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

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

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.

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?

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?

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?

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.

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.

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.