December 13, 2007
Russell Lewis wrote:
> 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.

It would make writing generic code unnecessarily difficult.
December 14, 2007
Walter Bright wrote:
> Russell Lewis wrote:
>> 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.
> 
> It would make writing generic code unnecessarily difficult.

????  I thought that one of the key arguments for putting the syntax back to the C++ way was that it would make generic code easier to write.  Right now, when we perform an assignment, generic code can't know (without specialization) whether it is assigning a value or a reference type.
December 14, 2007
On Thu, 13 Dec 2007 00:59:33 -0000, BC <NOTmi_emayl_adrez@hotmail.com.remove.not> wrote:

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

I think the problem with C++ (problem may be too harsh) is you are forced to choose between
pass by reference and pass by value semantics. Though in practice you rarely choose value semantics.
There seems to be a lot of toing and froing over which is best.
In my opinion there should be one default calling convention and the compiler decides
whether to pass by reference or value as it ought to know best which will be more efficient.
As programmer you just want to get on and code.
Note the ought though. I think there should be an option to choose one or the other when you
as programmer have good reason to believe one will perform better than the other. I'm not sure that
D makes this easy.
The important part of the contract is whether the object passed is mutable or not and this is why we need const.

Regards,

Bruce. (drunk and sleepy)
December 14, 2007
Russell Lewis wrote:
> Walter Bright wrote:
>> Russell Lewis wrote:
>>> 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.
>>
>> It would make writing generic code unnecessarily difficult.
> 
> ????  I thought that one of the key arguments for putting the syntax back to the C++ way was that it would make generic code easier to write.  Right now, when we perform an assignment, generic code can't know (without specialization) whether it is assigning a value or a reference type.

Because if I replace a struct with a class, then I have to go through every use of the struct and add a *.
December 14, 2007
"Walter Bright" <newshound1@digitalmars.com> wrote in message news:fjs7dt$2civ$1@digitalmars.com...
>>
>> 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.

Why not have ref counting built in (but optional) for classes, like 'scope' is. If the class is defined as such, or the declared as such, then it becomes a ref counted object. The ref count could follow the vtable pointer, and if it is < 0 then the object is not ref counted, if >= 0 then it is. Then any (de)assignments, become a matter of checking the class ref count, and a locked inc / dec it if it is a counted class.

Or have ref counted objects as only assignable to ref count referances. Eg..

Foo a;
counted Foo b;
counted Foo c = new Foo();

a = b; // error
b = c; // Ok
c = a; // error

I guess it wouldnt be popular if it added too much overhead to assignments. But it can be optimized for the non ref counted situation, the ref counted situation would require a lock instruction to be thread safe, and they are expensive anyway.

Can the wrapping of a class referance in a struct decrease the ref count on scope exit? Eg..

if (somthing)
{
     counted Foo f = this.getFoo();  <- Inc ref count
    // ...
} <-- can the struct wrapping class dec ref count here as f goes out of
scope?





December 14, 2007
On Thu, 13 Dec 2007 21:13:43 -0000, Walter Bright <newshound1@digitalmars.com> wrote:

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

I guess wrapping has most of the same effect as inheritance with non-virtual calls. Does that mean it will be possible to overload struct T.opAssign(T) to make the counting more robust?

PS. Will dmc++0x be out early due to already implementing most of it once?
December 14, 2007
Walter Bright wrote:
> 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.

Is this because it is too difficult to implement polymorphism for value types safely and efficiently right now?

There's the slicing problem, of course, but there should be ways around that: worst case, you could rebuild the current stack frame each time you assign a polymorphic struct, but the effects on performance would be unpleasant. More happily, you could handle polymorphic structs like classes, but copy on (non-const) assignment.

That would be allowed in D, if you could overload T.opAssign(T).
December 15, 2007
Christopher Wright wrote:
> That would be allowed in D, if you could overload T.opAssign(T).

C++ still has well-known slicing problems, even with overloading assignment.

The question is not "can this be done", it's more "is there a compelling reason to support such behavior". I think the answer is no. Do you really want a language where a class designer feels compelled to define an opassign overload, then make it private to prevent people from using the class as a value type? Where the base class designer needs to know what the derived classes are doing so he can make the destructor virtual or not? Where you cannot have arrays of base classes?
December 16, 2007
Walter Bright wrote:
> Christopher Wright wrote:
>> That would be allowed in D, if you could overload T.opAssign(T).
> 
> C++ still has well-known slicing problems, even with overloading assignment.
> 
> The question is not "can this be done", it's more "is there a compelling reason to support such behavior". I think the answer is no. Do you really want a language where a class designer feels compelled to define an opassign overload, then make it private to prevent people from using the class as a value type? Where the base class designer needs to know what the derived classes are doing so he can make the destructor virtual or not? Where you cannot have arrays of base classes?

At least C++ lets you control copying behavior completely in all circumstances.  And documents what you are supposed to do clearly. Right now D gives you the choice of

1) [structs] copy by value only, with no option to customize or intercept copy operations
2) [classes] no defined copy behavior whatsoever

1) makes interesting ref counting wrappers etc impossible, but I think you're planning to fix that one.

I think 2) is a problem also.  It means that developers will each come up with their own way to copy objects because there's no clear way to do it.  I think some particular scheme should be crowned, like any class that wants to be copyable should provide a the pair of methods dup(), and copy(ThisType).  And maybe there should be something in Object to this effect also, even if they don't do much of anything.  Looks like java implements a clone() method in the base Object class.  But it looks like that just makes it so you get a runtime exception if the class you're trying to clone doesn't support cloning.  That doesn't seem like an improvement over a compile time error.

So I'm not really sure what should be done, but I definitely think something should be done to specify "the D way" to polymorphically copy objects.  Built-ins mostly have .dup properties, but I don't think the spec actually says anywhere that user classes that want to be copyable should have a .dup.  But even specifying a .dup is not enough I think, because if I derive from some class A, I have to create my derived class, then get class A to copy the A parts of the new object somehow, say via a method like A.copy(A copy_from).

C++ may have problems regarding copying classes, but D's solution is effectively to just remove the C++ functionality good and bad.  Ok the slicing problem is gone, but so is copying.  There should be one obvious way to make classes in D copyable, whether it be enforced by the language, compiler, or simply the spec and D community.

--bb
December 16, 2007
Bill Baxter wrote:
> Walter Bright wrote:
>> Christopher Wright wrote:
>>> That would be allowed in D, if you could overload T.opAssign(T).
>>
>> C++ still has well-known slicing problems, even with overloading assignment.
>>
>> The question is not "can this be done", it's more "is there a compelling reason to support such behavior". I think the answer is no. Do you really want a language where a class designer feels compelled to define an opassign overload, then make it private to prevent people from using the class as a value type? Where the base class designer needs to know what the derived classes are doing so he can make the destructor virtual or not? Where you cannot have arrays of base classes?
> 
> At least C++ lets you control copying behavior completely in all circumstances.  And documents what you are supposed to do clearly. Right now D gives you the choice of
> 
> 1) [structs] copy by value only, with no option to customize or intercept copy operations
> 2) [classes] no defined copy behavior whatsoever
> 
> 1) makes interesting ref counting wrappers etc impossible, but I think you're planning to fix that one.
> 
> I think 2) is a problem also.  It means that developers will each come up with their own way to copy objects because there's no clear way to do it.  I think some particular scheme should be crowned, like any class that wants to be copyable should provide a the pair of methods dup(), and copy(ThisType).  And maybe there should be something in Object to this effect also, even if they don't do much of anything.  Looks like java implements a clone() method in the base Object class.  But it looks like that just makes it so you get a runtime exception if the class you're trying to clone doesn't support cloning.  That doesn't seem like an improvement over a compile time error.
> 
> So I'm not really sure what should be done, but I definitely think something should be done to specify "the D way" to polymorphically copy objects.  Built-ins mostly have .dup properties, but I don't think the spec actually says anywhere that user classes that want to be copyable should have a .dup.  But even specifying a .dup is not enough I think, because if I derive from some class A, I have to create my derived class, then get class A to copy the A parts of the new object somehow, say via a method like A.copy(A copy_from).
> 
> C++ may have problems regarding copying classes, but D's solution is effectively to just remove the C++ functionality good and bad.  Ok the slicing problem is gone, but so is copying.  There should be one obvious way to make classes in D copyable, whether it be enforced by the language, compiler, or simply the spec and D community.
> 
> --bb

In java you also need to implement a clonable interface which is a marker interface.
I think that adding a clonable interface to the standard library should be enough. something like:
---
interface clonable {
	object dup();
}
---
now you need to implement it to support copying. I don't think a dup method should be added to object. as you said, it isn't really an improvement, and usually Java experts recommend avoiding clone().
also, i don't see why a copy method is required.
for example, check the following code:
---
class Base : clonable {
    Base dup() {
       auto ret = cast(Base) this.classinfo.create;
       ret.x = this.x;
       ret.y = this.y;
       return ret;
    }
    int x = 6;
    double y = 8;
}

class DerivedA : Base {
    override DerivedA dup() {
       auto ret = cast(DerivedA) super.dup;
       ret.w = this.w;
       return ret;
    }
    long w = 42;
}