December 13, 2007
Martin Hinsch, el 12 de diciembre a las 22:02 me escribiste:
> 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.

Value-semantics has the "slicing problem" and works very poorly with virtual methods. It adds a lot of complexity.

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
De las generaciones venideras espero, nada más, que vengan.
	-- Ricardo Vaporeso
December 13, 2007
On Thu, 13 Dec 2007 01:51:13 -0000, Yigal Chripun <yigal100@gmail.com> wrote:

>  > 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?
>

i should have been clearer, i meant a. although i'd argue it's the same
question.

> 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.

in template code, you have to dup everything, just in case. and then it
may not have a dup method, or a copy constructor (which aren't generated
automatically, and if it has both which do you use?)

> value to ref: you can pass addresses of values to simulate references.

but then you need to change everything to pointer syntax. it would be
nice to sneak in references as opposed to pointers. i suppose this
comes under the header of 'c++ dirty tricks'

> 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.

it's so easy to miss one dup out and get very weird behaviour. code working
on matrices with dups all over the place is not something i relish.
i don't know, i'm not entirely convinced of my own argument. i just think
things could be 'excellent' or envelope-pushing rather than just 'ok'.

> 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).

i think there's a distinction between something that's a value type and
something that's POD. matrices, by their nature, are value types - their
identity is irrelevant. but they could do with inheritance, or at least
interfaces.

> 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..



December 13, 2007
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...

It's a good question. D structs are designed to represent value types, and classes as reference types. The two have very different uses and characteristics. C++ allows them to be mixed up together, with program bugs as the usual result.

For example, the slicing problem. If you inherit from a value type, and then add members, then everyone who uses the value type by value "slices" off the additional members.

Virtual functions make no sense for value types, and non-virtual functions are a recipe for disaster in reference types (hence the exhortation to not forget to make your destructors virtual if deriving from them, a lame bit of advice because base classes cannot control how they are used).

In C++, one designs a class to be a reference type or a value type. Interestingly, I've never once seen in documentation for a C++ class whether it is supposed to be used by reference or by value.

Clearly distinguishing value types from reference types:

1) Indicates to the user how a type is to be used
2) Allows for the correct semantic defaults
3) Eliminates whole categories of bugs that are impractical to detect in C++
December 13, 2007
On Thu, 13 Dec 2007 05:10:04 -0000, Walter Bright <newshound1@digitalmars.com> 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...
>
> It's a good question. D structs are designed to represent value types, and classes as reference types. The two have very different uses and characteristics. C++ allows them to be mixed up together, with program bugs as the usual result.
>
> For example, the slicing problem. If you inherit from a value type, and then add members, then everyone who uses the value type by value "slices" off the additional members.
>
> Virtual functions make no sense for value types, and non-virtual functions are a recipe for disaster in reference types (hence the exhortation to not forget to make your destructors virtual if deriving from them, a lame bit of advice because base classes cannot control how they are used).
>
> In C++, one designs a class to be a reference type or a value type. Interestingly, I've never once seen in documentation for a C++ class whether it is supposed to be used by reference or by value.
>
> Clearly distinguishing value types from reference types:
>
> 1) Indicates to the user how a type is to be used
> 2) Allows for the correct semantic defaults
> 3) Eliminates whole categories of bugs that are impractical to detect in C++

I admit I exaggerated in the original post (or was completely wrong. D isn't
broken) Perhaps we could consider all this as just thinking out loud.
I have to say I've never really had a problem with slicing (well, maybe
when I was first learning.) Assigning related value types to each other is
conversion, not polymorphism, if you accept that you're ok. You could
make things more interesting though (or a complete hack). You could make
all your container types descend from one,
with all virtual functions. In C++ you could then use them as value types,
and all the functions get called non-virtually or as a reference and
they're all virtual. Admittedly this rules out the non-virtual case if
using null pointers to save memory for empty containers. You could
possibly imagine a third way where a reference (giving you polymorphism)
simulates value semantics by dupping on every assignment (so you don't
have to worry if two share data). I can almost
hear you cringing as I type this. So many dirty tricks you can do in C++!
I have a question: aren't reference types mostly an implementation detail,
for speed/memory reasons? Anyway perhaps I should leave you all alone and
go learn brainfuck.
December 13, 2007
Yigal Chripun wrote:
>  > 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?
[snip]
> I'm new to D, but from what little i know, if you want OOP behavior (and matrices would benefit from polymorphism) 

How? What matrix operations are polymorphic?
December 13, 2007
On Thu, 13 Dec 2007 08:02:13 -0000, BC <NOTmi_emayl_adrez@hotmail.com.remove.not> wrote:

> On Thu, 13 Dec 2007 05:10:04 -0000, Walter Bright <newshound1@digitalmars.com> 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...
>>
>> It's a good question. D structs are designed to represent value types, and classes as reference types. The two have very different uses and characteristics. C++ allows them to be mixed up together, with program bugs as the usual result.
>>
>> For example, the slicing problem. If you inherit from a value type, and then add members, then everyone who uses the value type by value "slices" off the additional members.
>>
>> Virtual functions make no sense for value types, and non-virtual functions are a recipe for disaster in reference types (hence the exhortation to not forget to make your destructors virtual if deriving from them, a lame bit of advice because base classes cannot control how they are used).
>>
>> In C++, one designs a class to be a reference type or a value type. Interestingly, I've never once seen in documentation for a C++ class whether it is supposed to be used by reference or by value.
>>
>> Clearly distinguishing value types from reference types:
>>
>> 1) Indicates to the user how a type is to be used
>> 2) Allows for the correct semantic defaults
>> 3) Eliminates whole categories of bugs that are impractical to detect in C++
>
> I admit I exaggerated in the original post (or was completely wrong. D isn't
> broken) Perhaps we could consider all this as just thinking out loud.
> I have to say I've never really had a problem with slicing (well, maybe
> when I was first learning.) Assigning related value types to each other is
> conversion, not polymorphism, if you accept that you're ok. You could
> make things more interesting though (or a complete hack). You could make
> all your container types descend from one,
> with all virtual functions. In C++ you could then use them as value types,
> and all the functions get called non-virtually or as a reference and
> they're all virtual. Admittedly this rules out the non-virtual case if
> using null pointers to save memory for empty containers. You could
> possibly imagine a third way where a reference (giving you polymorphism)
> simulates value semantics by dupping on every assignment (so you don't
> have to worry if two share data).

oops, typo, i meant reference counting, obviously.
would it be possible to have a way of changing the behaviour of a struct
slightly without having to forward all the calls?
December 13, 2007
Don Clugston wrote:
> Yigal Chripun wrote:
>>  > 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?
> [snip]
>> I'm new to D, but from what little i know, if you want OOP behavior (and matrices would benefit from polymorphism) 
> 
> How? What matrix operations are polymorphic?

i can't think of any... you're right, my bad.
so in that case it does makes sense to use D structs.

My point was that for polymorphic types you need to use classes only, and that can be much simpler to achieve with reference semantics by default (although that's just an implementation detail).

for me, the distinction between PODs and "objects" should be the polymorphic behavior, not the size of it (maybe i didn't explain myself properly). Am i completely wrong here?
December 13, 2007
BC wrote:
>> I admit I exaggerated in the original post (or was completely wrong. D isn't
>> broken) Perhaps we could consider all this as just thinking out loud.
>> I have to say I've never really had a problem with slicing (well, maybe
>> when I was first learning.) Assigning related value types to each other is
>> conversion, not polymorphism, if you accept that you're ok. You could
>> make things more interesting though (or a complete hack). You could make
>> all your container types descend from one,
>> with all virtual functions. In C++ you could then use them as value types,
>> and all the functions get called non-virtually or as a reference and
>> they're all virtual. Admittedly this rules out the non-virtual case if
>> using null pointers to save memory for empty containers.

Yes, in C++ you can do all that. The issue is that when both value and reference semantics are mixed together in one class is that it's almost certainly a broken class design. Complicating the problem is the users of a class have to be careful to only use it as a value type, or only use it as a reference type, per the class implementation. I propose that this is an unnecessary burden on both the class designer and the class user, and certainly C++ code is susceptible to many insidious bugs because of it that are very hard to protect against.


>> You could
>> possibly imagine a third way where a reference (giving you polymorphism)
>> simulates value semantics by dupping on every assignment (so you don't
>> have to worry if two share data).
> 
> oops, typo, i meant reference counting, obviously.
> would it be possible to have a way of changing the behaviour of a struct
> slightly without having to forward all the calls?

The current ideas on doing reference counting in D involve having a struct wrap a class reference. Please note that current C++ reference counting designs do the same thing - C++ offers no efficiency advantage.
December 13, 2007
Yigal Chripun wrote:
> for me, the distinction between PODs and "objects" should be the polymorphic behavior, not the size of it (maybe i didn't explain myself properly). Am i completely wrong here?

You're right. Any object designed for inheritance or polymorphism should properly be a reference type.
December 13, 2007
Walter Bright wrote:
> It's a good question. D structs are designed to represent value types, and classes as reference types. The two have very different uses and characteristics. C++ allows them to be mixed up together, with program bugs as the usual result.
> 
> For example, the slicing problem. If you inherit from a value type, and then add members, then everyone who uses the value type by value "slices" off the additional members.
> 
> Virtual functions make no sense for value types, and non-virtual functions are a recipe for disaster in reference types (hence the exhortation to not forget to make your destructors virtual if deriving from them, a lame bit of advice because base classes cannot control how they are used).
> 
> In C++, one designs a class to be a reference type or a value type. Interestingly, I've never once seen in documentation for a C++ class whether it is supposed to be used by reference or by value.
> 
> Clearly distinguishing value types from reference types:
> 
> 1) Indicates to the user how a type is to be used
> 2) Allows for the correct semantic defaults
> 3) Eliminates whole categories of bugs that are impractical to detect in C++

Hear, hear!  Good arguments, all!  It still doesn't answer why we left out the little star on class-reference variable assignments.  As I've argued before, the question of syntax is orthogonal to the question of legal operations.  Make value-style operations illegal for classes, and keep the star there, IMHO.