www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Type inference for constructors

reply data pulverizer <data.pulverizer gmail.com> writes:
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);
}
```

On a slightly different note, I was doing some reading in 
std.typecons 
(https://github.com/dlang/phobos/blob/3754e92341a393331bd6b0bc9e70335d34e42016/s
d/typecons.d#L6838) on Github and wondered what `this` in the code below does:

```
  auto ref opIndex(this X, D...)(auto ref D i)               { 
return a[i]; }
```
Sep 17 2020
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
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
Sep 17 2020
parent data pulverizer <data.pulverizer gmail.com> writes:
On Friday, 18 September 2020 at 06:43:12 UTC, Simen Kjærås wrote:
 On Friday, 18 September 2020 at 05:43:56 UTC, data pulverizer

 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.
Thank you for the explanation and the reference.
 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
After reading your explanation and looking at the part of the manual you referred to, it looks as if this pattern could have a lot of utility, the `Addable` example in the manual looks like polymorphism with dynamic dispatch but retains static type a bit like Rust's (runtime) traits. Many thanks.
Sep 18 2020