April 21, 2005
In article <d48je6$arv$1@digitaldaemon.com>, TechnoZeus says...
>
>If the programmer wants to be sure that they are assigning values, and not changing the address of somehting, then the ":=" operator would be used...
>
>int a := 5;
>int b;
>int c;
>b := a+7;
>c := b;
>
>No ambiguity there.  Notice that with this convention, one would know what "a := b" is supposed to do, even without knowing what "a" and "b" represent.  The same can not be said of "a = b" in D.
>

The problem with your example in this argument is that it's ambiguous.

b := a+7

Does it mean "take the actual value of the lvalue"?

b = (a+7).opValue;

.. or "take the actual value of all the distinct portions of the lvalue"?

b = a.opValue + 7.opValue;

Which is correct?  Also, keep in mind, that with either interpretation, will limit its percieved utility:

T a,b,c,d;
a := b + c + d;

To obtain the opvalue of just one of b,c or d, i need to use more than one expression; regardless of the actual interpretation of ':='.  To side-step the limitations of the operator.  This is in sharp contrast to operators like good ol' '=' or even '&', which are much more explicit.

With an explicit syntax like '.dup' there's no question as to what's going on.

- EricAnderton at yahoo
April 21, 2005
I should've double-checked before posting.

by 'lvalue', I actually mean 'rvalue'.  Sorry for the confusion.

-EricAnderton at yahoo

In article <d48nr3$ejr$1@digitaldaemon.com>, pragma says...
>
>In article <d48je6$arv$1@digitaldaemon.com>, TechnoZeus says...
>>
>>If the programmer wants to be sure that they are assigning values, and not changing the address of somehting, then the ":=" operator would be used...
>>
>>int a := 5;
>>int b;
>>int c;
>>b := a+7;
>>c := b;
>>
>>No ambiguity there.  Notice that with this convention, one would know what "a := b" is supposed to do, even without knowing what "a" and "b" represent.  The same can not be said of "a = b" in D.
>>
>
>The problem with your example in this argument is that it's ambiguous.
>
>b := a+7
>
>Does it mean "take the actual value of the lvalue"?
>
>b = (a+7).opValue;
>
>.. or "take the actual value of all the distinct portions of the lvalue"?
>
>b = a.opValue + 7.opValue;
>
>Which is correct?  Also, keep in mind, that with either interpretation, will limit its percieved utility:
>
>T a,b,c,d;
>a := b + c + d;
>
>To obtain the opvalue of just one of b,c or d, i need to use more than one expression; regardless of the actual interpretation of ':='.  To side-step the limitations of the operator.  This is in sharp contrast to operators like good ol' '=' or even '&', which are much more explicit.
>
>With an explicit syntax like '.dup' there's no question as to what's going on.
>
>- EricAnderton at yahoo


April 21, 2005
pragma wrote:
> In article <d48gt8$8ao$1@digitaldaemon.com>, Vladimir says...
>>
>>May be we can add ':' unary operator which in expression :a works exactly like a.dup ? So a=b.dup will look as a = :b or even a =: b. When returning from function this will look like { return :a; }.
> 
> The only wart here is that you'll run into small problems with ':' when evaluating the ternary '?' operator:
> 
> foo() ? bar() : a; // what was meant here?  (value-of or ternary else)
> 
> .. but that's strictly a matter of operator precedence.  I for one, don't find it as readable.
> 
> Not that I think it's a good idea, but you could use something like '@' to mean 'value-of' (which would be akin to '&' meaning 'address-of').
> 
> { return @a; }
>
> This isn't too bad, but it still lands us in "create a new operator territory".
But what is so fundamental difference between "create a new property for fundamental data type" and "create a new operator" ?

> 
> I still think .dup() is the way to go.
For me it's just harder to type that @.
The only thing is that having @ operator it's too big tempting to allow T@
for creating class-value-type, which Walter will never accept, wont
he ? :-)
Anyway, if implemented, .dup() or := or @ would be very useful feature.

-- 
          Vladimir
April 21, 2005
In article <d48pet$g4d$1@digitaldaemon.com>, Vladimir says...
>
>> Not that I think it's a good idea, but you could use something like '@' to mean 'value-of' (which would be akin to '&' meaning 'address-of').
>> 
>> { return @a; }
>>
>> This isn't too bad, but it still lands us in "create a new operator territory".
>But what is so fundamental difference between "create a new property for fundamental data type" and "create a new operator" ?

Largely, the compiler impact is the biggest difference; a universal dup() property won't require anything new in the lexer and will likely be easily attached to the property evaluation bits already present.  Adding a ':=' operator requires changes to the lexer, and a expression handling branch, with quirks and rules all its own.  IMO, adding ':=' would be much more work to do, and not worth it since D has already (partially) sovled the problem.

There is a smaller impact to D's grammar is a close second as ':=' is somewhat ambiguous when applied to certain cases; I'm welcome to be wrong about that. Regardless, .dup() is wholly unambiguous and meshes well with the present design.

>
>> 
>> I still think .dup() is the way to go.
>For me it's just harder to type that @.
>The only thing is that having @ operator it's too big tempting to allow T@
>for creating class-value-type, which Walter will never accept, wont
>he ? :-)

Probably not.  Again, I'd be willing to bet that extending .dup to everything would be cake to implement by comparison.

- EricAnderton at yahoo
April 21, 2005
"pragma" <pragma_member@pathlink.com> wrote in message news:d48dib$57l$1@digitaldaemon.com...
> In article <d46v3g$1n7o$1@digitaldaemon.com>, Ben Hinkle says...
>>
>>About the template problem: I'd prefer to look into something like
>>extending
>>".dup" to all types rather than invent a new operator.
>
> Ben, thank you.  You took the words right out of my mouth. :)
>
> For classes, there's no need to make this a formal 'operator'.  It could
> merely
> be added to Object as a shallow copy (return this;) and then overridden in
> any
> class where it's needed.
>
> So really, all that's needed is a 'dup' property for scalars.  The rest is
> up to
> the developer.
[snip]

One issue with .dup is that the expression x.dup calls the same thing if x is a struct or a ptr to a struct. Not that I'm complaining since I don't think the := does any better wrt pointers. In general I'm not optimistic about either := or .dup helping template programming by themselves. I'd like to see more motivating examples of what the problems are and what the workarounds look like. Sometimes the cure is worse than the disease.


April 21, 2005
> Correct me if I'm mistaken, but I think what you are saying only takes reference types into account.  The idea here is to get away from the risk of code failing to work when value types and reference types inevitably get confused.
> 
> There is, for example, not much sense to the following code...
> 
> int a = 5.dup;
> int b;
> int c;
> b = a.dup + 7.dup;
> c = b.dup;
> 
> Of course, this is an extreme case, but it is meant to illustrate a point.
> 
> If the programmer wants to be sure that they are assigning values, and not changing the address of somehting, then the ":=" operator would be used...
> 
> int a := 5;
> int b;
> int c;
> b := a+7;
> c := b;
> 
> No ambiguity there.  Notice that with this convention, one would know what "a := b" is supposed to do,
> even without knowing what "a" and "b" represent.  The same can not be said of "a = b" in D.

Hmm, isn't there a problem that if you do

func(T a)
{
    T b:=a;
}

b is null if T is reference-type, so it can't even have the value assigned? You can't explicitly new it, because that wouldn't work with primitive types again.

It could get automatically allocated, but that'd require the class to have a zero-parameter constructor, which may again break, and in fact, calling it may cause unforeseen effects.

Just allocating memory without calling the constructor is not an option at all, because the opValue (or whatever) may depend on the objects state being initialized...

Furthermore, if you do a:=b+c, you needlessly create a new object (the result of b+c), so it would be very inefficient.

Finally, if (a is b), modifying either with := would also modify the other, so you just move the problem to other cases. In other words, a:=c+d modifies b as well, and it's a=c+d that doesn't.

IMO, all of these mean that := will not actually help with the value_types/reference_types divide, but will instead only shift the problems to other cases.

I think the best option is to either
- write two versions of templates, one specialized on Object, or
- use the a=b+0 idiom and implement opAdd on all relevant classes


xs0
April 21, 2005
xs0 wrote:

> 
>> Correct me if I'm mistaken, but I think what you are saying only takes reference types into account.  The idea here is to get away from the risk of code failing to work when value types and reference types inevitably get confused.
>> 
>> There is, for example, not much sense to the following code...
>> 
>> int a = 5.dup;
>> int b;
>> int c;
>> b = a.dup + 7.dup;
>> c = b.dup;
>> 
>> Of course, this is an extreme case, but it is meant to illustrate a point.
>> 
>> If the programmer wants to be sure that they are assigning values, and not changing the address of somehting, then the ":=" operator would be used...
>> 
>> int a := 5;
>> int b;
>> int c;
>> b := a+7;
>> c := b;
>> 
>> No ambiguity there.  Notice that with this convention, one would know
>> what "a := b" is supposed to do,
>> even without knowing what "a" and "b" represent.  The same can not be
>> said of "a = b" in D.
> 
> Hmm, isn't there a problem that if you do
> 
> func(T a)
> {
>      T b:=a;
> }
> 
> b is null if T is reference-type, so it can't even have the value assigned? You can't explicitly new it, because that wouldn't work with primitive types again.
> 
> It could get automatically allocated, but that'd require the class to have a zero-parameter constructor, which may again break, and in fact, calling it may cause unforeseen effects.
Please, look at my post in different branch of this thread: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/22165

> Just allocating memory without calling the constructor is not an option at all, because the opValue (or whatever) may depend on the objects state being initialized...
> 
> Furthermore, if you do a:=b+c, you needlessly create a new object (the result of b+c), so it would be very inefficient.
> 
> Finally, if (a is b), modifying either with := would also modify the other, so you just move the problem to other cases. In other words, a:=c+d modifies b as well, and it's a=c+d that doesn't.
> 
> IMO, all of these mean that := will not actually help with the value_types/reference_types divide, but will instead only shift the problems to other cases.
> 
> I think the best option is to either
> - write two versions of templates, one specialized on Object, or
> - use the a=b+0 idiom and implement opAdd on all relevant classes
> 
> 
> xs0

-- 
          Vladimir
April 21, 2005
Ben Hinkle wrote:
> I'd like to see more motivating examples of what the problems are and what the workarounds look like. Sometimes the cure is worse than the disease.

One of examples you can find at the end of my post in different branch of this thread: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/22137

Of course there are workarounds, but they are ugly and error-prone.
The biggest problems occurs when one tries to make template from
non-template function. Or when one had written and tested template and then
realized that it won't work with his new class-based type and should be
rewritten. And this can't be solved with .dup() property.

BTW in C++ this example can be _easily_ implemented.

-- 
          Vladimir
April 21, 2005
On Thu, 21 Apr 2005 14:32:43 +0000 (UTC), pragma <pragma_member@pathlink.com> wrote:
> In article <d46v3g$1n7o$1@digitaldaemon.com>, Ben Hinkle says...
>>
>> About the template problem: I'd prefer to look into something like extending
>> ".dup" to all types rather than invent a new operator.
>
> Ben, thank you.  You took the words right out of my mouth. :)
>
> For classes, there's no need to make this a formal 'operator'.  It could merely
> be added to Object as a shallow copy (return this;) and then overridden in any
> class where it's needed.
>
> So really, all that's needed is a 'dup' property for scalars.  The rest is up to
> the developer.
>
>
> class Foobar{
> public Foobar dup(){
> return this; // or a copy
> }
> }
>
> void main(){
> Foobar a,b;
> a = new Foobar();
> b = a.dup; // custom ('deep') copy
>
> int c,d;
> c = d.dup; // value-copy: allowed for consistency
>
> int[] e,f
> e = f.dup; // old hat
> }
>
> The above folds into templates, extremely well:
>
> template valueOf(T){ T valueOf(T x){ return x.dup; } }
>
> .. where 'T' can be, well, anything.  I'll add that the above is also
> *impossible* with ':=' and would require a temporary varible to work.  Thus, it
> would be less flexible (and probably useful IMO).
>
> There's absolutely no need for an additional operator like ':='.

Assuming .dup is added for intrinsics. However... Dereks original goal was to achieve this:

class A {}
class B {}

A a = new A();
B b;

b = a;

i.e. construct b using a.

The current proposed method is a copy constructor. But, as intrinsics have no constructors how do you write it generically?

:= solves that problem as well as the other which .dup can solve.

Regan
April 21, 2005
On Thu, 21 Apr 2005 12:44:35 -0400, Ben Hinkle <ben.hinkle@gmail.com> wrote:
> "TechnoZeus" <TechnoZeus@PeoplePC.com> wrote in message
> news:d48iic$9se$1@digitaldaemon.com...
>> It's a big thread... that might have been in it somewhere.
>> This branch of it deals with adding ":=" as a separate operator in
>> addition to the "=" operator,
>> and having ":=" act as a value assignment operator such that...
>> a := b;
>> anways results in (a == b) being true, but never makes (a is b) become
>> true.
>>
>> Not related to overloading the "=" operator.
>>
>> TZ
>
> hehe. Sorry but it sounds funny to say an operator called := with overload
> opAssign is not related to overloading assignment. I would bet no matter
> what the symbol is and the overload name Walter's objections would still
> apply.

But they don't as far as I can see. Reading:
http://www.digitalmars.com/d/faq.html#assignmentoverloading

and remembering he mentioned something along the lines of "overloading = causes subtle behaviour which is a source of bugs for little gain".

1. := is a new operator, so no subtle behaviour for = is added.

2. You could argue := has the subtle behaviour, but I argue it isn't subtle because if you use := you're asking for that behaviour.

3. The copy constructor argument is on the surface valid, but consider intrinsics which have no constructors at all.

4. Lastly .dup does not solve the whole problem, the original intent was to make this possible:

class A{}
class B{}

A a = new A();
B b;

b = a;

construct a A using an A.

So while you can write a copy constructor:

class A {
 this(B b) {}
}

intrinsics don't have constructors so in a template:

template(T) { void foo(T t) {
  B b = new B();
  T t;

  t = new T(b);
}}

it doesn't work when T is 'int' etc.


.dup does not solve the above as:
  t = b.dup

returns a B not a T.


However := solves both problems neatly.

t := b;

calls opAssign for type T (for intrinsics it would do what it currently does on assignment).

Regan