www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template method and type resolution of return type

reply "matovitch" <camille.brugel laposte.net> writes:
Hi everyone !

Let's say I have a struct :

struct Test
{
	immutable (ubyte)[] data;

	T get(T)()
	{
		return *(cast(T*)(&(data[0])));
	}
}

This code will work :

import std.stdio;

void main()
{
	Test t;
	t.data = [152, 32, 64, 28, 95];
	float b = t.get!float;
	writefln("%s", b);
}

This won't compile :

import std.stdio;

void main()
{
	Test t;
	t.data = [152, 32, 64, 28, 95];
	float b = t.get;
	writefln("%s", b);
}

This neither:

import std.stdio;

void main()
{
	Test t;
	t.data = [152, 32, 64, 28, 95];
	float b = t.get!(typeof(b));
	writefln("%s", b);
}

And this will work:

import std.stdio;

void main()
{
	Test t;
	t.data = [152, 32, 64, 28, 95];
	float b;
         b = t.get!(typeof(b));
	writefln("%s", b);
}

Why can't dmd infere the type 'float' ? In fact this would allow 
a nicer syntax for the Json struct in vibe.d for example.
Apr 19 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
matovitch:

 struct Test
 {
 	immutable (ubyte)[] data;

 	T get(T)()
 	{
 		return *(cast(T*)(&(data[0])));
 	}
It's better to return const/immutable data. Otherwise the program gives undefined results. In alternative use mutable ubytes for data. Also &data[0] is probably data.ptr.
 This won't compile :

 import std.stdio;

 void main()
 {
 	Test t;
 	t.data = [152, 32, 64, 28, 95];
 	float b = t.get;
 	writefln("%s", b);
D doesn't perform inference on the return type.
 This neither:
...
 	Test t;
 	t.data = [152, 32, 64, 28, 95];
 	float b = t.get!(typeof(b));
 	writefln("%s", b);
I don't know. Perhaps b is not yet defined. This in theory could work.
 In fact this would allow a nicer syntax for the Json struct in 
 vibe.d for example.
I don't think in future D will behave differently on this code. Bye, bearophile
Apr 19 2014
parent reply "matovitch" <camille.brugel laposte.net> writes:
On Saturday, 19 April 2014 at 17:49:54 UTC, bearophile wrote:
 matovitch:

 struct Test
 {
 	immutable (ubyte)[] data;

 	T get(T)()
 	{
 		return *(cast(T*)(&(data[0])));
 	}
It's better to return const/immutable data. Otherwise the program gives undefined results. In alternative use mutable ubytes for data. Also &data[0] is probably data.ptr.
I did'nt know that one.
 This won't compile :

 import std.stdio;

 void main()
 {
 	Test t;
 	t.data = [152, 32, 64, 28, 95];
 	float b = t.get;
 	writefln("%s", b);
D doesn't perform inference on the return type.
I see. But why ? It's seems it exits a workaround overloading cast operators in c++ : http://programmaticallyspeaking.blogspot.se/2012/09/infer-return-type-for-templated.html However I think it would only work with opImplicitCast in D. The code given in vibe.d doc could became : void manipulateJson(Json j) { j = Json.emptyObject; j.name = "Example"; j.id = 1; // retrieving the values is done using get() assert(j["name"] == "Example"); assert(j["id"] == 1); // print out as JSON: {"name": "Example", "id": 1} writefln("JSON: %s", j.toString()); } ps : Thank you for all your great examples on Rosetta code (or the last one about the rubik's cube).
Apr 19 2014
next sibling parent "matovitch" <camille.brugel laposte.net> writes:
On Saturday, 19 April 2014 at 18:46:28 UTC, matovitch wrote:
 On Saturday, 19 April 2014 at 17:49:54 UTC, bearophile wrote:
 matovitch:
 I did'nt know that one.
This last sentence is misleading, let be clear : I know almost nothing when it comes to D...but I'm willing to learn ! ;-)
Apr 19 2014
prev sibling parent "matovitch" <camille.brugel laposte.net> writes:
On Saturday, 19 April 2014 at 18:46:28 UTC, matovitch wrote:
 On Saturday, 19 April 2014 at 17:49:54 UTC, bearophile wrote:
 matovitch:

 struct Test
 {
 	immutable (ubyte)[] data;

 	T get(T)()
 	{
 		return *(cast(T*)(&(data[0])));
 	}
It's better to return const/immutable data. Otherwise the program gives undefined results. In alternative use mutable ubytes for data. Also &data[0] is probably data.ptr.
I did'nt know that one.
 This won't compile :

 import std.stdio;

 void main()
 {
 	Test t;
 	t.data = [152, 32, 64, 28, 95];
 	float b = t.get;
 	writefln("%s", b);
D doesn't perform inference on the return type.
I see. But why ? It's seems it exits a workaround overloading cast operators in c++ : http://programmaticallyspeaking.blogspot.se/2012/09/infer-return-type-for-templated.html However I think it would only work with opImplicitCast in D. The code given in vibe.d doc could became : void manipulateJson(Json j) { j = Json.emptyObject; j.name = "Example"; j.id = 1; // retrieving the values is done using get() assert(j["name"] == "Example"); assert(j["id"] == 1); // print out as JSON: {"name": "Example", "id": 1} writefln("JSON: %s", j.toString()); } ps : Thank you for all your great examples on Rosetta code (or the last one about the rubik's cube).
Or even : void manipulateJson(Json j) { j = Json.emptyObject; j.name = "Example"; j.id = 1; assert(j.name == "Example"); assert(j.id == 1); // print out as JSON: {"name": "Example", "id": 1} writefln("JSON: %s", j.toString()); } Or at least this will work : void manipulateJson(Json j) { j = Json.emptyObject; j.name = "Example"; j.id = 1; string s = j.name; assert(s == "Example"); // print out as JSON: {"name": "Example", "id": 1} writefln("JSON: %s", j.toString()); } Ok I stop fooding.
Apr 19 2014
prev sibling parent reply Andrej Mitrovic via Digitalmars-d-learn writes:
On 4/19/14, matovitch via Digitalmars-d-learn
<digitalmars-d-learn puremagic.com> wrote:
 This won't compile :

 import std.stdio;

 void main()
 {
 	Test t;
 	t.data = [152, 32, 64, 28, 95];
 	float b = t.get;
 	writefln("%s", b);
 }
Because it's probably overkill. At some point it becomes too much magic. The following currently works but it might be considered an ambiguity with return type inference: ----- struct S { int get() { return 0; } T get(T)() { return T.init; } } void main() { S s; float x = s.get(); // which overload? (currently int get()) } -----
Apr 19 2014
parent reply David Held <dmd wyntrmute.com> writes:
On 4/19/2014 3:31 PM, Andrej Mitrovic via Digitalmars-d-learn wrote:
 [...]
 struct S
 {
      int get()  { return 0; }
      T get(T)() { return T.init; }
 }

 void main()
 {
      S s;
      float x = s.get();  // which overload? (currently int get())
 }
Isn't this just because concrete methods are better overload candidates than method templates? Dave
Apr 19 2014
parent reply "matovitch" <camille.brugel laposte.net> writes:
On Sunday, 20 April 2014 at 00:55:31 UTC, David Held wrote:
 On 4/19/2014 3:31 PM, Andrej Mitrovic via Digitalmars-d-learn 
 wrote:
 [...]
 struct S
 {
     int get()  { return 0; }
     T get(T)() { return T.init; }
 }

 void main()
 {
     S s;
     float x = s.get();  // which overload? (currently int 
 get())
 }
Isn't this just because concrete methods are better overload candidates than method templates? Dave
struct S { ubyte get() { return 0 ; } float get() { return 0.; } } void main() { S s; float x = s.get(); // does'nt know which overload, does'nt compile. }
Apr 20 2014
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 20 April 2014 at 07:52:08 UTC, matovitch wrote:
 struct S
 {
    ubyte get()  { return 0 ; }
    float get()  { return 0.; }
 }

 void main()
 {
    S s;
    float x = s.get();  // does'nt know which overload, does'nt 
 compile.
 }
What I do find interesting though, is that you are allowed to write the overload, whereas C++ would outright block you for ambiguity "at the source". This means that with proper meta magic eg `__traits(getOverloadSet, S, "get")`, you could, *manually* resolve the ambiguity yourself.
Apr 20 2014
parent "matovitch" <camille.brugel laposte.net> writes:
On Sunday, 20 April 2014 at 08:28:07 UTC, monarch_dodra wrote:
 On Sunday, 20 April 2014 at 07:52:08 UTC, matovitch wrote:
 struct S
 {
   ubyte get()  { return 0 ; }
   float get()  { return 0.; }
 }

 void main()
 {
   S s;
   float x = s.get();  // does'nt know which overload, does'nt 
 compile.
 }
What I do find interesting though, is that you are allowed to write the overload, whereas C++ would outright block you for ambiguity "at the source". This means that with proper meta magic eg `__traits(getOverloadSet, S, "get")`, you could, *manually* resolve the ambiguity yourself.
You mean getOverloads ? (yes it's interesting) How about this : class S { public { this() {} union other { SFloat u_float; SUbyte u_ubyte; } alias other this; } } struct SFloat { float data; alias data this; } struct SUbyte { ubyte data; alias data this; } void main() { S s; s.other.u_float.data = 0.5; //float x = s; } This gives : main.d(31): Error: need 'this' for 'data' of type 'float'
Apr 20 2014