www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Implicit conversion in constructor

reply "rcorre" <ryan rcorre.net> writes:
Is there any reason why implicit conversion from Foo to Thing is 
permitted in a regular method but not in a constructor?

Trying to figure out whether this is a bug or some sort of 
constructor-specific safety precaution.

struct Thing {
   Foo foo;
   alias foo this;
}

class Foo { }

class Bar {
   Thing thing;

   void fine() {
     thing = new Foo(); // ok
   }

   this() {
     thing = new Foo(); // nope!
   }
}
Jul 17 2015
next sibling parent reply "tcak" <1ltkrs+3wyh1ow7kzn1k sharklasers.com> writes:
On Saturday, 18 July 2015 at 02:23:26 UTC, rcorre wrote:
 Is there any reason why implicit conversion from Foo to Thing 
 is permitted in a regular method but not in a constructor?

 Trying to figure out whether this is a bug or some sort of 
 constructor-specific safety precaution.

 struct Thing {
   Foo foo;
   alias foo this;
 }

 class Foo { }

 class Bar {
   Thing thing;

   void fine() {
     thing = new Foo(); // ok
   }

   this() {
     thing = new Foo(); // nope!
   }
 }
I even am not sure how in the world it allows implicit conversion from class to struct in "fine" at all.
Jul 17 2015
next sibling parent "rcorre" <ryan rcorre.net> writes:
On Saturday, 18 July 2015 at 02:28:09 UTC, tcak wrote:
 I even am not sure how in the world it allows implicit 
 conversion from class to struct in "fine" at all.
The 'alias this' in the struct permits implicit conversion. I _think_ that is intended behavior, though I admit I'm not actually sure now. I've been taking it for granted for awhile...
Jul 17 2015
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Saturday, 18 July 2015 at 02:28:09 UTC, tcak wrote:
 I even am not sure how in the world it allows implicit 
 conversion from class to struct in "fine" at all.
Given: struct Foo { T x; alias x this; } Any time you do Foo foo; foo.something = whatever; // or foo = whatever; // or whatever = foo; It first tries that code directly. If that doesn't work, it then tries rewriting `foo` into `foo.x`: foo.x.something = whatever; foo.x = whatever; whatever = foo.x; And if that compiles, you're all set, that code gets generated. The OP's situation is just case #2 here. The compiler is taking the illegal `thing = new Foo;` and rewriting it into the legal `thing.foo = new Foo;` automatically via alias this.
Jul 17 2015
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Saturday, 18 July 2015 at 02:23:26 UTC, rcorre wrote:
 Is there any reason why implicit conversion from Foo to Thing 
 is permitted in a regular method but not in a constructor?
In the constructor, you are supposed to be constructing things, so the first "assignment" of structs is actually a constructor call. D does not support implicit construction (kinda sadly, but it doesn't). In the other methods, it calls opAssign instead, since the struct already exists. So this is the difference between: Thing thing = new Foo(); // in the ctor, this line in main wouldn't work either with the same error and thing = new Foo(); // in the other method, this line in main does work Try adding `void opAssign(T)(T t) { static assert(0); }` to your struct and recompile. You'll see it throws on the method. Then change that `opAssign` to `this`, so it becomes a constructor. Then you'll see it is called in the class constructor. Moreover, note that this only applies to the *first* assignment of the struct. If you copy/paste that line in the constructor again right under it, you'll see the compiler only throws the error once. The first one is a construction. The second one is a standard assignment again. Put those two lines in a runtime branch: `if(something) thing = new Foo(); else thing = new Foo();` and notice how the compiler throws two errors again. The first assignment in any branch of a constructor is a construction! The next one is an assignment. So the rule is slightly complex (and the implementation may be buggy, though it seems good to me now), but it is intentional. The reason for this goes beyond just that constructors are supposed to be constructing. It also is relevant for `immutable` members - these are allowed to be constructed, but not modified, so if the class constructor didn't treat those as constructions, it would be impossible to set them up with runtime data. And it is also important for ` disable this()` struct members, which must be constructed explicitly. If the first assignment in a ctor didn't count for that, you couldn't have them in a class at all.
Jul 17 2015