December 09, 2006
Chris Nicholson-Sauls wrote:
> Burton Radons wrote:
>> - Casting a value v to a struct S is now rewritten as S(v).
>>
>> I'm 100% against this. This is what C++ does, and it conflates construction and casting; with some VERY simple examples (such as the first one we think of when we think of additional types, bignums), there's an ambiguous conflict because one of the constructors should have a count of how many digits you want - and one of the casters takes an integer for a value to initialise to. My solution at the time was to add a dummy argument to the constructor so that the compiler didn't try to match them, which is absurd.
>>
>> I don't know why C++ was designed like this when its error was so blatant, but D doesn't need to replicate its mistake. "S.opCastFrom (v)" please, except that it shouldn't be static either.
> 
> Essentially agreed.  I'm not entirely fond of the "silent" new opAssign either, because of the visual ambiguity it can lead to.  (Its worth noting that, even though '='->opAssign is listed in the spec, the bottom of the same page still lists '=' among the operators which will not be given overloads.  Hm.)

Same.  And frankly, I'm having trouble coming up with a practical use for the new opAssign.  For one thing, it isn't commutative:

    auto c = new MyClass;
    int  i = 5;
    c = i; // will work
    i = c; // won't work

And now structs have an opAssign but still have binary copy semantics and no ctor/dtor support.  The result is totally confusing.  What was the use case for this feature?


Sean
December 09, 2006
Jarrett Billingsley wrote:
> "Walter Bright" <newshound@digitalmars.com> wrote in message news:ele2k9$2hr5$1@digitaldaemon.com...
> 
>>More ABI changes, and implicit [] => * no longer allowed.
>>
>>http://www.digitalmars.com/d/changelog.html
>>
>>http://ftp.digitalmars.com/dmd.175.zip
> 
> 
> No offense, but would it honestly kill you to allow ctors in structs?  We've been using static opCall as a _workaround_ for the lack of struct ctors, and making it part of the language doesn't really seem to be addressing the problem.  That, and it doesn't make any sense that classes use "this()" and structs use "static S opCall()".  We're starting to get into "overloading indexing in C++" territory.
> 
> That, and which would be more efficient?  The static opCall needs to return an instance of the struct on the stack, which could be very inefficient for large structs.  With a true ctor, the struct is passed by reference to the ctor and has its fields set directly.
> 
> And I also can't figure out how to make the implicit opCall work with more than one parameter.  :P
> 
> I'm also a little wary about opAssign.  Not that I don't find it useful, just that you've been vehemently opposed to overloading it in D for how many years, and three weeks before 1.0 you reverse your opinion.  What does that mean?
> 

The thing with opAssign, I realised after reading the spec, is that it explicitly doesn't allow copy assignment. This reduces it from the level of a powerful feature to a mere toy, or at most a form of implicit casting.

Assigning one struct to another still guarantees a bitwise copy, and reference assignment for class instances cannot be stepped on. This removes essentially all of the danger that opAssign might have introduced.

> But complaints aside, thanks for removing the []=>* implicit cast and the bugfixes.  Man, this last month has been an exciting time for D :) 
> 
> 


-- 
Kirk McDonald
Pyd: Wrapping Python with D
http://pyd.dsource.org
December 09, 2006
Sean Kelly schrieb:
> Chris Nicholson-Sauls wrote:
>> Burton Radons wrote:
>>> - Casting a value v to a struct S is now rewritten as S(v).
>>>
>>> I'm 100% against this. This is what C++ does, and it conflates construction and casting; with some VERY simple examples (such as the first one we think of when we think of additional types, bignums), there's an ambiguous conflict because one of the constructors should have a count of how many digits you want - and one of the casters takes an integer for a value to initialise to. My solution at the time was to add a dummy argument to the constructor so that the compiler didn't try to match them, which is absurd.
>>>
>>> I don't know why C++ was designed like this when its error was so blatant, but D doesn't need to replicate its mistake. "S.opCastFrom (v)" please, except that it shouldn't be static either.
>>
>> Essentially agreed.  I'm not entirely fond of the "silent" new opAssign either, because of the visual ambiguity it can lead to.  (Its worth noting that, even though '='->opAssign is listed in the spec, the bottom of the same page still lists '=' among the operators which will not be given overloads.  Hm.)
> 
> Same.  And frankly, I'm having trouble coming up with a practical use for the new opAssign.  For one thing, it isn't commutative:
> 
>     auto c = new MyClass;
>     int  i = 5;
>     c = i; // will work
>     i = c; // won't work
> 
> And now structs have an opAssign but still have binary copy semantics and no ctor/dtor support.  The result is totally confusing.  What was the use case for this feature?
> 
> 
> Sean

Why are opAssign overloads possible for structs? They lead to a bad style like the example above: It's possible to assign a primitive type to an aggregate type, without showing what is done in the code.
December 09, 2006
Walter Bright wrote:

> More ABI changes, and implicit [] => * no longer allowed.
> 
> http://www.digitalmars.com/d/changelog.html
> 
> http://ftp.digitalmars.com/dmd.175.zip


opAssing not mentioned here, but anyway I like what I have read in Docs!

Finally I can use more user friendly and compact syntax for assigning values
to Any
(http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D.announce&artnum=4827):

auto v=new Any;

Was:
v.assign(5);

Now:
v=5;

Very good syntax for this kind of container! I just miss templatized constructors and following will be available:

void varFunc(Any[] arr ...) {
        foreach(v; arr) {
                writefln(v.type);
        }
}

void main() {
        bool test;
#       varFunc(new Any(5), new Any("tekst"[]), new Any(&variadicFunction));
#       varFunc(new Any(5.6), new Any(&test));
}

(Currently it is necessary to write:
# varFunc((new Any).assign(5.6), (new Any).assign(&test));
)


I will send updated version of Any soon...

-- 
Regards
Marcin Kuszczak
(Aarti_pl)
December 09, 2006
Jarrett Billingsley wrote:
> No offense, but would it honestly kill you to allow ctors in structs?  We've been using static opCall as a _workaround_ for the lack of struct ctors, and making it part of the language doesn't really seem to be addressing the problem.  That, and it doesn't make any sense that classes use "this()" and structs use "static S opCall()".  We're starting to get into "overloading indexing in C++" territory.

It turns out that static opCall() and this() are equivalent. C++ has some obscure rules to try to disambiguate them. I wished to avoid that problem, and since static opCall() is routinely in use, picked them.

> That, and which would be more efficient?  The static opCall needs to return an instance of the struct on the stack, which could be very inefficient for large structs.  With a true ctor, the struct is passed by reference to the ctor and has its fields set directly.

The optimizer removes the redundant copy, and builds the result directly into the target.

> And I also can't figure out how to make the implicit opCall work with more than one parameter.  :P

S(1,2,3)

> I'm also a little wary about opAssign.  Not that I don't find it useful, just that you've been vehemently opposed to overloading it in D for how many years, and three weeks before 1.0 you reverse your opinion.  What does that mean?

The problem I have, and still have, is the identity assignment. This is specifically disallowed with opAssign. I can go into the reasons why if you like.

Having opAssign for foreign types turns out to be needed for things like, say I want to build a ranged integer. This is an integer that can only have values between m and n. Without opAssign, I'd have to use a property:
	RangedInt!(m,n) r;
	r.value = 6;
It's just not right.

> But complaints aside, thanks for removing the []=>* implicit cast and the bugfixes.  Man, this last month has been an exciting time for D :) 

For me as well!
December 09, 2006
Chris Miller wrote:
> On Sat, 09 Dec 2006 13:59:24 -0500, Walter Bright <newshound@digitalmars.com> wrote:
> 
>> Chris Miller wrote:
>>> Allow static opAssign to return an instance of the class that will be assigned to the lvalue:
>>
>> This wasn't done because there are several use cases where you wouldn't want to erase all previous contents of the struct being assigned to.
> 
> But if it's optional it's up to the struct writer to use void as the return or not.

I don't think that'll work. He'll wind up being forced to set all the fields.
December 09, 2006
"Walter Bright" <newshound@digitalmars.com> wrote in message news:elf9mn$snp$1@digitaldaemon.com...

> It turns out that static opCall() and this() are equivalent. C++ has some obscure rules to try to disambiguate them. I wished to avoid that problem, and since static opCall() is routinely in use, picked them.

For classes they're not.  Why should structs be any different?  And even if static opCalls are routinely in use, are they the best solution?

And are they _really_ equivalent?  Where's the 'this' pointer in a static opCall()?

> The optimizer removes the redundant copy, and builds the result directly into the target.

Wouldn't it be easier to just have ctors, so implementations don't have to worry about writing an optimizer just to support this behavior?

>> And I also can't figure out how to make the implicit opCall work with more than one parameter.  :P
>
> S(1,2,3)

Oh.  I was thinking more along the lines of being able to do "S s(1, 2, 3);".

> The problem I have, and still have, is the identity assignment. This is specifically disallowed with opAssign. I can go into the reasons why if you like.
>
> Having opAssign for foreign types turns out to be needed for things like,
> say I want to build a ranged integer. This is an integer that can only
> have values between m and n. Without opAssign, I'd have to use a property:
> RangedInt!(m,n) r;
> r.value = 6;
> It's just not right.

That makes sense.  It gives the utility of opAssign in most cases without the scary stuff.

Though as was mentioned elsewhere, it's not commutative, so it's still not possible to do

RangedInt!(m, n) r;
r = 5;
int x = r; // error

:/

>> But complaints aside, thanks for removing the []=>* implicit cast and the bugfixes.  Man, this last month has been an exciting time for D :)
>
> For me as well!


December 09, 2006
Walter Bright wrote:
> Jarrett Billingsley wrote:
>> No offense, but would it honestly kill you to allow ctors in structs?  We've been using static opCall as a _workaround_ for the lack of struct ctors, and making it part of the language doesn't really seem to be addressing the problem.  That, and it doesn't make any sense that classes use "this()" and structs use "static S opCall()".  We're starting to get into "overloading indexing in C++" territory.
> 
> It turns out that static opCall() and this() are equivalent. C++ has some obscure rules to try to disambiguate them. I wished to avoid that problem, and since static opCall() is routinely in use, picked them.

Just because someone at some time in the distant pass realized that opCall() simulates constructor-like behavior, it doesn't make it 'ok'; it makes it 'an ok work around'.

Think back over the last year.. how many people have asked how to create a constructor for structs?  How much you wanna bet none of them would have had to ask if 'this' wasn't misspelled as 'opCall'?

Since the desired behavior is construction, let's stop kidding ourselves and actually give structs both the behavior and the syntax of construction, please?  And while you're in there.. how about destruction and RAII?  I guess I'm in the camp that would like to see structs be closer to classes but am ok with them not supporting inheritance and other features that lead to vtables.

Later,
Brad
December 09, 2006

Walter Bright wrote:
> More ABI changes, and implicit [] => * no longer allowed.
> 
> http://www.digitalmars.com/d/changelog.html
> 
> http://ftp.digitalmars.com/dmd.175.zip

# Casting a value v to a struct S is now rewritten as S(v).
# Initializing a struct S from a value v is now rewritten as S(v).

Can you clarify more what that means?

# TypeInfo now always generated for enum, struct, and typedef's, to enable more thorough rtti.

So, can we get a string version of enum values? and can we get struct names?

# hidden feature?

Why is everyone talking about opAssign? I don't see it mentioned in the change log.
December 09, 2006
Walter Bright wrote:

>> I'm also a little wary about opAssign.  Not that I don't find it useful, just that you've been vehemently opposed to overloading it in D for how many years, and three weeks before 1.0 you reverse your opinion.  What does that mean?
> 
> The problem I have, and still have, is the identity assignment. This is specifically disallowed with opAssign. I can go into the reasons why if you like.
> 

I wonder if it is not possible to make D, working as a base with values not with references.

In such a case references would be hidden from programmers and only values would be visible at first. Assigning would always mean assign value, and when there should be passed reference the special syntax would be necessary, so references would be special case.

To disambiguate you can make something like this:

auto v := new Any; // special assignment operator ':=' for references auto z := new Any;

v = 5; // Standard opAssign
z = v; // No problem here, opAssign can be used as usually
z :=v; // Reference copy - opAssign is not used here

Additionally when passing arguments to function, which demands references, there could be used implicit conversion from values to references (so that for user it would be visible as sending values). Below example almost works now (almost because constructors can not be templatized):

void varFunc(Any[] arr ...) {
        foreach(v; arr) writefln(v.type);
}

void main() {
#       varFunc(new Any(5), new Any("tekst"[]), new Any(&variadicFunction));
}

In language in which everything is consider as an object you could just write:

void main() {
        bool test;
#       varFunc(Any(5), Any("tekst"[]), Any(&variadicFunction));
#       varFunc(Any(5.6), Any(&test));
}

If there should be send reference(pointer) it should be done explicitly.
E.g.

void varFunc(Any*[] arr ...) {
....
}
void main() {
#       varFunc(new Any(5), new Any("tekst"[]), new Any(&variadicFunction));
}

Does it make any sense? Please comment...


> Having opAssign for foreign types turns out to be needed for things
> like, say I want to build a ranged integer. This is an integer that can
> only have values between m and n. Without opAssign, I'd have to use a
> property:
> RangedInt!(m,n) r;
> r.value = 6;
> It's just not right.

the same in case of boost::Any port to D.

-- 
Regards
Marcin Kuszczak
(Aarti_pl)