I thought it was a great idea to allow both value semantics
and pointer semantics for the same types in C++ by the simple
addition of a * or &. What was wrong with that that needed
to be fixed in D? GC could have been done without changing
this. Now in D template code doesn't know which
semantics apply and structs can't inherit. If you write
something as a struct and then realise you need inheritance
you're stuck. D has so many good ideas it's a shame to see
it broken in this way...

BC wrote:
> I thought it was a great idea to allow both value semantics
> and pointer semantics for the same types in C++ by the simple
> addition of a * or &. What was wrong with that that needed
> to be fixed in D? GC could have been done without changing
> this. Now in D template code doesn't know which
> semantics apply and structs can't inherit. If you write
> something as a struct and then realise you need inheritance
> you're stuck. D has so many good ideas it's a shame to see
> it broken in this way...
I 99% agree with you, but I would like to debate just a smidgeon. I dislike the fact that in C++ (unless you're very careful) your "structs" are really heavyweight classes (vtbl, etc.) I like the fact that in D you can explicitly differentiate between heavyweight entities (classes) and lightweight ones (structs).
But I very much agree that for clarity, consistency, and template-ease, the syntax for "pointer/reference to a class" should be identical to the syntax for "pointer/reference to a struct".
So I would argue that there was something broken with C++ structs and classes. D fixed it, but then broke something else. :(

BC wrote:
> I thought it was a great idea to allow both value semantics
> and pointer semantics for the same types in C++ by the simple
> addition of a * or &. What was wrong with that that needed
> to be fixed in D? GC could have been done without changing
> this. Now in D template code doesn't know which
> semantics apply and structs can't inherit. If you write
> something as a struct and then realise you need inheritance
> you're stuck. D has so many good ideas it's a shame to see
> it broken in this way...
No. No no no no no. I hate seeing this argument.
structs are a shim. They are a way of getting lower-level access to the organization of memory.
In C++, this is ANYTHING but simple:
class A {
...
}
void someidiotfunction(A a);
void someidiotfunction2(A *a);
void someidiotfunction3(A &a);
You now have three ways of passing an "object", with different semantics and different possible results!
In proper object oriented design, objects are contexts. It makes no sense to duplicate contexts. Contexts are an abstraction of an environment in which to perform actions, and it makes no sense to duplicate that environment whenever you happen to pass it from one function to another (oh except when you don't).
D is not the problem. C++'s insistence on forcing details of implementation down the users' throat is the problem.
- Gregor Richards

Gregor Richards wrote:
> BC wrote:
>> I thought it was a great idea to allow both value semantics
>> and pointer semantics for the same types in C++ by the simple
>> addition of a * or &. What was wrong with that that needed
>> to be fixed in D? GC could have been done without changing
>> this. Now in D template code doesn't know which
>> semantics apply and structs can't inherit. If you write
>> something as a struct and then realise you need inheritance
>> you're stuck. D has so many good ideas it's a shame to see
>> it broken in this way...
> > > No. No no no no no. I hate seeing this argument.
> > structs are a shim. They are a way of getting lower-level access to the organization of memory.
In an abstract, academic sense, maybe you're right. As a practical matter, they are (in D, at least) a way to organize your data without the runtime overhead of classes. At least, that is one perfectly valid way to use them.
> In C++, this is ANYTHING but simple:
> > class A {
> ...
> }
> > void someidiotfunction(A a);
> void someidiotfunction2(A *a);
> void someidiotfunction3(A &a);
> > You now have three ways of passing an "object", with different semantics and different possible results!
> > In proper object oriented design, objects are contexts. It makes no sense to duplicate contexts. Contexts are an abstraction of an environment in which to perform actions, and it makes no sense to duplicate that environment whenever you happen to pass it from one function to another (oh except when you don't).
I proposed a simple solution to this a while ago: disallow copying of classes, including passing them by value. So, in your example above, I would propose that only the 2nd function should be valid, and the other 2 should be syntax errors. It's simple. It's consistent with structs.
It enforces the "don't copy a context" paradigm you are talking about.
And it trivially teaches a newbie how to do things in D:
Newbie: Write code that passes classes by value
Compiler: Syntax Error! You must pass classes by pointer
Newbie: Hmm. OK. Can do.
Ofc, we'll get newbies on the newsgroup flaming us, asking why pass-class-by-value is disallowed, and we'll have to teach them. But currently, what we have is a design that looks good at first (when writing trivial code) but which gets ugly when you write advanced code (like templates, or refactoring).

On Wed, 12 Dec 2007 12:24:44 -0800, Gregor Richards wrote:
> BC wrote:
>> I thought it was a great idea to allow both value semantics and pointer semantics for the same types in C++ by the simple addition of a * or &. What was wrong with that that needed to be fixed in D? GC could have been done without changing this. Now in D template code doesn't know which semantics apply and structs can't inherit. If you write something as a struct and then realise you need inheritance you're stuck. D has so many good ideas it's a shame to see it broken in this way...
> > > No. No no no no no. I hate seeing this argument.
> > structs are a shim. They are a way of getting lower-level access to the organization of memory.
> > In C++, this is ANYTHING but simple:
> > class A {
> ...
> }
> }
> void someidiotfunction(A a);
> void someidiotfunction2(A *a);
> void someidiotfunction3(A &a);
> > You now have three ways of passing an "object", with different semantics and different possible results!
> > In proper object oriented design, objects are contexts. It makes no sense to duplicate contexts. Contexts are an abstraction of an environment in which to perform actions, and it makes no sense to duplicate that environment whenever you happen to pass it from one function to another (oh except when you don't).
> > D is not the problem. C++'s insistence on forcing details of implementation down the users' throat is the problem.
> > - Gregor Richards
I don't mean to be offensive, but I totally don't see the point. Of course C++ structs (being inherited from C) are too low-level. Still, I would argue that this is a property of C++ not of value-semantics. And who decides a) what "proper object-oriented design" means, b) that it's inherently a great thing and c) that it is tied to reference semantics? IMO it makes perfect sense to treat objects as just a more complicated kind of value. Look at the following code:
int a=1;
a++;
int b = a + 10;
In this piece of code the variable a is used once as a reference (i.e.
modified in place) and once as a value (i.e. copied). In the same way it
can make sense for "real" objects to use them as values in some operations
and as references in others. You can easily make up a way to specify which
way to use a function arg (like, say, 'in' and 'inout') without having to
know anything about values or references.
To sum it up - I think although C++ structs + pointers + references is
messy, that doesn't mean that OOP and value vs. reference semantics aren't
completely orthogonal concepts.
And by the way this is the main point keeping me from using D (and the
fact that the gcc frontend is so slow in catching up). Since I started
to read the newsgroup I got the impression that the special syntactic
treatment of object references has been *the* major hurdle for many of the
more difficult/controversial language extensions (const comes to mind).
cheers
Martin
--
Martin Hinsch
m.hinsch@rug.nl
+31 50 363 8097
CEES Centre for Ecological and Evolutionary Studies
Biologisch Centrum
Kerklaan 30
Postbus 14
9750 AA Haren

Martin Hinsch wrote:
> On Wed, 12 Dec 2007 12:24:44 -0800, Gregor Richards wrote:
> >> BC wrote:
>>> I thought it was a great idea to allow both value semantics and pointer
>>> semantics for the same types in C++ by the simple addition of a * or &.
>>> What was wrong with that that needed to be fixed in D? GC could have
>>> been done without changing this. Now in D template code doesn't know
>>> which semantics apply and structs can't inherit. If you write something
>>> as a struct and then realise you need inheritance you're stuck. D has so
>>> many good ideas it's a shame to see it broken in this way...
>>>> No. No no no no no. I hate seeing this argument.
>>>> structs are a shim. They are a way of getting lower-level access to the
>> organization of memory.
>>>> In C++, this is ANYTHING but simple:
>>>> class A {
>> ...
>> }
>> }
>> void someidiotfunction(A a);
>> void someidiotfunction2(A *a);
>> void someidiotfunction3(A &a);
>>>> You now have three ways of passing an "object", with different semantics
>> and different possible results!
>>>> In proper object oriented design, objects are contexts. It makes no sense
>> to duplicate contexts. Contexts are an abstraction of an environment in
>> which to perform actions, and it makes no sense to duplicate that
>> environment whenever you happen to pass it from one function to another
>> (oh except when you don't).
>>>> D is not the problem. C++'s insistence on forcing details of
>> implementation down the users' throat is the problem.
>>>> - Gregor Richards
> > I don't mean to be offensive, but I totally don't see the point. Of course
> C++ structs (being inherited from C) are too low-level. Still, I would
> argue that this is a property of C++ not of value-semantics. And who
> decides a) what "proper object-oriented design" means,
Consensus and history.
> b) that it's
> inherently a great thing
This is irrelevant. Whether OO is good or not, D aims to be OO.
> and c) that it is tied to reference semantics?
Consensus. C++ is popular, but it is the exception to the rule in this regard. Virtually no other language has this bizarre property.
> IMO it makes perfect sense to treat objects as just a more complicated
> kind of value. Look at the following code:
> > int a=1;
> a++;
> int b = a + 10;
This code has no function calls. And, if it was all implemented with operator overloading, it would be the same whether it had value or reference semantics:
Integer a = new Integer(/*magic internal data representing the value 1*/);
a.opIncrement(); /* no imperative language would implement this as a
* copy, as then all objects would be immutable */
Integer b = a.opAdd(new Integer(10)); /* whether the integer is copied
* or not, a returns a new one, it
* has no reason to modify its
* argument */
In other words, this code is irrelevant.
> > In this piece of code the variable a is used once as a reference (i.e.
> modified in place) and once as a value (i.e. copied).
No it isn't.
> In the same way it
> can make sense for "real" objects to use them as values in some operations
> and as references in others.
Intrinsic values do not mutate in the same way that objects do. In an object oriented sense, they're immutable. When you say a = a + 5, it's rebinding the variable a to a new value, computed as a + 5. The actual data representing its original value is not modified, a is simply rebound. This has the same result whether by-value or by-reference. Because they're immutable, there's no distinction between by-value and by-reference passing. If all the intrinsic types were actually by-ref objects, there would be no difference.
(Note: a++ and ++a are sort of exceptions to this rule)
> You can easily make up a way to specify which
> way to use a function arg (like, say, 'in' and 'inout') without having to
> know anything about values or references.
Yes - D already has one.
> To sum it up - I think although C++ structs + pointers + references is
> messy, that doesn't mean that OOP and value vs. reference semantics aren't
> completely orthogonal concepts.
> And by the way this is the main point keeping me from using D
Seriously? You are /way/ too much of a C++'er. Go use any other OO language, and you will find your opinion very quickly in the minority. "I don't mean to be offensive," but that's just silly.
> (and the
> fact that the gcc frontend is so slow in catching up). Since I started
> to read the newsgroup I got the impression that the special syntactic
> treatment of object references has been *the* major hurdle for many of the
> more difficult/controversial language extensions (const comes to mind).
This is a purely syntactic hurdle, and the giant ugly mess that is by-value objects is not worth the slightly simpler syntax. Which, incidentally, would be more complicated syntax in basically every other scenario.
> > cheers
> Martin
>
- Gregor Richards

Gregor Richards wrote:
> Martin Hinsch wrote:
>> IMO it makes perfect sense to treat objects as just a more complicated
>> kind of value. Look at the following code:
>>>> int a=1;
>> a++;
>> int b = a + 10;
> > > This code has no function calls. And, if it was all implemented with operator overloading, it would be the same whether it had value or reference semantics:
> > Integer a = new Integer(/*magic internal data representing the value 1*/);
> a.opIncrement(); /* no imperative language would implement this as a
> * copy, as then all objects would be immutable */
> Integer b = a.opAdd(new Integer(10)); /* whether the integer is copied
> * or not, a returns a new one, it
> * has no reason to modify its
> * argument */
> > In other words, this code is irrelevant.
>
I feel strangely compelled to describe Python's behavior in this case, although I admit I'm not entirely clear what the point is. In Python, integers are immutable objects.
>>> a = 1 # (1)
>>> a += 1 # (2) Python has no increment/decrement operators
>>> b = a + 10 # (3)
(1) Binds an int object with the value 1 to the name 'a'.
(2) In-place addition is strange in Python. Numbers, being immutable, cannot actually be modified. Instead, 'a += 1' actually creates a new int object [see note 1] with the value 2, and binds that object to the name 'a'. (Thus removing the old reference to the object with the value 1.)
(3) Does exactly what you'd expect: Creates a new int object [see note 1] with the value 12, and binds it to the name 'b'.
Notes:
[1] In fact, it doesn't create a new object: Integer objects below 100 are cached and reused for performance reasons. So here it's /really/ grabbing an object from the cache. This is considered an implementation detail, however, and is usually best ignored.
--
Kirk McDonald
http://kirkmcdonald.blogspot.com
Pyd: Connecting D and Python
http://pyd.dsource.org

On Wed, 12 Dec 2007 14:59:16 -0800, Gregor Richards wrote:
> Martin Hinsch wrote:
>> On Wed, 12 Dec 2007 12:24:44 -0800, Gregor Richards wrote:
>>
[snip]
>>>>>> In C++, this is ANYTHING but simple:
>>>>>> class A {
>>> ...
>>> }
>>> }
>>> void someidiotfunction(A a);
>>> void someidiotfunction2(A *a);
>>> void someidiotfunction3(A &a);
>>>>>> You now have three ways of passing an "object", with different semantics and different possible results!
>>>>>> In proper object oriented design, objects are contexts. It makes no sense to duplicate contexts. Contexts are an abstraction of an environment in which to perform actions, and it makes no sense to duplicate that environment whenever you happen to pass it from one function to another (oh except when you don't).
>>>>>> D is not the problem. C++'s insistence on forcing details of implementation down the users' throat is the problem.
>>>>>> - Gregor Richards
>> >> I don't mean to be offensive, but I totally don't see the point. Of course C++ structs (being inherited from C) are too low-level. Still, I would argue that this is a property of C++ not of value-semantics. And who decides a) what "proper object-oriented design" means,
> > Consensus and history.
So, you're basically saying follow the crowd since everybody does...
> >> b) that it's
>> inherently a great thing
> > This is irrelevant. Whether OO is good or not, D aims to be OO.
I thought D had the much more modest goal to be the best language ever ;-).
> >> and c) that it is tied to reference semantics?
> > Consensus. C++ is popular, but it is the exception to the rule in this regard. Virtually no other language has this bizarre property.
>
see above. I don't think that consensus is a good argument (except maybe
in politics).
>> IMO it makes perfect sense to treat objects as just a more complicated kind of value. Look at the following code:
>> >> int a=1;
>> a++;
>> int b = a + 10;
> > This code has no function calls. And, if it was all implemented with
I see no reasons to treat operators anything different than as sugarified function calls.
[snip]
> > Intrinsic values do not mutate in the same way that objects do. In an object oriented sense, they're immutable. When you say a = a + 5, it's rebinding the variable a to a new value, computed as a + 5. The actual data representing its original value is not modified, a is simply rebound. This has the same result whether by-value or by-reference. Because they're immutable, there's no distinction between by-value and by-reference passing. If all the intrinsic types were actually by-ref objects, there would be no difference.
> > (Note: a++ and ++a are sort of exceptions to this rule)
Ok, you have sort of a point. I think what I was talking about was mutable vs. immutable objects which is a kind of related (and interesting as well) but still different topic.
> >> You can easily make up a way to specify which way to use a function arg (like, say, 'in' and 'inout') without having to know anything about values or references.
> > Yes - D already has one.
I know, I was trying (and obviously failing ;-) to be sarcastic.
Anyways, the point I was trying to make is that your example of all the
different possibilities to pass objects as function arguments in C++ has
nothing to do with values vs. references but rather with the fact that C++
(as you said) doesn't properly abstract from implementation details.
Therefore you have to "construct" the different ways to pass arguments
(modifiable/non-modifiable) from the low-level machinery (i.e. pointers)
or the slightly more high-level half-hearted add-on (i.e. references (&)).
If the language offers you a way to properly describe the semantics of
argument passing this becomes a non-issue.
> >> To sum it up - I think although C++ structs + pointers + references is messy, that doesn't mean that OOP and value vs. reference semantics aren't completely orthogonal concepts. And by the way this is the main point keeping me from using D
> > Seriously? You are /way/ too much of a C++'er. Go use any other OO language, and you will find your opinion very quickly in the minority.
so, minority == wrong?
Actually my first OO language was Objective C which is as referency as you
can get without going directly to SmallTalk. I've also done quite some
programming in Java and Ruby both of which also belong to this
category (albeit one with static and the other one with dynamic typing).
I really liked both, Ruby and Objective C (I strongly dislike Java but for
entirely different reasons). Still, the distinction between object
references on one hand and plain type values on the other hand always
seemed quite artificial to me.
I think it makes kind of sense in a dynamic, "scripty" language where you would like to ignore types most of the time. As soon as you enter the statically typed world there is in my opinion not really a good reason anymore to make objects references per default.
You can get everything you want from OOP (data hiding, inheritance, polymorphism) with value types as default.
[snip]
> This is a purely syntactic hurdle, and the giant ugly mess that is by-value objects is not worth the slightly simpler syntax. Which, incidentally, would be more complicated syntax in basically every other scenario.
>
Please explain (seriously).
Martin Hinsch

On Wed, 12 Dec 2007 22:59:16 -0000, Gregor Richards <Richards@codu.org> wrote:
> Martin Hinsch wrote:
>> On Wed, 12 Dec 2007 12:24:44 -0800, Gregor Richards wrote:
>>>>> BC wrote:
>>>> I thought it was a great idea to allow both value semantics and pointer
>>>> semantics for the same types in C++ by the simple addition of a * or &.
>>>> What was wrong with that that needed to be fixed in D? GC could have
>>>> been done without changing this. Now in D template code doesn't know
>>>> which semantics apply and structs can't inherit. If you write something
>>>> as a struct and then realise you need inheritance you're stuck. D has so
>>>> many good ideas it's a shame to see it broken in this way...
>>>>>> No. No no no no no. I hate seeing this argument.
>>>>>> structs are a shim. They are a way of getting lower-level access to the
>>> organization of memory.
>>>>>> In C++, this is ANYTHING but simple:
>>>>>> class A {
>>> ...
>>> }
>>> }
>>> void someidiotfunction(A a);
>>> void someidiotfunction2(A *a);
>>> void someidiotfunction3(A &a);
>>>>>> You now have three ways of passing an "object", with different semantics
>>> and different possible results!
>>>>>> In proper object oriented design, objects are contexts. It makes no sense
>>> to duplicate contexts. Contexts are an abstraction of an environment in
>>> which to perform actions, and it makes no sense to duplicate that
>>> environment whenever you happen to pass it from one function to another
>>> (oh except when you don't).
>>>>>> D is not the problem. C++'s insistence on forcing details of
>>> implementation down the users' throat is the problem.
>>>
I don't see how C++ is forcing anything. C++ is the one that gives you
the choice. If I want two closely related types to be viewed through a
common interface or to share implementation in D, I have to accept
reference semantics as well, everywhere. If you have an aversion to
by-value objects you can always stick to pointers in C++. Use an alias.
We're not trying to take anything away, it's an addition.
a question: should matrices be structs or classes?
>>> - Gregor Richards
>> I don't mean to be offensive, but I totally don't see the point. Of course
>> C++ structs (being inherited from C) are too low-level. Still, I would
>> argue that this is a property of C++ not of value-semantics. And who
>> decides a) what "proper object-oriented design" means,
>> Consensus and history.
>>> b) that it's
>> inherently a great thing
>> This is irrelevant. Whether OO is good or not, D aims to be OO.
>>> and c) that it is tied to reference semantics?
>> Consensus. C++ is popular, but it is the exception to the rule in this regard. Virtually no other language has this bizarre property.
>>> IMO it makes perfect sense to treat objects as just a more complicated
>> kind of value. Look at the following code:
>> int a=1;
>> a++;
>> int b = a + 10;
>> This code has no function calls. And, if it was all implemented with operator overloading, it would be the same whether it had value or reference semantics:
>> Integer a = new Integer(/*magic internal data representing the value 1*/);
> a.opIncrement(); /* no imperative language would implement this as a
> * copy, as then all objects would be immutable */
> Integer b = a.opAdd(new Integer(10)); /* whether the integer is copied
> * or not, a returns a new one, it
> * has no reason to modify its
> * argument */
>> In other words, this code is irrelevant.
>>> In this piece of code the variable a is used once as a reference (i.e.
>> modified in place) and once as a value (i.e. copied).
>> No it isn't.
>>> In the same way it
>> can make sense for "real" objects to use them as values in some operations
>> and as references in others.
>> Intrinsic values do not mutate in the same way that objects do. In an object oriented sense, they're immutable. When you say a = a + 5, it's rebinding the variable a to a new value, computed as a + 5. The actual data representing its original value is not modified, a is simply rebound. This has the same result whether by-value or by-reference. Because they're immutable, there's no distinction between by-value and by-reference passing. If all the intrinsic types were actually by-ref objects, there would be no difference.
>> (Note: a++ and ++a are sort of exceptions to this rule)
>
along with a-- --a += -= *= /= %= &= |= ~= ^= <<= >>= >>>=
>> You can easily make up a way to specify which
>> way to use a function arg (like, say, 'in' and 'inout') without having to
>> know anything about values or references.
>> Yes - D already has one.
>>> To sum it up - I think although C++ structs + pointers + references is
>> messy, that doesn't mean that OOP and value vs. reference semantics aren't
>> completely orthogonal concepts.
>> And by the way this is the main point keeping me from using D
>> Seriously? You are /way/ too much of a C++'er. Go use any other OO language, and you will find your opinion very quickly in the minority. "I don't mean to be offensive," but that's just silly.
>>> (and the
>> fact that the gcc frontend is so slow in catching up). Since I started
>> to read the newsgroup I got the impression that the special syntactic
>> treatment of object references has been *the* major hurdle for many of the
>> more difficult/controversial language extensions (const comes to mind).
>> This is a purely syntactic hurdle, and the giant ugly mess that is by-value objects is not worth the slightly simpler syntax. Which, incidentally, would be more complicated syntax in basically every other scenario.
>>> cheers
>> Martin
>>>> - Gregor Richards

> a question: should matrices be structs or classes?
I'd like to clarify your question:
do you want to ask -
a) whether they should be value types or reference types?
or
b) whether they should be implemented with D structs or D classes?
if you mean a than it really doesn't matter.
you are quite right that you can implement OOP features with both reference and value semantics. doing both is redundant because they achieve the same goal.
i.e. passing by value achieves the same as const reference and passing the address of the value achieves the same as passing by mutable reference.
so it's just a question of implementation and most languages choose reference semantics due to the more efficient memory use.
so in this case the consensus is the better option.
also note that you can mix-n-match: you can implement one semantic with the other:
ref to value: you can have a dup method (clone in java, but you knew that already) although it should be avoided and probably isn't needed in the general case.
value to ref: you can pass addresses of values to simulate references.
if you meant b than i think that classes should be used.
I'm new to D, but from what little i know, if you want OOP behavior (and matrices would benefit from polymorphism) than you need to use a class and not a struct.
the semantics shouldn't matter as it's a matter of implementation and not interface. (ideally you'd just use "in" and "inout" and let the compiler optimize when you pass around parameters).
if you want a matrix to be a value type you can simulate that with a dup method, i think.
D structs should only be used for PODs. a good example would be a struct containing an internet address where you need it to be in a specific memory layout (endian-ness).
also, if you care about heap allocation vs. stack, than you could always use scope classes which would be stack based.
that's all from a theoretical POV of course, practically, there maybe other issues that influence that decision. also const still has a few kinks that need to be sorted out in D.
Just my 2 cents..