POV-Ray : Newsgroups : povray.off-topic : Another "This is why I..." : Re: Another "This is why I..." Server Time
5 Sep 2024 19:24:02 EDT (-0400)
  Re: Another "This is why I..."  
From: Darren New
Date: 27 May 2009 12:14:35
Message: <4a1d66eb@news.povray.org>
Warp wrote:
> Darren New <dne### [at] sanrrcom> wrote:
>>>   The class which represents a numerical value is a good example of a
>>> value-based object for which reference semantics make little sense 
> 
>> Right. But it also makes no sense for it to be read/write.
> 
>   It doesn't make sense for a numerical variable to be read/write? There's
> definitely something I'm not understanding here.

It doesn't make sense for a numerical *instance* to be read-write. When you 
say a = b + c, you're not modifying b or c or the old value of a. You're 
replacing what's in 'a' with a new value.

You say "x = sin(x)", not "x.sin()"

>   How do you use, let's say for example, a value-based loop counter variable
> if it's not read/write? I can't even bend my mind to figure out how you could
> construct a loop with a read-only variable.

Not variable. Value. Same variable, different values.

Look at something that makes sense to maybe be read/write, like strings. 
Contrast "name = trim(name)" with "name.trim()".

>> I can't think of examples that should be modifiable *and* copyable. If it's 
>> modifiable, you don't want multiple copies floating about.
> 
>   Maybe we are having a different notion of what "copyable" means, because
> I'm not really understanding.

By "read/write", I mean a value where you can invoke a method that changes 
the actual value of the instance. Same instance, new value. A class in C++ 
that has methods that aren't marked "const" would be an example.

By "copyable", I mean a instance where assigning the value that's now in one 
variable to a second variable gives you a new instance in the second 
variable that can be modified independently of the value in the first 
variable. Something in C++ with the default copy constructor being public 
would be an example.

In other words, I find it hard to come up with good examples where you can 
do both of these:

a) modify the values inside the class, such that if you have multiple 
pointers/references/etc to the instance, all holders of that pointer will 
see the changes, and

b) have the ability to create a new instance with all the same values.

The reason being that if you can modify a shared instance, and also *copy* 
the shared instance, then you can wind up with the copies being out of sync 
with each other. And if you can modify values in place, then conceptually 
the object actually represents something independent of where it is stored, 
so making multiple copies implies duplicating whatever that instance represents.

>   I'm not understanding what you are saying.
> 
>   It sounds to me like splitting hairs with semantics. Is "a = 5" modifying
> the value of 'a', or is it creating a "new integral value, 5, and storing
> it over the old value of 'a'"?

The latter.

My point is that if you do
a = 5; b = a; a = 7;
you're not changing the value in b.

If you do
a = "  hello   ";  b = a;  a.trim();
are you changing the value in b?

>   Internally it's modifying the variable 'a' (the memory location
> represented by that variable name is modified to have a new value).
> On the language level it's modifying the value of the variable 'a'.
> I'm really not seeing how it's not really modifying 'a', but somehow
> "creating a new integral value".

It's modifying 'a'. It's not modifying '5'.  So in this case, you have an 
instance that's not modifiable. If you say "a = 5;" there's then nothing you 
can do to '5' to change 'a'.

>   The same with a pixel object. I could say, for example, something like
> "image[x][y].setRed(123);" and by doing that I'm *modifying* the value of
> the pixel in question. Nothing new is created and nothing is being copied
> around. Instead, the pixel object is being modified in-place.

Right. Now, why would you want multiple classes holding pointers to the same 
pixel?  I'm not talking "use a pointer so you can change the value inside a 
function because we don't really have pass by reference" pointers (a la C). 
I'm talking about long-term use of multiple instances of some class with 
pointers to the same pixel. What other classes would declare a member 
variable holding "pointer to pixel"?

>> I also don't see any good point for making pixels or integers into objects 
>> if you have the choice not to.
> 
>   Then you have a rather odd concept of how useful encapsulation is.

There are lots of ways to encapsulate stuff that doesn't involve making the 
pixel an object. To me, OO is a lot more than just a namespace holding a 
bunch of functions. I wouldn't use OO for encapsulation. I'd use encapsulation.

If your only encapsulation mechanism is OO, then sure, you're kind of stuck 
with that.

>> But I don't see any compelling reason to code like pixels have 
>> "behavior" and "state" as such.
> 
>   Need for "behavior" could be a question of opinion, but pixels not
> having state? Exactly how do you expect to store pixel data anywhere if
> that somewhere has no state? How do you expect something with no state
> to remember the value of the pixel? That seems completely incoherent to me.

Well, generally "state" implies "behavior". Otherwise it's just a value. 
There's no "state" in a pixel because there's no "state transitions" that 
make sense or don't make sense. I.e., there's no state such that you could 
reasonable put invariants on the instances or preconditions on the methods 
that you could enforce.

It's kind of a conceptual thing, really. Obviously it's all *implemented* as 
fields in the structure holding the data.

>>  Images don't saturate themselves, nor do 
>> pixels, for example.
> 
>   I'm not exactly sure if by "saturate" you are talking about modifying
> an image, or something completely different I'm not familiar with. If you
> are talking about modifying the image, then why not? Why couldn't you be
> able to tell an image "saturate by this amount" and then it does that?

(By "saturate" I meant turning up the intensity of the hue.)

OK. Perhaps a bad example, there. Images saturate themselves. I suppose if 
you wanted to push it, you could have images having a saturate() member that 
  iterates over each pixel, calling saturate() for the pixel. You couldn't 
do that with something like "blur", tho, since that involves multiple 
pixels. So you're likely to have some sort of class that represents a 
collection of pixels anyway.

>> IIRC, in Smalltalk, pixels weren't objects. You had 
>> bitmaps as the objects, and if you needed you could make a one-pixel bitmap, 
>> but all of the methods were designed for big bitmaps.
> 
>   What does it matter what kind of libraries some programming language
> offers? The creators of those libraries made their own design decisions,
> but why should that matter? I'm talking about your own code.

I was giving an example, is all.

>   Don't tell you you *can't* create a pixel class in Smalltalk.

Of course you can. It's just going to be fiendishly inefficient, just like 
it would be in Java. I was explaining how, in a language where an individual 
pixel is inefficient, the designers of the class library used a container as 
the lowest-level element in the graphics library.

>> Unless your compiler is smart enough to ditch the vptr (or its equivalent) 
>> when you put the pixel into an array-of-pixels
> 
>   Why do you think I like C++?

Really?  You can have a pixel with virtual functions, and then the vptr goes 
away when you assign it into an array? So a pixel with virtual functions 
takes at least two words of memory, but an array of 100 pixels only takes 
100 words of memory?

Hmmm. Yes, actually, now I think I understand that. You wind up "slicing" 
off the subclass, right? So you actually copy the subclass of the pixel into 
the array by copying it into an instance of the superclass?

Yeah, OK. Now I see why you might *ever* want to do that. It seemed like 
just brokenness to me before. :-)

Let me see if I have this straight:

class alpha {
   public:
     virtual void xyz() { ... };
     alpha(long x) { pdq = x; }
     long pdq;
   }
class beta : alpha {
   public: virtual void xyz() { ... };
   beta(long x) { pdq = x; }
   }

alpha * b = new beta(123);
alpha a = b;
alpha c[100];

Now, at this point, what is the sizeof(a) and the sizeof(c)?
Is c 100 longs, or is it 100 longs plus 100 vptrs?
If the former, then I understand what you're saying and
now understand why C++ does slicing that way.


>   Sure, I can leak and trash memory and crash the program with C++, but
> when I know what I'm doing (and I pretty much do), it allows me to do
> things efficiently while still maintaining a relly high level of
> encapsulation and abstraction.

Sure. Once you're good at it and you can find the libraries you need and 
know where the non-portable bits are, I can see where it's useful. Obviously 
there's a reason lots of people like it.

>   Classes with no virtual functions have no vptr. Is this sometimes a
> pain in the neck? Maybe. However, when you know what you are doing, it
> allows you to write really efficient code.

Sure.

-- 
   Darren New, San Diego CA, USA (PST)
   There's no CD like OCD, there's no CD I knoooow!


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.