![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> 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.
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.
> 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.
> > A pixel class is another good example. Maybe even a better example.
> > A pixel is often an object which has the same size as the natural word
> > size of the architecture (eg. 32 bits), or at most double that (at least
> > if you are using integral color components). A pixel class is also something
> > which is usually instantiated *a lot*, as well as copied and modified
> > extensively.
> I don't think you really modify pixels, do you? You create a new pixel and
> store it over top of the previous pixel. You wouldn't want to modify a pixel
> and have all the red pixels in your image turn blue or something, no?
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'"?
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".
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.
> 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.
What would, in your opinion, be the best way of abstracting away the
internal structure of a pixel so that the code used to handle pixels can
be reused for different purposes? If you want to be able to later modify
the internal structure and/or functionality of a pixel in a centralized
place and in such way that it doesn't break existing code, I don't see
any better alternative than encapsulation, and an object-oriented class
is just perfect for this purpose.
> 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.
> 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?
> 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.
Don't tell you you *can't* create a pixel class in Smalltalk.
> 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++?
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.
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.
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> 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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> 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.
By that definition no language ever modifies any variable.
> > 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.
Of course you are. You are changing it to 5.
> If you do
> a = " hello "; b = a; a.trim();
> are you changing the value in b?
Depends on the semantics of the type.
> >> 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?
No. I can have a pixel with no vptr, and I can store such pixels in an
array. Unlike in many other languages.
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> wrote:
>> 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.
>
> By that definition no language ever modifies any variable.
Not true.
class customer {
public: int age; string name;
void setage(int newage) { this.age = newage; }
}
customer fred;
fred.setage(23);
fred.setage(17);
You definitely change fred twice there. You replaced the value of fred.age,
but in so doing changed the value of fred.
If you're using java and you say
customer fred = new customer();
fred.setage(23);
customer barney = fred;
writeln(barney.age);
fred.setage(17);
writeln(barney.age);
you're going to get two different outputs for barney's age. In C++ (as
written) you won't, because the assignment to barney isn't an assignment of
identity but an assignment of value.
>> My point is that if you do
>> a = 5; b = a; a = 7;
>> you're not changing the value in b.
>
> Of course you are. You are changing it to 5.
Right. You're not changing the value in b when you assign 7 to a.
>> If you do
>> a = " hello "; b = a; a.trim();
>> are you changing the value in b?
>
> Depends on the semantics of the type.
That's my point. I can't think of any class where you'd realistically want
to choose on a variable-by-variable basis or a value-by-value basis.
Certainly not when doing DDD. Maybe when doing scientific stuff it's more
common?
It just doesn't seem like the right way to do OOD, because to me you either
have a class that represents an entity (and thus has an identity and thus
makes no sense to copy and thus must be shared via references) or you have a
class that represents a value (and thus must be read-only if shared, and
hence if the object is much bigger than a pointer it might reasonably save
space to represent it that way, a la "flyweight" pattern).
In this case, a raw string obviously doesn't represent an entity in the real
world, so the answer *should* be "you don't change b".
>>>> 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?
>
> No. I can have a pixel with no vptr, and I can store such pixels in an
> array. Unlike in many other languages.
Oh, OK. To me, conflating encapsulation with class with inheritance is a
"bad" thing to do in OOD. It leads to having things like classes *and*
namespaces, or to "friend" functions and "friend" classes, etc.
Actually, it seems to me that in C++ if you're going to allow "stripping" an
instance to its superclass, you should be able to get rid of the vptr in the
case that you're not operating thru a pointer or reference. I didn't think
the language currently works that way and you confirmed that, but it seems
like it might be a space savings, as you say.
But, as I tried to say, if you're modeling the real world via OO, having
nothing but references isn't much of a problem. It's certainly not a problem
if you have classes that are either value classes or reference classes, and
you can't pick on a variable-by-variable basis which it is. (I.e., it
shouldn't be a problem to have value classes to which you can't take an
explicit pointer. C++-style references are of course still useful for
pass-by-reference type stuff if the language doesn't otherwise support
pass-by-reference.)
--
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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> >> My point is that if you do
> >> a = 5; b = a; a = 7;
> >> you're not changing the value in b.
> >
> > Of course you are. You are changing it to 5.
> Right. You're not changing the value in b when you assign 7 to a.
Uh? That's because you are changing the value of a, not the value of b.
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Darren New <dne### [at] san rr com> wrote:
>>>> My point is that if you do
>>>> a = 5; b = a; a = 7;
>>>> you're not changing the value in b.
>>> Of course you are. You are changing it to 5.
>
>> Right. You're not changing the value in b when you assign 7 to a.
>
> Uh? That's because you are changing the value of a, not the value of b.
Yes! Precisely. You're not changing the value of 5. You're changing the
value of 'a'.
Contrast with
a = " hello "; b = a; a.trim();
Whether you changed 'b' depends on whether string literals have value or
reference semantics. *Unless* strings are read-only, in which case a.trim()
returns a new string which gets discarded.
--
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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New wrote:
> Warp wrote:
>> Darren New <dne### [at] san rr com> wrote:
>>>>> My point is that if you do
>>>>> a = 5; b = a; a = 7;
>>>>> you're not changing the value in b.
>>>> Of course you are. You are changing it to 5.
>>
>>> Right. You're not changing the value in b when you assign 7 to a.
>>
>> Uh? That's because you are changing the value of a, not the value of b.
>
> Yes! Precisely. You're not changing the value of 5. You're changing the
> value of 'a'.
Or, maybe more clearly....
a = 5; b = a; a++;
This doesn't change the value in 'b'. You're not incrementing the value in
'a'. You're replacing the value in 'a' with a new value. Numbers are so
familiar that you don't normally think of '5' as being an instance of an
object, so it's hard to separate object from variable in ones mind with
integers. That's why I gave the string example.
Note that in FORTRAN, the equivalent code would actually change the value in
'b' as well. (As in, all arguments get passed by reference, and you can
actually change the storage location where the literal '5' is held, and you
get screwed. Obviously not in all FORTRAN implementations, but...)
--
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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> Yes! Precisely. You're not changing the value of 5. You're changing the
> value of 'a'.
I'm sorry, but I'm having difficult time understanding what you are
talking about. It just seems inconsistent and incoherent.
In a previous post you argued how you are not changing the value of 'a'
and now you are saying that you are.
> Contrast with
> a = " hello "; b = a; a.trim();
> Whether you changed 'b' depends on whether string literals have value or
> reference semantics. *Unless* strings are read-only, in which case a.trim()
> returns a new string which gets discarded.
I don't really understand what's your point.
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Darren New <dne### [at] san rr com> wrote:
> Or, maybe more clearly....
> a = 5; b = a; a++;
> This doesn't change the value in 'b'.
I don't even understand why it should, if you are handling value-based
variables.
> You're not incrementing the value in
> 'a'. You're replacing the value in 'a' with a new value.
"a++" probably results in an assembler machine code which makes the CPU
increment the value of a memory location by one. Exactly how the bits go
through the transistors in order to achieve this feels irrelevant. It's
the end result that matters: You modified the value of the variable.
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> I don't really understand what's your point.
Did you read the link about DDD?
If you design software that way, one of the rules can be summarized as
"objects which you can copy must have value semantics" by which it is meant
that they must be immutable once created, like integers or Java strings.
On the other hand, objects which have an identity (i.e., which correlate to
real world entities or get stored persistently) cannot be duplicated.
In other words (and over-simplifying), your objects either represent things
related to the domain (and thus have an identity and thus make no sense to
duplicate in memory) or they represent attributes of those things (and thus
have no identity but also don't make sense to modify, being the values an
attribute in the modifiable entity takes on).
Given that, a language where anything big enough to hold a pointer needs to
be treated as a reference doesn't seem like a burden. That a pixel may need
to get accessed with a syntax like a "friend function" provides instead of
distinguished-caller doesn't seem problematic to me in the big picture, if
indeed your language requires such a change.
--
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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |