View mode: basic / threaded / horizontal-split · Log in · Help
December 14, 2006
Re: DMD 0.177 release
Andrei Alexandrescu (See Website for Email) wrote:
> That makes me wonder - if a = b is used without picking up its result 
> (the usual case), and if opAssign() returns an S, will the compiler 
> optimize away the extra copy at zero cost?

No. The caller and callee don't know about each other.

> What I think happens is that the function will take a pointer to the 
> destination which is zero, so a comparison will be made. But perhaps the 
> optimizer will take care of eliminating that?

You could have a null pointer passed to the return result, but that 
would entail an extra check on the part of the callee.

This is why a lot of C++ code tends to return references instead of values.
December 14, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> BCS wrote:
> 
>> With constructors, it is not only simpler code, but looks like what is 
>> happening.
>>
>> struct S
>> {
>>     static S err;
>>     int k, l;
>>
>>     this(int i, int j)
>>     {
>>         k=i;
>>         l=j;
>>
>>         if(!ret.test) this = err;
>>     }
>>
>>     bool test(){...}
>> }
> 
> 
> Assignment to this inside a constructor is a mistake as it breaks the 
> assumptions the language makes about constructors.

What assumptions does it break? This would be valid:

struct S
{
    static S err;
    int k, l;
    this(int i, int j)
    {
        k=i;
        l=j;
        if(!ret.test)
        {
           this.k = err.k;
           this.l = err.l;
        }
    }
    bool test(){...}
}

and as far as I can tell, they are the same.
OK well maybe it should have been written as this:

        if(!ret.test) *this = err;
                   // ^- add this

Either way, I think the original argument still holds. The constructor 
form still looks more like what is acutely happening, and as a result 
has less of a "phantom" cost.
December 14, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> Andrei Alexandrescu (See Website for Email) wrote:
> 
>> That makes me wonder - if a = b is used without picking up its result 
>> (the usual case), and if opAssign() returns an S, will the compiler 
>> optimize away the extra copy at zero cost?
> 
> 
> No. The caller and callee don't know about each other.
> 
>> What I think happens is that the function will take a pointer to the 
>> destination which is zero, so a comparison will be made. But perhaps 
>> the optimizer will take care of eliminating that?
> 
> 
> You could have a null pointer passed to the return result, but that 
> would entail an extra check on the part of the callee.
> 
> This is why a lot of C++ code tends to return references instead of values.

I guess compiling internally two versions, one that returns S and one 
that returns void, might be worth looking into. Because right now user 
code for opAssign() can't be politically correct and efficient at the 
same time.

Here's a better alternative:

Require opAssign() to always return void and have the compiler return a 
reference to the left-hand side. That is, transform:

a = b;

into:

(a.opAssign(b), a);

with the mention that a only gets evaluated once.

This way assignment _always_ returns its left-hand side and user code 
cannot subvert that behavior. Also the code will be efficient because no 
more spurious copies are being made.


Andrei
December 14, 2006
Re: DMD 0.177 release
Let's not forget that the members of a struct can be initialized "inline":

struct X {
 int a = 2;
}

This makes the lack of constructors for structs a lot less significant.

Additionally, destructors for structs are primarily used for wrappers, RAII, 
and let's not forget scope(...), which is much better suited for RAII than 
destructors ever were. It makes the lack of destructors for structs a lot 
less significant..

So, if people want a C++-looking initialize function, they can use static 
opCall, and it'll look like a call to a constructor (ie. having the same 
name as the struct).

L.
December 14, 2006
Re: DMD 0.177 release
"Alexander Panek" <a.panek@brainsware.org> wrote in message 
news:eln5td$2pta$1@digitaldaemon.com...
> Are you, actually, talking about a D -> MSIL compiler, so it can be run 
> inside the VM and a .NET implementation in D, for that purpose? Or do you 
> mean something /similar/ to C# + .NET? If so, I agree. Something like that 
> has to be in D. :) I hope this will pop up

We had one, once : ( but then the guy's HDD crashed... Sad, sad story.

L.
December 14, 2006
Re: DMD 0.177 release
BCS wrote:
> OK well maybe it should have been written as this:
> 
>         if(!ret.test) *this = err;
>                    // ^- add this

That's completely different <g>.

> Either way, I think the original argument still holds. The constructor 
> form still looks more like what is acutely happening, and as a result 
> has less of a "phantom" cost.
December 14, 2006
Re: DMD 0.177 release
Andrei Alexandrescu (See Website For Email) wrote:
> I guess compiling internally two versions, one that returns S and one 
> that returns void, might be worth looking into. Because right now user 
> code for opAssign() can't be politically correct and efficient at the 
> same time.
> 
> Here's a better alternative:
> 
> Require opAssign() to always return void and have the compiler return a 
> reference to the left-hand side. That is, transform:
> 
> a = b;
> 
> into:
> 
> (a.opAssign(b), a);
> 
> with the mention that a only gets evaluated once.
> 
> This way assignment _always_ returns its left-hand side and user code 
> cannot subvert that behavior. Also the code will be efficient because no 
> more spurious copies are being made.

It is possible to force the return type of opAssign. But I'd suggest 
making it an S*, with the rewrite to:

	*(a.opAssign(b))
December 14, 2006
Re: DMD 0.177 release
== Quote from Andrei Alexandrescu (See Website For Email)
(SeeWebsiteForEmail@erdani.org)'s article
> Walter Bright wrote:
> > Andrei Alexandrescu (See Website for Email) wrote:
> >
> >> That makes me wonder - if a = b is used without picking up its result
> >> (the usual case), and if opAssign() returns an S, will the compiler
> >> optimize away the extra copy at zero cost?
> >
> >
> > No. The caller and callee don't know about each other.
> >
> >> What I think happens is that the function will take a pointer to the
> >> destination which is zero, so a comparison will be made. But perhaps
> >> the optimizer will take care of eliminating that?
> >
> >
> > You could have a null pointer passed to the return result, but that
> > would entail an extra check on the part of the callee.
> >
> > This is why a lot of C++ code tends to return references instead of values.
> I guess compiling internally two versions, one that returns S and one
> that returns void, might be worth looking into. Because right now user
> code for opAssign() can't be politically correct and efficient at the
> same time.
> Here's a better alternative:
> Require opAssign() to always return void and have the compiler return a
> reference to the left-hand side. That is, transform:
> a = b;
> into:
> (a.opAssign(b), a);
> with the mention that a only gets evaluated once.
> This way assignment _always_ returns its left-hand side and user code
> cannot subvert that behavior. Also the code will be efficient because no
> more spurious copies are being made.
> Andrei

I wonder, are there cases where assignment should not return 'this'?

What I'm thinking of is something like:

class StringExpression {
 ... holds equations between strings
};

class String {
  // wrapper around char[]
  StringExpression opCat(String x);
  StringExpression opCat(StringExpression x);
};

This 'expression-class' stuff is done more commonly with matrices, where the
programmer is trying to to combine multiplies and adds via some optimization rules.

Since C++ at least is flexible (syntax wise at least) on operator inputs and
outputs, I have to wonder if there are really consequences for not following those
expectations here.

Imagine a string expression like this:

a = b ~ (c = d ~ e);

Now if I can do "StringExpression String::opAssign(...)", this could maybe be
rewritten (code not shown...) to result in something like this:

a = b ~ d ~ e;
c = a[b.length..a.length];

Not that this is worth the effort or that the language should do this with
strings, but as a programmer, can I reasonably do this kind of trick with operator
return values or am I just digging a hole for myself?  (I realize that even if
useful it may not be worthwhile.)

Kevin
December 14, 2006
Re: DMD 0.177 release
Walter Bright wrote:
> It is possible to force the return type of opAssign. But I'd suggest 
> making it an S*, with the rewrite to:
> 
>     *(a.opAssign(b))
> 

class C {
  C* opAssign(...) {...}
}
struct S {
  S* opAssign(...) {...}
}

Seriously?? Ugh.

Why not just "C opAssign" and "S opAssign"? In the opCall discussion you 
said yourself that the return value will be optimized.

Am I missing something?

L.
December 14, 2006
Re: DMD 0.177 release
Lionello Lunesu wrote:
> "Alexander Panek" <a.panek@brainsware.org> wrote in message 
> news:eln5td$2pta$1@digitaldaemon.com...
>> Are you, actually, talking about a D -> MSIL compiler, so it can be run 
>> inside the VM and a .NET implementation in D, for that purpose? Or do you 
>> mean something /similar/ to C# + .NET? If so, I agree. Something like that 
>> has to be in D. :) I hope this will pop up
> 
> We had one, once : ( but then the guy's HDD crashed... Sad, sad story.
> 
> L. 
> 
> 

https://mywebspace.wisc.edu/daaugustine/web/d/

This is all that remains of all his work, so far as I can tell.  Some day it would be nice 
if http://www.scratch-ware.net/dfiles/ suddenly existed again.  Oh well.

-- Chris Nicholson-Sauls
9 10 11 12 13 14 15 16 17
Top | Discussion index | About this forum | D home