Type inference for constructors

Simen Kjærås simen.kjaras at gmail.com
Fri Sep 18 06:43:12 UTC 2020


On Friday, 18 September 2020 at 05:43:56 UTC, data pulverizer 
wrote:
> I’d like to know if constructors of classes and structs can 
> have type inference. So far, I am using a separate function for 
> this purpose, for example:
>
> ```
> import std.stdio: writeln;
>
> struct Pair(T, U)
> {
>   T first;
>   U second;
>   this(T first, U second)
>   {
>     this.first = first;
>     this.second = second;
>   }
> }
>
> Pair!(T, U) pair(T, U)(T first, U second)
> {
>   return Pair!(T, U)(first, second);
> }
>
> void main()
> {
>   auto mp = pair("Michael", 32);//standard function inference 
> works
>   //auto m0 = Pair("Michael", 32); //I’d like to be able to do 
> this
>   writeln("pair: ", mp);
> }
> ```

That's issue 1997: https://issues.dlang.org/show_bug.cgi?id=1997

D's templates are turing complete, and there may be arbitrary 
amounts of logic obscuring the mapping between type template 
parameters and the specific argument types of the type's 
constructor, so the problem is intractable in the general case. 
E.g:

template Foo(T) {
     static if (is(T == int)) {
         struct Foo {
             this(int i) {}
             // int-specific code
         }
     } else {
         struct Foo {
             this(T t) {}
             // generic code
         }
     }
}

The above example is a simple one, yet mapping from a constructor 
call to the correct template parameters is difficult.


> [I] wondered what `this` in the code below does:
>
> ```
>  auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; }
> ```

That's a template this parameter 
(https://dlang.org/spec/template.html#template_this_parameter). 
It takes on the type of 'this' at the point of instantiation. 
That is:

struct S {
     void fun(this T)() { pragma(msg, T); }
}

unittest {
     S s;
     const S sc;
     immutable S si;
     shared S ss;
     s.fun();  // prints S
     sc.fun(); // prints const(S)
     si.fun(); // prints immutable(S)
     ss.fun(); // prints shared(S)
}

This allows the return type to have the same constness as 'this', 
or for specific code to be executed when operating on e.g. a 
non-mutable instance, where lazy initialization couldn't be 
performed. In many cases, this is better served by using inout:

https://dlang.org/spec/function.html#inout-functions

--
   Simen


More information about the Digitalmars-d-learn mailing list