www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Is 'alias this' too buggy/limited to be usable?

reply Dennis <dkorpel gmail.com> writes:
I was trying to extend a type using alias this:
```
struct Number {
     double value;
     alias value this;

     //possible extra functionality
}

import std.math: cos, abs, pow;
void main() {
     auto num = Number(3);
	
     auto a = cos(num);
     auto b = abs(num);
     auto c = pow(2, num);
}
```
'a' works: cos has an overload of double and because of alias 
this the 'value' field of Number is passed.
'b' doesn't work: it resolves the generic type of abs to Number 
and tries to convert the returned double value to a 'Number', 
instead of resolving the type to double.
'c' doesn't work because the constraint isFloatingPoint!Number is 
not met.

Apparently the `alias this` is not considered during type 
inference of templates, while according to the Liskov 
substitution principle they should be accepted.

So I searched around and found a bunch of related (unfixed as of 
yet) issues:

https://issues.dlang.org/show_bug.cgi?id=5363 (const + alias this 
= wrong code)
https://issues.dlang.org/show_bug.cgi?id=14499 (segfault on alias 
this to self)
https://issues.dlang.org/show_bug.cgi?id=13189 (`alias this` is 
not transitive)
https://issues.dlang.org/show_bug.cgi?id=5380 (alias this is not 
considered with superclass lookup)

All have to do with alias this not being considered when you want 
to, or being considered when you don't want it to. 'alias this' 
sounds like a really cool feature to me, but all these 
limitations scare me off.

Is it usable at the moment? Any improvements planned? I'd like to 
hear some opionions or possible workarounds.
Jan 04 2018
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 4 January 2018 at 17:36:07 UTC, Dennis wrote:
 Is it usable at the moment? Any improvements planned? I'd like 
 to hear some opionions or possible workarounds.
As a workaround, you can roll out your own versions of those functions, just cast Number to double and then pass it to the std.math functions (locally imported). You may also want to cast back to Number, or something. One improvement would be to allow operator overloading for implicit casting, as in https://issues.dlang.org/show_bug.cgi?id=3968
Jan 04 2018
parent Dennis <dkorpel gmail.com> writes:
On Thursday, 4 January 2018 at 18:18:29 UTC, jmh530 wrote:
 As a workaround, you can roll out your own versions of those 
 functions, just cast Number to double and then pass it to the 
 std.math functions (locally imported). You may also want to 
 cast back to Number, or something.
Thanks, but the whole idea of using alias this is to prevent having to write special extra code. Take for example: ``` import std.math: isNaN; double parseDouble(string s) { ... } unittest { assert(parseDouble("123") == 123); assert(parseDouble("NaN").isNaN); } ``` Now what do you return when the string is malformed? You decide to change it to: ``` import std.typecons: Nullable; Nullable!double parseDouble(string s) { ``` Now Nullable has a `get` method and `alias get this`, so this line still compiles: assert(parseDouble("123") == 123); But this line gives an error: it can't instantiate the templated isNaN on type Nullable!double. assert(parseDouble("NaN").isNaN); The best way to fix it is to call get explicitly: assert(parseDouble("NaN").get.isNaN); I don't like this 'it mostly still works, but sometimes it breaks' property when you change 'double' to 'Nullable!double' which is supposed to extend it. My current solution is to just enforce you call .get all the time: the workaround is "don't use alias this"!
Jan 04 2018