Thread overview
alias this constructor
Mar 25, 2018
Dave Jones
Mar 25, 2018
Jonathan M Davis
Mar 25, 2018
Shachar Shemesh
Mar 25, 2018
Jonathan M Davis
Mar 25, 2018
Adam D. Ruppe
March 25, 2018
struct Foo
{
    int x;
    alias x this;
}

Foo f = 12; // error

Foo foo;
f = 12;     // this is OK

any reason why the first cant be allowed?
March 24, 2018
On Sunday, March 25, 2018 00:47:20 Dave Jones via Digitalmars-d wrote:
> struct Foo
> {
>      int x;
>      alias x this;
> }
>
> Foo f = 12; // error
>
> Foo foo;
> f = 12;     // this is OK
>
> any reason why the first cant be allowed?

Because it was deemed to cause too many problems. C++ code can have quite a few problems related to all of the implicit conversions it allows with stuff like constructing objects. Walter decided that D would be better off if it did not allow such conversions, and as such, D is much pickier about implicit conversions in general.

Occasionally, the restrictions are annoying, but they also prevent bugs. I have no idea whether Walter could be convinced at this point to allow some sort of implicit construction in D or not.

Personally, I tend to think that we'd be better off if we didn't have alias this at all, because it tends to cause problems in anything outside of simple use cases (especially with generic code - implicit conversions in generic code are almost always a terrible idea). Sometimes, it's useful, but it's often just a recipe for subtle bugs. But at least the fact that D only allows you to implicitly convert in one direction reduces the problem.

- Jonathan M Davis

March 25, 2018
On Sunday, 25 March 2018 at 00:47:20 UTC, Dave Jones wrote:
> struct Foo
> {
>     int x;
>     alias x this;
> }
>
> Foo f = 12; // error

You just need to define a constructor that takes an int. alias this is all about taking an existing object and substituting a member for it - emphasis on *existing* object, so it needs to already be constructed.

But you can construct from other types

struct Foo {
   int x;
   this(int x) { this.x = x; }
}

Foo f = 12; // allowed, calls that constructor

> Foo foo;
> f = 12;     // this is OK

Important to note that foo already exists here and is NOT reconstructed - the compiler just rewrites that into `f.x = 12;`, doing a member assignment.
March 25, 2018
On 25/03/18 04:51, Jonathan M Davis wrote:
> On Sunday, March 25, 2018 00:47:20 Dave Jones via Digitalmars-d wrote:
>> struct Foo
>> {
>>       int x;
>>       alias x this;
>> }
>>
>> Foo f = 12; // error
>>
>> Foo foo;
>> f = 12;     // this is OK
>>
>> any reason why the first cant be allowed?
> 
> Because it was deemed to cause too many problems. C++ code can have quite a
> few problems related to all of the implicit conversions it allows with stuff
> like constructing objects. Walter decided that D would be better off if it
> did not allow such conversions, and as such, D is much pickier about
> implicit conversions in general.

That's a good reason to disallow assignment from int to Foo. I see zero sense in allowing assignment and disallowing construction.

*****

Technically, I understand the mechanisms at play here. During construction, this is a Foo object, and it has no construction from int. During assignment, we are allowed to convert a Foo lvalue to a Foo.x (int) lvalue, and that gets assigned.

Despite understanding the mechanics, I find the end result surprising and unexpected. D makes it damn easy to implicitly expose an inner member, and much more difficult to actually do this safely (you have to create a property and then alias this that property).

If I'd be building C++ today, I'd replace the "explicit" keyword with "implicit" (i.e. - still allow single var constructors to become implicit conversion ops, but make that transformation an opt-in rather than an opt-out feature). I think that would have been a much better approach than what D took.

Shachar
March 24, 2018
On Sunday, March 25, 2018 06:24:35 Shachar Shemesh via Digitalmars-d wrote:
> On 25/03/18 04:51, Jonathan M Davis wrote:
> > On Sunday, March 25, 2018 00:47:20 Dave Jones via Digitalmars-d wrote:
> >> struct Foo
> >> {
> >>
> >>       int x;
> >>       alias x this;
> >>
> >> }
> >>
> >> Foo f = 12; // error
> >>
> >> Foo foo;
> >> f = 12;     // this is OK
> >>
> >> any reason why the first cant be allowed?
> >
> > Because it was deemed to cause too many problems. C++ code can have quite a few problems related to all of the implicit conversions it allows with stuff like constructing objects. Walter decided that D would be better off if it did not allow such conversions, and as such, D is much pickier about implicit conversions in general.
>
> That's a good reason to disallow assignment from int to Foo. I see zero sense in allowing assignment and disallowing construction.
>
> *****
>
> Technically, I understand the mechanisms at play here. During construction, this is a Foo object, and it has no construction from int. During assignment, we are allowed to convert a Foo lvalue to a Foo.x (int) lvalue, and that gets assigned.
>
> Despite understanding the mechanics, I find the end result surprising and unexpected. D makes it damn easy to implicitly expose an inner member, and much more difficult to actually do this safely (you have to create a property and then alias this that property).

Having something like opImplicitCast would arguably have been better than alias this.

> If I'd be building C++ today, I'd replace the "explicit" keyword with "implicit" (i.e. - still allow single var constructors to become implicit conversion ops, but make that transformation an opt-in rather than an opt-out feature). I think that would have been a much better approach than what D took.

That would be a significant improvement for C++, though over time, I've increasingly become of the opinion that adding implicit conversions to user-defined types is more trouble than it's worth. There are certainly times when it's useful, but it causes enough problems that I'm not at all convinced that it's ultimately a feature worth having. And with the route that D went, implicit conversions are arguably crippled anyway. So, we have a partial solution that isn't really enough to cleanly use implicit conversions when it might be appropriate, but what we have is still enough to cause problems.

- Jonathan M Davis