www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opAssign and const?

reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
  I have the following dilemma. Hopefully I have this right.

struct X {
   ref X opAssign(X x2);
   ref X opAssign(ref X x2);
}

X fn();

void func(){
   X x, x2;

   x = x2; //uses ref
   x = fn(); //without ref
}

  According to the book, this is how it is suppose to be. const is 
a added promise not to modify anything. So... if i changed the 
ref to ref const... it won't call unless the item input was const 
as well.

//same as above except..
struct X {
   ref X opAssign(X x2);
   ref X opAssign(ref const X x2); //const added
}

void func(){
   X x, x2;
   const X x3;

   x = x2; //without ref???
   x = x3; //ref
}

  Since the input is intended to be read only anyways, why won't 
it work as expected with x = x2? This seems like a bug. If it's 
not, then I need to make two ref versions so it will behave 
properly. (If you need I can past actual working example)
May 03 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, May 04, 2012 07:49:29 Era Scarecrow wrote:
   I have the following dilemma. Hopefully I have this right.
 
 struct X {
    ref X opAssign(X x2);
    ref X opAssign(ref X x2);
 }
 
 X fn();
 
 void func(){
    X x, x2;
 
    x = x2; //uses ref
    x = fn(); //without ref
 }
 
   According to the book, this is how it is suppose to be. const is
 a added promise not to modify anything. So... if i changed the
 ref to ref const... it won't call unless the item input was const
 as well.
 
 //same as above except..
 struct X {
    ref X opAssign(X x2);
    ref X opAssign(ref const X x2); //const added
 }
 
 void func(){
    X x, x2;
    const X x3;
 
    x = x2; //without ref???
    x = x3; //ref
 }
 
   Since the input is intended to be read only anyways, why won't
 it work as expected with x = x2? This seems like a bug. If it's
 not, then I need to make two ref versions so it will behave
 properly. (If you need I can past actual working example)

I believe that the issue is that x2 isn't const, so when the compiler decides which of the two overloads to use, it picks the one which doesn't use const. If the const ref version were the only one, then it would work with x2, but since it isn't, the other one gets picked because it's deemed a better match. - Jonathan M Davis
May 03 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 May 2012 at 06:15:21 UTC, Jonathan M Davis wrote:
 I believe that the issue is that x2 isn't const, so when the 
 compiler decides which of the two overloads to use, it picks 
 the one which doesn't use const. If the const ref version were 
 the only one, then it would work with x2, but since it isn't, 
 the other one gets picked because it's deemed a better match.

I figured that was the case too. But I get the feeling that's wrong in this case. I was hoping to have only two declared opAssing's, one for temporaries (without ref) and one for copying. Kinda like the difference between saying a=b and a[]=b[] for an array. Be annoying if I had to force the cast to be const to do what I wanted; Right?
May 03 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 May 2012 at 06:32:41 UTC, Era Scarecrow wrote:
 opAssing's

Hmmm suppose to be OpAssign. Nothing quite like a bug in your automatic text converter right?
May 03 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, May 04, 2012 08:32:40 Era Scarecrow wrote:
 On Friday, 4 May 2012 at 06:15:21 UTC, Jonathan M Davis wrote:
 I believe that the issue is that x2 isn't const, so when the
 compiler decides which of the two overloads to use, it picks
 the one which doesn't use const. If the const ref version were
 the only one, then it would work with x2, but since it isn't,
 the other one gets picked because it's deemed a better match.

I figured that was the case too. But I get the feeling that's wrong in this case. I was hoping to have only two declared opAssing's, one for temporaries (without ref) and one for copying. Kinda like the difference between saying a=b and a[]=b[] for an array. Be annoying if I had to force the cast to be const to do what I wanted; Right?

If you make the one which isn't a ref const as well, it'll probably work. - Jonathan M Davis
May 03 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 May 2012 at 06:48:40 UTC, Jonathan M Davis wrote:
 If you make the one which isn't a ref const as well, it'll 
 probably work.

Yeah I think so too. It will just be either a direct copy or I cast the object as const and pass it through. Seems like extra work to me and should be handled by the compiler. Anyways, thanks for looking at the problem with me.
May 03 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, May 04, 2012 08:52:49 Era Scarecrow wrote:
 On Friday, 4 May 2012 at 06:48:40 UTC, Jonathan M Davis wrote:
 If you make the one which isn't a ref const as well, it'll
 probably work.

Yeah I think so too. It will just be either a direct copy or I cast the object as const and pass it through. Seems like extra work to me and should be handled by the compiler. Anyways, thanks for looking at the problem with me.

With the last beta, there was a discussion in changing how ref and const ref works to allow rvalues while disallowing whatever use cases it is that causes problems with that in C++. If that gets sorted out and fully implemented, then you'd only need one overload. As it stands, the closest that you could get would be to use auto ref, but that only works with templated functions. - Jonathan M Davis
May 03 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 May 2012 at 06:55:47 UTC, Jonathan M Davis wrote:
 With the last beta, there was a discussion in changing how ref 
 and const ref works to allow rvalues while disallowing whatever 
 use cases it is that causes problems with that in C++. If that 
 gets sorted out and fully implemented, then you'd only need one 
 overload. As it stands, the closest that you could get would be 
 to use auto ref, but that only works with templated functions.

I'll be looking forward to how that works out. I'm trying to be contentious of what code I can label as const (usable) and what I can't. I know there will be cases where I am using my struct as const, and having this minor oddity come out of the woodwork is one of the first real issues I've found that wasn't my own fault.
May 04 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 04 May 2012 02:52:49 -0400, Era Scarecrow <rtcvb32 yahoo.com>  
wrote:

 On Friday, 4 May 2012 at 06:48:40 UTC, Jonathan M Davis wrote:
 If you make the one which isn't a ref const as well, it'll probably  
 work.

Yeah I think so too. It will just be either a direct copy or I cast the object as const and pass it through. Seems like extra work to me and should be handled by the compiler. Anyways, thanks for looking at the problem with me.

I don't think it will make a copy of a temporary even if it's cast to const. I think marking the non-ref version as const will solve the problem how you wish (as long as the argument really *isn't* modified inside that function). -Steve
May 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 May 2012 at 12:42:54 UTC, Steven Schveighoffer wrote:
 I don't think it will make a copy of a temporary even if it's  
 cast to const.  I think marking the non-ref version as const  
 will solve the problem how you wish (as long as the argument  
 really *isn't* modified inside that function).

Well the result seems to be true enough.. It also seems to work if both are const. Why didn't I consider that before? Maybe it should be noted in the next TDPL book. import std.stdio; import std.conv; struct X { int x; int y; this (int x1, int y1) { x = x1; y = y1; } ref X opAssign(const X x2) { writeln("from temporary?"); x=x2.x; y=x2.y; return this; } ref X opAssign(const ref X x2) { writeln("copy specific values?"); x=x2.x; return this; } } //from temporary X fn() { return X(1,2); } void main() { X x = X(3,4); X y = X(5,6); x = y; // 5,4 or 5,6? writeln("Should selectively copy (5,4) - ", to!string(x)); x = fn(); // 1,2 writeln("should overwrite all (1,2)- ", to!string(x)); }
May 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 May 2012 at 20:35:57 UTC, Era Scarecrow wrote:

  Well the result seems to be true enough.. It also seems to 
 work if both are const. Why didn't I consider that before? 
 Maybe it should be noted in the next TDPL book.

As I look at my code I realize why now. Pointers and arrays... that's why... test.d(16): Error: cannot implicitly convert expression (x2.y) of type const(int[]) to int[] Which is why I was trying to suggest the ref was const since I wasn't modifying and could ensure it (just copying between buffers) but the temporary I'm taking over.. So that doesn't work now. This means I'll likely need 2 copies of the ref; 1 const and 1 non-const. import std.stdio; import std.conv; struct X { int x; int[] y; this (int x1, int y1) { x = x1; y ~= y1; } //const here won't work. ref X opAssign(const X x2) { writeln("from temporary?"); x=x2.x; y=x2.y; //breaks here return this; } ref X opAssign(ref const X x2) { writeln("copy specific values?"); x=x2.x; y[]=x2.y[]; return this; } } X fn() { return X(1,2); } void main() { X x = X(3,4); X y = X(5,6); x = y; writeln("Should selectively copy (ref)- ", to!string(x)); x = fn(); writeln("should overwrite all - ", to!string(x)); }
May 04 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 04 May 2012 16:47:07 -0400, Era Scarecrow <rtcvb32 yahoo.com>  
wrote:

 On Friday, 4 May 2012 at 20:35:57 UTC, Era Scarecrow wrote:

  Well the result seems to be true enough.. It also seems to work if  
 both are const. Why didn't I consider that before? Maybe it should be  
 noted in the next TDPL book.

As I look at my code I realize why now. Pointers and arrays... that's why... test.d(16): Error: cannot implicitly convert expression (x2.y) of type const(int[]) to int[] Which is why I was trying to suggest the ref was const since I wasn't modifying and could ensure it (just copying between buffers) but the temporary I'm taking over.. So that doesn't work now. This means I'll likely need 2 copies of the ref; 1 const and 1 non-const. import std.stdio; import std.conv; struct X { int x; int[] y; this (int x1, int y1) { x = x1; y ~= y1; } //const here won't work. ref X opAssign(const X x2) { writeln("from temporary?"); x=x2.x; y=x2.y; //breaks here

y[] = x2.y[]; // as you did below
      return this;
    }

    ref X opAssign(ref const X x2) {
      writeln("copy specific values?");
      x=x2.x;
 	y[]=x2.y[];
      return this;
    }
 }

 X fn() {
    return X(1,2);
 }

 void main()
 {
    X x = X(3,4);
    X y = X(5,6);

    x = y;
    writeln("Should selectively copy (ref)- ", to!string(x));

    x = fn();
    writeln("should overwrite all - ", to!string(x));
 }

btw, are you sure the lengths will always be identical? Otherwise, you may want to do y.length = x2.y.length first. -Steve
May 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 May 2012 at 21:12:55 UTC, Steven Schveighoffer wrote:
 y[] = x2.y[];
 // as you did below

That may deal with the language requirements, but the ideal was to take over the temporary; If not the ref would copy the contents. I wonder if I will need to have 2 copies of each opAssign to satisfy everything.
 btw, are you sure the lengths will always be identical?  
 Otherwise, you may want to do y.length = x2.y.length first.

This example code doesn't cover that, but yes I have checks in place for such an occurrence. Likely 99% of the time copying will be between identical sizes.
May 04 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 04 May 2012 17:26:02 -0400, Era Scarecrow <rtcvb32 yahoo.com>  
wrote:

 On Friday, 4 May 2012 at 21:12:55 UTC, Steven Schveighoffer wrote:
 y[] = x2.y[];
 // as you did below

That may deal with the language requirements, but the ideal was to take over the temporary; If not the ref would copy the contents. I wonder if I will need to have 2 copies of each opAssign to satisfy everything.

OK, I see what you are trying to do. I'll have to think about it some more. I'm very concerned that you could potentially end up calling this function with an lvalue, which would make this a disasterous strategy. -Steve
May 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 4 May 2012 at 21:29:14 UTC, Steven Schveighoffer wrote:
 On Fri, 04 May 2012 17:26:02 -0400, Era Scarecrow
 On Friday, 4 May 2012 at 21:12:55 UTC, Steven Schveighoffer 
 wrote:
 y[] = x2.y[];
 // as you did below

That may deal with the language requirements, but the ideal was to take over the temporary; If not the ref would copy the contents. I wonder if I will need to have 2 copies of each opAssign to satisfy everything.


 OK, I see what you are trying to do.  I'll have to think about  
 it some more.  I'm very concerned that you could potentially  
 end up calling this function with an lvalue, which would make  
 this a disastrous strategy.

Well let's see if we can recap it into perspective so we're on the same Page. I'm trying to make a struct that on assignment will copy it's contents. On opAssign In both cases the mutable and const/immutable rvalue will copy it's contents. If it's a temporary (which is always returned as mutable) I want to take it over rather than copy the contents. The contents are likely referenced elsewhere already. Here's a stripped version of my struct, obviously with lots of missing unneeded stuff. struct X { ubyte[] buffer; //from temporary being returned. ref X opAssign(X rhs) { this.buffer = rhs.buffer; return this; } //copying from right side to left. ref X opAssign(ref X rhs) { if (buffer.length != rhs.length) { buffer.length = rhs.buffer.length; ptr = buffer.ptr; } buffer[] = rhs.buffer[]; return this; } }
May 04 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, May 05, 2012 01:18:13 Era Scarecrow wrote:
 On Friday, 4 May 2012 at 21:29:14 UTC, Steven Schveighoffer wrote:
 On Fri, 04 May 2012 17:26:02 -0400, Era Scarecrow
 
 On Friday, 4 May 2012 at 21:12:55 UTC, Steven Schveighoffer
 
 wrote:
 y[] = x2.y[];
 // as you did below

That may deal with the language requirements, but the ideal was to take over the temporary; If not the ref would copy the contents. I wonder if I will need to have 2 copies of each opAssign to satisfy everything.

OK, I see what you are trying to do. I'll have to think about it some more. I'm very concerned that you could potentially end up calling this function with an lvalue, which would make this a disastrous strategy.

Well let's see if we can recap it into perspective so we're on the same Page. I'm trying to make a struct that on assignment will copy it's contents. On opAssign In both cases the mutable and const/immutable rvalue will copy it's contents. If it's a temporary (which is always returned as mutable) I want to take it over rather than copy the contents. The contents are likely referenced elsewhere already.

As I understand it, you don't need to do _anything_ special to avoid having a temporary copied when passed to your function. Because it's a temporary, it should be moved into the function parameter, not copied. No postblit or opAssign will be executed. It's only when it's _not_ a temporary that a copy will be made. And even in _that_ case, it should be a move if that function call is the last place that the variable is used. So, I believe that you're trying to avoid copies that will never happen anyway. They would if you were dealing with C++ - particularly C++98 - but not in D (C++11 fixes the problem via move constructors). - Jonathan M Davis
May 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 5 May 2012 at 02:21:06 UTC, Jonathan M Davis wrote:
 As I understand it, you don't need to do _anything_ special to  
 avoid having a temporary copied when passed to your function. 
 Because it's a  temporary, it should be moved into the function 
 parameter, not copied. No  postblit or opAssign will be 
 executed. It's only when it's _not_ a  temporary that a copy 
 will be made. And even in _that_ case, it should be a move if  
 that function call is the last place that the variable is used.

That's what I originally thought too... But when I'm dealing with the temporary there's something broken. So if I only have only the ref. Error: function X.opAssign (ref X rhs) is not callable using argument types (X) so; struct X { ref X opAssign(ref X rhs); } X func(); struct Y { X x; this() { x = func(); } } Unless there's a default it drops back to, it is only seeing the one assign function.
 So, I believe that you're trying to avoid copies that will  
 never happen anyway. They would if you were dealing with C++ - 
 particularly  C++98 - but not in D (C++11 fixes the problem via 
 move constructors).

I'm not trying to avoid copying (Blocks are small so it's likely a tiny cost); I'm trying to keep arrays separate. Let's add to my example; I Hope I got it right based on the behavior I'm seeing. struct X { ubyte[] buffer; this(ubyte[] b) { buffer = b; } ref X opAssign(ref X rhs); } X func() { return X(new ubyte[5]); } void func2(){ ubyte[15] buff; X x1 = X(buff[0 .. 5]); X x2 = X(buff[5 .. 10]); const X x3 = X(buff[10 .. $]); x1 = x2; //should use ref, opAssign required to keep addresses separate assert(x1.buff !is x2.buff); //must pass, else value semantics I'm using breaks x1 = func(); //default copy can work, but fails due to opAssign(ref X) existing. Works with opAssign(X) x1 = x3; //should fail and needs a (const X) or (ref const X). //but if you change to (ref const X), x1 = x2; //then opAssign(X) runs, making arrays x1 & x2 point to the same place; not what i want. } In my thinking i make (ref const X) then mutable versions should work too; but somehow it's deciding to use (X) instead of (ref const X). I'm promising I won't change the data, not requiring the data can't be changed.
May 04 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, May 05, 2012 05:15:00 Era Scarecrow wrote:
 On Saturday, 5 May 2012 at 02:21:06 UTC, Jonathan M Davis wrote:
 As I understand it, you don't need to do _anything_ special to
 avoid having a temporary copied when passed to your function.
 Because it's a  temporary, it should be moved into the function
 parameter, not copied. No  postblit or opAssign will be
 executed. It's only when it's _not_ a  temporary that a copy
 will be made. And even in _that_ case, it should be a move if
 that function call is the last place that the variable is used.

That's what I originally thought too... But when I'm dealing with the temporary there's something broken. So if I only have only the ref. =20 Error: function X.opAssign (ref X rhs) is not callable using argument types (X) =20 so; struct X { ref X opAssign(ref X rhs); } =20 X func(); =20 struct Y { X x; this() { x =3D func(); } } =20 Unless there's a default it drops back to, it is only seeing the one assign function.

If you've declared an opAssign, I'd be very surprised if _any_ assignme= nt=20 worked which didn't work with the opAssign that you declared. Once you'= ve=20 declared an opAssign, you've taken over the assignment operator, and yo= u need=20 to define it for all of the types that you want it to work with.
 So, I believe that you're trying to avoid copies that will
 never happen anyway. They would if you were dealing with C++ -
 particularly  C++98 - but not in D (C++11 fixes the problem via
 move constructors).

I'm not trying to avoid copying (Blocks are small so it's likely a tiny cost); I'm trying to keep arrays separate. Let's add to my example; I Hope I got it right based on the behavior I'm seeing. =20 struct X { ubyte[] buffer; this(ubyte[] b) { buffer =3D b; } ref X opAssign(ref X rhs); } =20 X func() { return X(new ubyte[5]); } =20 void func2(){ ubyte[15] buff; X x1 =3D X(buff[0 .. 5]); X x2 =3D X(buff[5 .. 10]); const X x3 =3D X(buff[10 .. $]); =20 x1 =3D x2; //should use ref, opAssign required to keep addresses separate assert(x1.buff !is x2.buff); //must pass, else value semantics I'm using breaks =20 x1 =3D func(); //default copy can work, but fails due to opAssign(ref X) existing. Works with opAssign(X) =20 x1 =3D x3; //should fail and needs a (const X) or (ref const X). =20 //but if you change to (ref const X), x1 =3D x2; //then opAssign(X) runs, making arrays x1 & x2 point to the same place; not what i want. } =20 In my thinking i make (ref const X) then mutable versions should work too; but somehow it's deciding to use (X) instead of (ref const X). I'm promising I won't change the data, not requiring the data can't be changed.

According to http://dlang.org/function.html: --------- Func=C2=ADtions are over=C2=ADloaded based on how well the ar=C2=ADgu=C2= =ADments to a func=C2=ADtion=20 can match up with the pa=C2=ADra=C2=ADme=C2=ADters. The func=C2=ADtion = with the best match is se=C2=AD lected. The lev=C2=ADels of match=C2=ADing are:=20 1. no match 2. match with im=C2=ADplicit con=C2=ADver=C2=ADsions 3. match with con=C2=ADver=C2=ADsion to const 4. exact match --------- It picks opAssign(X) over opAssign(ref const X) with an argument of typ= e X,=20 because opAssign(X) is an exact match (#4) whereas opAssign(ref const X= )=20 requires a conversion to const (#3). - Jonathan M Davis
May 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 5 May 2012 at 03:32:06 UTC, Jonathan M Davis wrote:
 If you've declared an opAssign, I'd be very surprised if _any_  
 assignment worked which didn't work with the opAssign that you 
 declared.  Once you've declared an opAssign, you've taken over 
 the assignment  operator, and you need to define it for all of 
 the types that you want it to work with.

So define all four... gotcha...
 According to http://dlang.org/function.html:

 ---------
 Func­tions are over­loaded based on how well the  
 ar­gu­ments to a func­tion can match up with the 
 pa­ra­me­ters. The func­tion with the  best match is 
 se­lected. The lev­els of match­ing are:

 1. no match
 2. match with im­plicit con­ver­sions
 3. match with con­ver­sion to const
 4. exact match
 ---------

 It picks opAssign(X) over opAssign(ref const X) with an 
 argument of type X,because opAssign(X) is an exact match (#4) 
 whereas opAssign(ref const X)requires a conversion to const 
 (#3).

I guess there's one question left. Where does the struct live? If it closes at ending of the scope I believed that meant the stack, but then this would be illegal: ref X func() { return X(new ubyte[5]); //reference to local variable! } If it lives on the heap too rather than the stack, that'd good to know. I don't recall it specifying in TDPL, but it would be easy enough to assume it does (Coming from C).
May 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
 On Saturday, 5 May 2012 at 03:32:06 UTC, Jonathan M Davis wrote:
 ---------
 Func­tions are over­loaded based on how well the   
 ar­gu­ments to a func­tion can match up with the  
 pa­ra­me­ters. The func­tion with the  best match is  
 se­lected. The lev­els of match­ing are:

 1. no match
 2. match with im­plicit con­ver­sions
 3. match with con­ver­sion to const
 4. exact match
 ---------


Hmm maybe it should have a preference for Lvalue vs Rvalue... So... Walter or Andrei? 1. no match 2. match with im­plicit con­ver­sions (Lvalue required) 3. match with con­ver­sion to const (Lvalue required) 4. match with im­plicit con­ver­sions 5. match with con­ver­sion to const 6. exact match
May 04 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, May 05, 2012 05:50:26 Era Scarecrow wrote:
 On Saturday, 5 May 2012 at 03:32:06 UTC, Jonathan M Davis wrote:
 ---------
 Func=C2=ADtions are over=C2=ADloaded based on how well the
 ar=C2=ADgu=C2=ADments to a func=C2=ADtion can match up with the
 pa=C2=ADra=C2=ADme=C2=ADters. The func=C2=ADtion with the  best ma=



 se=C2=ADlected. The lev=C2=ADels of match=C2=ADing are:
=20
 1. no match
 2. match with im=C2=ADplicit con=C2=ADver=C2=ADsions
 3. match with con=C2=ADver=C2=ADsion to const
 4. exact match
 ---------


Hmm maybe it should have a preference for Lvalue vs Rvalue... So... Walter or Andrei? =20 1. no match 2. match with im=C2=ADplicit con=C2=ADver=C2=ADsions (Lvalue requir=

   3. match with con=C2=ADver=C2=ADsion to const (Lvalue required)
   4. match with im=C2=ADplicit con=C2=ADver=C2=ADsions
   5. match with con=C2=ADver=C2=ADsion to const
   6. exact match

This will likely be _very_ relevant to the proposed changes which make = ref and=20 const ref work with rvalues (the details on that are still being sorted= out, I=20 believe). However, I don't believe that either Walter or Andrei pays at= tention=20 to D.Learn, so if you want to bring it up for discussion, post about it= in the=20 main newsgroup (not to mention, your post is buried enough in this thre= ad that=20 many who _do_ pay attention to D.Learn wouldn't see it). - Jonathan M Davis
May 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 5 May 2012 at 04:15:21 UTC, Jonathan M Davis wrote:
 On Saturday, May 05, 2012 05:50:26 Era Scarecrow wrote:

 Hmm maybe it should have a preference for Lvalue vs Rvalue...
 So... Walter or Andrei?
 
   1. no match
   2. match with im­plicit con­ver­sions (Lvalue required)
   3. match with con­ver­sion to const (Lvalue required)
   4. match with im­plicit con­ver­sions
   5. match with con­ver­sion to const
   6. exact match

This will likely be _very_ relevant to the proposed changes which make ref and const ref work with rvalues (the details on that are still being sorted out, I believe). However, I don't believe that either Walter or Andrei pays attention to D.Learn, so if you want to bring it up for discussion, post about it in the main newsgroup (not to mention, your post is buried enough in this thread that many who _do_ pay attention to D.Learn wouldn't see it).

Your probably right.. Thanks, I'll repost this portion over there, I think I saw a topic already present that was this (or closely related) to this.
May 04 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, May 05, 2012 05:43:43 Era Scarecrow wrote:
 On Saturday, 5 May 2012 at 03:32:06 UTC, Jonathan M Davis wrote:
 If you've declared an opAssign, I'd be very surprised if _any_
 assignment worked which didn't work with the opAssign that you
 declared.  Once you've declared an opAssign, you've taken over
 the assignment  operator, and you need to define it for all of
 the types that you want it to work with.

So define all four... gotcha...

You need to define enough that you can pass any X to one of them. Gener= ally,=20 you probably just need opAssign(const X) and opAssign(const ref X), but= since=20 you're trying to have more particular semantics about whether resources= get=20 transferred or not, you may need all four.
 According to http://dlang.org/function.html:
=20
 ---------
 Func=C2=ADtions are over=C2=ADloaded based on how well the
 ar=C2=ADgu=C2=ADments to a func=C2=ADtion can match up with the
 pa=C2=ADra=C2=ADme=C2=ADters. The func=C2=ADtion with the  best mat=


 se=C2=ADlected. The lev=C2=ADels of match=C2=ADing are:
=20
 1. no match
 2. match with im=C2=ADplicit con=C2=ADver=C2=ADsions
 3. match with con=C2=ADver=C2=ADsion to const
 4. exact match
 ---------
=20
 It picks opAssign(X) over opAssign(ref const X) with an
 argument of type X,because opAssign(X) is an exact match (#4)
 whereas opAssign(ref const X)requires a conversion to const
 (#3).

I guess there's one question left. Where does the struct live? If it closes at ending of the scope I believed that meant the stack, but then this would be illegal: =20 ref X func() { return X(new ubyte[5]); //reference to local variable! } =20 If it lives on the heap too rather than the stack, that'd good to know. I don't recall it specifying in TDPL, but it would be easy enough to assume it does (Coming from C).

That code _should_ be illegal. It's as bad as X* func() { X x; return &x; } I think that there's an enhancement request about making it an error li= ke my=20 example is, but I can't find it at the moment. Temporaries definitely g= o on the=20 stack. - Jonathan M Davis
May 04 2012
prev sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 5 May 2012 at 04:15:21 UTC, Jonathan M Davis wrote:

 This will likely be _very_ relevant to the proposed changes  
 which make ref and const ref work with rvalues (the details on 
 that are still  being sorted out, I believe). However, I don't 
 believe that either Walter or Andrei  pays attention to 
 D.Learn, so if you want to bring it up for discussion, post  
 about it in the main newsgroup (not to mention, your post is 
 buried enough in  this thread that many who _do_ pay attention 
 to D.Learn wouldn't see it).

TDPL pg. 145 1) If there's one exact match, take that 2) Select a set of candidates that would accept the call if no other overloads are present. Here is where type deductions deduces types and if clauses are evaluated. 3) If the set has size zero, issue "no match" error. 4) If all functions are not in the same module, issue "attempt at cross-module overloading" error. 5) From that set eliminate all functions that are less specialized than any others in the set; that is, keep only the most specialized functions. 6) If the remaining set has size greater than one, issue "ambiguous call" error 7) The sole element of the set is the winner. void transmogrify(uint){} void transmogrify(long){} ... the first is more specialized so it is entitled to win. -- I get the feeling the 'ref' in our current discussion isn't being considered as how specialized it is (step 5). Maybe, but it's something to comment on. We'll see what Walter/Andrei have to say. my proposed Lvalue required steps are likely a better help than the rest of this though.
May 04 2012