www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Implicit string lit conversion to wstring/dstring

reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
Code:
	import std.stdio;
	version(explicit) {
		void func(dstring s) {
			dstring t = s;
			writeln(t);
		}
	} else {
		void func(S)(S s) {
			dstring t = s;	// line 10
			writeln(t);
		}
	}
	void main() {
		func("abc");
	}

If version=explicit is set, the program compiles fine. But if not, then
the compiler complains:

	test.d:10: Error: cannot implicitly convert expression (s) of type string to
immutable(dchar)[]

What do I need to do to make the template version of func trigger
implicit conversion of the string lit to dstring? What I'm trying to do
is to templatize dstring as well, but still benefit from the
string->dstring conversion when instantiated with dstring.

(Ditto with implicit conversion to wstring.)


T

-- 
He who laughs last thinks slowest.
Mar 14 2012
next sibling parent reply =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= <xtzgzorex gmail.com> writes:
On 14-03-2012 19:00, H. S. Teoh wrote:
 Code:
 	import std.stdio;
 	version(explicit) {
 		void func(dstring s) {
 			dstring t = s;
 			writeln(t);
 		}
 	} else {
 		void func(S)(S s) {
 			dstring t = s;	// line 10
 			writeln(t);
 		}
 	}
 	void main() {
 		func("abc");
 	}

 If version=explicit is set, the program compiles fine. But if not, then
 the compiler complains:

 	test.d:10: Error: cannot implicitly convert expression (s) of type string to
immutable(dchar)[]

 What do I need to do to make the template version of func trigger
 implicit conversion of the string lit to dstring? What I'm trying to do
 is to templatize dstring as well, but still benefit from the
 string->dstring conversion when instantiated with dstring.

 (Ditto with implicit conversion to wstring.)


 T
I doubt that such an implicit conversion even exists. You have to prefix the string appropriately, e.g.: string s = "foo"; wstring w = w"bar"; dstring d = d"baz"; -- - Alex
Mar 14 2012
next sibling parent =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= <xtzgzorex gmail.com> writes:
On 14-03-2012 19:00, Alex Rnne Petersen wrote:
 On 14-03-2012 19:00, H. S. Teoh wrote:
 Code:
 import std.stdio;
 version(explicit) {
 void func(dstring s) {
 dstring t = s;
 writeln(t);
 }
 } else {
 void func(S)(S s) {
 dstring t = s; // line 10
 writeln(t);
 }
 }
 void main() {
 func("abc");
 }

 If version=explicit is set, the program compiles fine. But if not, then
 the compiler complains:

 test.d:10: Error: cannot implicitly convert expression (s) of type
 string to immutable(dchar)[]

 What do I need to do to make the template version of func trigger
 implicit conversion of the string lit to dstring? What I'm trying to do
 is to templatize dstring as well, but still benefit from the
 string->dstring conversion when instantiated with dstring.

 (Ditto with implicit conversion to wstring.)


 T
I doubt that such an implicit conversion even exists. You have to prefix the string appropriately, e.g.: string s = "foo"; wstring w = w"bar"; dstring d = d"baz";
Sorry, I lied. Like this: string s = "foo"c; (the c is optional) wstring w = "bar"w; dstring d = "baz"d; See: http://dlang.org/lex.html -- - Alex
Mar 14 2012
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Mar 14, 2012 at 07:00:35PM +0100, Alex Rønne Petersen wrote:
 On 14-03-2012 19:00, H. S. Teoh wrote:
Code:
	import std.stdio;
	version(explicit) {
		void func(dstring s) {
			dstring t = s;
			writeln(t);
		}
	} else {
		void func(S)(S s) {
			dstring t = s;	// line 10
			writeln(t);
		}
	}
	void main() {
		func("abc");
	}

If version=explicit is set, the program compiles fine. But if not, then
the compiler complains:

	test.d:10: Error: cannot implicitly convert expression (s) of type string to
immutable(dchar)[]

What do I need to do to make the template version of func trigger
implicit conversion of the string lit to dstring? What I'm trying to do
is to templatize dstring as well, but still benefit from the
string->dstring conversion when instantiated with dstring.

(Ditto with implicit conversion to wstring.)


T
I doubt that such an implicit conversion even exists. You have to prefix the string appropriately, e.g.:
OK, maybe implicit conversion is the wrong word. The compiler is obviously interpreting func("abc") as func("abc"d) when we declare func(dstring). But when we declare func(S)(S), the compiler deduces "abc" as string and sets S=string. What I want is to force the compiler to deduce S=dstring when I declare func(S)(S) and call it as func("abc"). T -- Дерево держится корнями, а человек - друзьями.
Mar 14 2012
next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 14-03-2012 19:16, H. S. Teoh wrote:
 On Wed, Mar 14, 2012 at 07:00:35PM +0100, Alex Rønne Petersen wrote:
 On 14-03-2012 19:00, H. S. Teoh wrote:
 Code:
 	import std.stdio;
 	version(explicit) {
 		void func(dstring s) {
 			dstring t = s;
 			writeln(t);
 		}
 	} else {
 		void func(S)(S s) {
 			dstring t = s;	// line 10
 			writeln(t);
 		}
 	}
 	void main() {
 		func("abc");
 	}

 If version=explicit is set, the program compiles fine. But if not, then
 the compiler complains:

 	test.d:10: Error: cannot implicitly convert expression (s) of type string to
immutable(dchar)[]

 What do I need to do to make the template version of func trigger
 implicit conversion of the string lit to dstring? What I'm trying to do
 is to templatize dstring as well, but still benefit from the
 string->dstring conversion when instantiated with dstring.

 (Ditto with implicit conversion to wstring.)


 T
I doubt that such an implicit conversion even exists. You have to prefix the string appropriately, e.g.:
OK, maybe implicit conversion is the wrong word. The compiler is obviously interpreting func("abc") as func("abc"d) when we declare func(dstring). But when we declare func(S)(S), the compiler deduces "abc" as string and sets S=string. What I want is to force the compiler to deduce S=dstring when I declare func(S)(S) and call it as func("abc"). T
But then... why not just make it take a dstring? Maybe I'm not following your intent here... Anyway, what Phobos functions tend to do is to set S = string by default and otherwise force people to either pass the string type *or* use the string suffices. -- - Alex
Mar 14 2012
parent "Nick Sabalausky" <a a.a> writes:
"Alex Rnne Petersen" <xtzgzorex gmail.com> wrote in message 
news:jjqn9f$1iht$1 digitalmars.com...
 But then... why not just make it take a dstring? Maybe I'm not following 
 your intent here...
Probably because then this becomes an error: string s = "abc"; func(s); It's an interesting problem. I'm not aware of a solution. I suppose you'd just have to make it take only dstring and then expect string/wstring vars to be handled by the caller like "func(to!dstring(s))"
Mar 14 2012
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 14 Mar 2012 14:16:11 -0400, H. S. Teoh <hsteoh quickfur.ath.cx>  
wrote:

 What I want is to force the compiler to deduce S=dstring when I declare
 func(S)(S) and call it as func("abc").
http://d.puremagic.com/issues/show_bug.cgi?id=4998 Please vote or contribute your thoughts. -Steve
Mar 14 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Mar 14, 2012 at 02:44:40PM -0400, Steven Schveighoffer wrote:
 On Wed, 14 Mar 2012 14:16:11 -0400, H. S. Teoh
 <hsteoh quickfur.ath.cx> wrote:
 
What I want is to force the compiler to deduce S=dstring when I
declare func(S)(S) and call it as func("abc").
http://d.puremagic.com/issues/show_bug.cgi?id=4998 Please vote or contribute your thoughts.
[...] Ahhh, thanks for pointing this out. That is exactly the problem I'm struggling with. I guess the motivation of my original question wasn't clear. I should say that I ran into this problem in the context of my AA implementation. I've successfully implemented Andrei's suggestion: int[wstring] will now accept wchar[], const(wchar)[], in addition to wstring in .get, .opIndex, etc.. It will implicitly call wchar[].idup when it needs to create a new hash entry. (Ditto with dstring, and with any immutable array key type.) To implement this change, opIndexAssign now looks like this: struct AssociativeArray(Key,Value) { ... void opIndexAssign(K)(in Value v, in K key) if (isCompatWithKey!K) { ... } } The template isCompatWithKey basically checks if K can be implicitly converted to Key, or has an .idup method that returns something that can be implicitly converted to Key. However, this change broke this code: AssociativeArray!(wstring,int) aa; aa["abc"] = 123; // error: compiler deduces K as string, // so isCompatWithKey!K fails: string // can't implicitly convert to wstring Whereas before, when opIndexAssign looked like this: void opIndexAssign(in Value v, in Key key) { ... } everything worked, because the compiler deduces the type of "abc" as wstring since Key==wstring. Now you have to write: aa["abc"w] = 123; which isn't the end of the world, I suppose, but it's not very nice, and also breaks existing code that depended on the compiler automatically deducing that typeof("abc")==wstring. T -- There are three kinds of people in the world: those who can count, and those who can't.
Mar 14 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/12 2:01 PM, H. S. Teoh wrote:
 However, this change broke this code:

 	AssociativeArray!(wstring,int) aa;
 	aa["abc"] = 123;	// error: compiler deduces K as string,
 				// so isCompatWithKey!K fails: string
 				// can't implicitly convert to wstring

 Whereas before, when opIndexAssign looked like this:

 		void opIndexAssign(in Value v, in Key key)
 		{
 			...
 		}

 everything worked, because the compiler deduces the type of "abc" as
 wstring since Key==wstring.
Aha! This is one of those cases in which built-in magic smells of putrid beef soup. I think it's possible to still make this work by beefing up the template constraints such that the working signature is selected for strings. Andrei
Mar 14 2012
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Mar 14, 2012 at 02:07:04PM -0500, Andrei Alexandrescu wrote:
 On 3/14/12 2:01 PM, H. S. Teoh wrote:
However, this change broke this code:

	AssociativeArray!(wstring,int) aa;
	aa["abc"] = 123;	// error: compiler deduces K as string,
				// so isCompatWithKey!K fails: string
				// can't implicitly convert to wstring

Whereas before, when opIndexAssign looked like this:

		void opIndexAssign(in Value v, in Key key)
		{
			...
		}

everything worked, because the compiler deduces the type of "abc" as
wstring since Key==wstring.
Aha! This is one of those cases in which built-in magic smells of putrid beef soup.
+1.
 I think it's possible to still make this work by beefing up the
 template constraints such that the working signature is selected for
 strings.
[...] I tried the following, but it still doesn't work properly: void opIndexAssign()(in Value v, in Key key) { __opIndexAssignImpl(v, key); } void opIndexAssign(K)(in Value v, in K key) if (!is(K==Key) && isCompatWithKey!K) { __opIndexAssignImpl(v, key); } This causes this case to fail: AssociativeArray!(wstring,int) aa; wchar[] key = "abc"w.dup; aa[key] = 123; // Error: template newAA.AA!(immutable(wchar)[],int).AssociativeArray.opIndexAssign() cannot deduce template function from argument types !()(int,wchar[]) I don't understand what's happening here. The condition "!is(K==Key)" is necessary because otherwise the compiler complains that more than one template matches the given call, but for some weird reason both templates vanish from consideration when the condition is put in. T -- It is the quality rather than the quantity that matters. -- Lucius Annaeus Seneca
Mar 14 2012
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/14/12 2:34 PM, H. S. Teoh wrote:
 I tried the following, but it still doesn't work properly:

 	void opIndexAssign()(in Value v, in Key key)
 	{
 		__opIndexAssignImpl(v, key);
 	}

 	void opIndexAssign(K)(in Value v, in K key)
 		if (!is(K==Key)&&  isCompatWithKey!K)
 	{
 		__opIndexAssignImpl(v, key);
 	}
Try special casing for the exact types (string, char[] etc), get that working, and then generalize from there. Andrei
Mar 14 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2012 08:34 PM, H. S. Teoh wrote:
 On Wed, Mar 14, 2012 at 02:07:04PM -0500, Andrei Alexandrescu wrote:
 On 3/14/12 2:01 PM, H. S. Teoh wrote:
 However, this change broke this code:

 	AssociativeArray!(wstring,int) aa;
 	aa["abc"] = 123;	// error: compiler deduces K as string,
 				// so isCompatWithKey!K fails: string
 				// can't implicitly convert to wstring

 Whereas before, when opIndexAssign looked like this:

 		void opIndexAssign(in Value v, in Key key)
 		{
 			...
 		}

 everything worked, because the compiler deduces the type of "abc" as
 wstring since Key==wstring.
Aha! This is one of those cases in which built-in magic smells of putrid beef soup.
+1.
 I think it's possible to still make this work by beefing up the
 template constraints such that the working signature is selected for
 strings.
[...] I tried the following, but it still doesn't work properly: void opIndexAssign()(in Value v, in Key key) { __opIndexAssignImpl(v, key); } void opIndexAssign(K)(in Value v, in K key) if (!is(K==Key)&& isCompatWithKey!K) { __opIndexAssignImpl(v, key); } This causes this case to fail: AssociativeArray!(wstring,int) aa; wchar[] key = "abc"w.dup; aa[key] = 123; // Error: template newAA.AA!(immutable(wchar)[],int).AssociativeArray.opIndexAssign() cannot deduce template function from argument types !()(int,wchar[]) I don't understand what's happening here. The condition "!is(K==Key)" is necessary because otherwise the compiler complains that more than one template matches the given call, but for some weird reason both templates vanish from consideration when the condition is put in. T
Use this for now: void opIndexAssign(K)(in int v, scope K key) if (!is(K==Key) && isCompatWithKey!K) {...} 'in K key'/const(K) key will only IFTI-match a const type. I don't think that is sensible at all, you may want to file a bug report.
Mar 14 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2012 09:18 PM, Timon Gehr wrote:
 Use this for now:
 void opIndexAssign(K)(in int v, scope K key)
 if (!is(K==Key) && isCompatWithKey!K)
 {...}
oops. I meant: void opIndexAssign(K)(in Value v, scope K key) if (!is(K==Key) && isCompatWithKey!K) {...}
 'in K key'/const(K) key will only IFTI-match a const type. I don't think
 that is sensible at all, you may want to file a bug report.
Mar 14 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Mar 14, 2012 at 02:07:04PM -0500, Andrei Alexandrescu wrote:
 On 3/14/12 2:01 PM, H. S. Teoh wrote:
However, this change broke this code:

	AssociativeArray!(wstring,int) aa;
	aa["abc"] = 123;	// error: compiler deduces K as string,
				// so isCompatWithKey!K fails: string
				// can't implicitly convert to wstring

Whereas before, when opIndexAssign looked like this:

		void opIndexAssign(in Value v, in Key key)
		{
			...
		}

everything worked, because the compiler deduces the type of "abc" as
wstring since Key==wstring.
Aha! This is one of those cases in which built-in magic smells of putrid beef soup. I think it's possible to still make this work by beefing up the template constraints such that the working signature is selected for strings.
[...] Also, IMHO, this needs to work for array literals in general, not just strings. For example, this should work: int[ubyte[]] aa; aa[[1,2,3]] = 123; The [1,2,3] should be deduced as ubyte[] instead of int[]. T -- Ignorance is bliss... but only until you suffer the consequences!
Mar 14 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Mar 14, 2012 at 02:07:04PM -0500, Andrei Alexandrescu wrote:
[...]
 Aha! This is one of those cases in which built-in magic smells of
 putrid beef soup.
[...] It gets worse than we first thought: void f1(dstring x) { dstring y = x; } void f2()(dstring x) { dstring y = x; } void f2(U)(U x) if (!is(U==string)) { dstring y = x; } void f3(byte[] x) { byte[] y = x; } void f4()(byte[] x) { byte[] y = x; } void f4(U)(U x) if (!is(U==int[])) { byte[] y = x; } void main() { f1("abc"); // OK: "abc" deduced as dstring f2("abc"); // OK: "abc" defaults to string, but f2(U)(U) // declines U==string, so f2()(dstring) is // chosen, and "abc" is deduced as dstring f3([1,2,3]); // OK: [1,2,3] deduced as byte[] f4([1,2,3]); // Error: template test2.f4() does not match any function template declaration // Error: template test2.f4() cannot deduce template function from argument types !()(int[]) } WAT?? So "abc" will match f()(dstring x), but [1,2,3] doesn't match f()(byte[] b)? Upon further investigation: void f5(dstring s) {} void f6()(dstring s) {} void f7(byte[] s) {} void f8()(byte[] s) {} void main() { f5("abc"); // OK f6("abc"); // OK (!) f7([1,2,3]); // OK f8([1,2,3]); // cannot deduce template function from argument types !()(int[]) } WAT? T -- "You know, maybe we don't *need* enemies." "Yeah, best friends are about all I can take." -- Calvin & Hobbes
Mar 17 2012
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
OK, perhaps the previous subject line of the previous post deterred
people from actually reading the contents. :-(

Basically, I'm trying to address Andrei's request that this should work
with my AA implementation:

	int[dstring] aa;
	aa["abc"] = 1;	// "abc" implicitly deduced as dstring

Currently, for maximum usability, the code allows any type to be
supplied for the key, as long as it can be implicitly converted to the
AA's key type. This is implemented as:

	opIndexAssign(K)(Value v, K key) if (implicitConvertible!K) {}

However, this causes a problem with dstring and wstring, because a
literal like "abc" defaults to string rather than dstring or wstring, so
when the compiler tries to find a match for opIndexAssign, it sees that
string can't implicitly convert to dstring, so it produces an error.

This doesn't happen if opIndexAssign was simply:

	opIndexAssign(Value v, Key key) {}

where Key==dstring, because then the compiler implicitly deduces "abc"
as a dstring.

In order to fix this, one fix is:

	// Key==dstring
	opIndexAssign()(Value v, Key key) { __opIndexAssignImpl(v,key); }
	opIndexAssign(K)(Value v, K key)
		if (implicitConvertible!K && !is(K==string))
	{
		__opIndexAssignImpl(v,key);
	}

How this works is, when the compiler sees "abc", it first tries to match
opIndexAssign(K=string)(Value,K), defaulting "abc" to string, but the
signature constraint declines, so the compiler tries
opIndexAssign()(Value v, dstring key), which matches with "abc" as
dstring.

This works for string, wstring, and dstring.

However, the compiler seems to handle numerical literals like [1,2,3]
differently. For example:

	void func(byte[] b) {}
	func([1,2,3]);		// OK

However:

	void func()(byte[] b) {}
	func([1,2,3]);		// Does not match template

Because of this, it's basically impossible to make literals like [1,2,3]
work with AA's with key type byte[], short[], etc., because [1,2,3] will
never match byte[] in a templated function, and int[] cannot be
implicitly converted to byte[]. So it is impossible to replicate the
implicit conversion in code like:

	byte[] b;
	b = [1,2,3];

without compiler changes. :-(


--T
Mar 18 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/19/2012 04:40 AM, H. S. Teoh wrote:
 OK, perhaps the previous subject line of the previous post deterred
 people from actually reading the contents. :-(

 Basically, I'm trying to address Andrei's request that this should work
 with my AA implementation:

 	int[dstring] aa;
 	aa["abc"] = 1;	// "abc" implicitly deduced as dstring

 Currently, for maximum usability, the code allows any type to be
 supplied for the key, as long as it can be implicitly converted to the
 AA's key type. This is implemented as:

 	opIndexAssign(K)(Value v, K key) if (implicitConvertible!K) {}

 However, this causes a problem with dstring and wstring, because a
 literal like "abc" defaults to string rather than dstring or wstring, so
 when the compiler tries to find a match for opIndexAssign, it sees that
 string can't implicitly convert to dstring, so it produces an error.

 This doesn't happen if opIndexAssign was simply:

 	opIndexAssign(Value v, Key key) {}

 where Key==dstring, because then the compiler implicitly deduces "abc"
 as a dstring.

 In order to fix this, one fix is:

 	// Key==dstring
 	opIndexAssign()(Value v, Key key) { __opIndexAssignImpl(v,key); }
 	opIndexAssign(K)(Value v, K key)
 		if (implicitConvertible!K&&  !is(K==string))
 	{
 		__opIndexAssignImpl(v,key);
 	}

 How this works is, when the compiler sees "abc", it first tries to match
 opIndexAssign(K=string)(Value,K), defaulting "abc" to string, but the
 signature constraint declines, so the compiler tries
 opIndexAssign()(Value v, dstring key), which matches with "abc" as
 dstring.

 This works for string, wstring, and dstring.

 However, the compiler seems to handle numerical literals like [1,2,3]
 differently. For example:

 	void func(byte[] b) {}
 	func([1,2,3]);		// OK

 However:

 	void func()(byte[] b) {}
 	func([1,2,3]);		// Does not match template

 Because of this, it's basically impossible to make literals like [1,2,3]
 work with AA's with key type byte[], short[], etc., because [1,2,3] will
 never match byte[] in a templated function, and int[] cannot be
 implicitly converted to byte[]. So it is impossible to replicate the
 implicit conversion in code like:

 	byte[] b;
 	b = [1,2,3];

 without compiler changes. :-(


 --T
This is a bug I have reported some time ago. Vote here: http://d.puremagic.com/issues/show_bug.cgi?id=7366
Mar 19 2012
prev sibling parent James Miller <james aatch.net> writes:
On 19 March 2012 16:40, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:
 OK, perhaps the previous subject line of the previous post deterred
 people from actually reading the contents. :-(

 Basically, I'm trying to address Andrei's request that this should work
 with my AA implementation:

 =C2=A0 =C2=A0 =C2=A0 =C2=A0int[dstring] aa;
 =C2=A0 =C2=A0 =C2=A0 =C2=A0aa["abc"] =3D 1; =C2=A0// "abc" implicitly ded=
uced as dstring
 Currently, for maximum usability, the code allows any type to be
 supplied for the key, as long as it can be implicitly converted to the
 AA's key type. This is implemented as:

 =C2=A0 =C2=A0 =C2=A0 =C2=A0opIndexAssign(K)(Value v, K key) if (implicitC=
onvertible!K) {}
 However, this causes a problem with dstring and wstring, because a
 literal like "abc" defaults to string rather than dstring or wstring, so
 when the compiler tries to find a match for opIndexAssign, it sees that
 string can't implicitly convert to dstring, so it produces an error.

 This doesn't happen if opIndexAssign was simply:

 =C2=A0 =C2=A0 =C2=A0 =C2=A0opIndexAssign(Value v, Key key) {}

 where Key=3D=3Ddstring, because then the compiler implicitly deduces "abc=
"
 as a dstring.

 In order to fix this, one fix is:

 =C2=A0 =C2=A0 =C2=A0 =C2=A0// Key=3D=3Ddstring
 =C2=A0 =C2=A0 =C2=A0 =C2=A0opIndexAssign()(Value v, Key key) { __opIndexA=
ssignImpl(v,key); }
 =C2=A0 =C2=A0 =C2=A0 =C2=A0opIndexAssign(K)(Value v, K key)
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (implicitConver=
tible!K && !is(K=3D=3Dstring))
 =C2=A0 =C2=A0 =C2=A0 =C2=A0{
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0__opIndexAssignImp=
l(v,key);
 =C2=A0 =C2=A0 =C2=A0 =C2=A0}

 How this works is, when the compiler sees "abc", it first tries to match
 opIndexAssign(K=3Dstring)(Value,K), defaulting "abc" to string, but the
 signature constraint declines, so the compiler tries
 opIndexAssign()(Value v, dstring key), which matches with "abc" as
 dstring.

 This works for string, wstring, and dstring.

 However, the compiler seems to handle numerical literals like [1,2,3]
 differently. For example:

 =C2=A0 =C2=A0 =C2=A0 =C2=A0void func(byte[] b) {}
 =C2=A0 =C2=A0 =C2=A0 =C2=A0func([1,2,3]); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0// OK
 However:

 =C2=A0 =C2=A0 =C2=A0 =C2=A0void func()(byte[] b) {}
 =C2=A0 =C2=A0 =C2=A0 =C2=A0func([1,2,3]); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0// Does not match template
 Because of this, it's basically impossible to make literals like [1,2,3]
 work with AA's with key type byte[], short[], etc., because [1,2,3] will
 never match byte[] in a templated function, and int[] cannot be
 implicitly converted to byte[]. So it is impossible to replicate the
 implicit conversion in code like:

 =C2=A0 =C2=A0 =C2=A0 =C2=A0byte[] b;
 =C2=A0 =C2=A0 =C2=A0 =C2=A0b =3D [1,2,3];

 without compiler changes. :-(


 --T
This sounds like a major bug. At compile time, the compiler should have more than enough information to do the implicit conversion for templates. I haven't looked much at the compiler code, but I assume that there is a semantic pass that does the implicit conversions? Could that be used/copied to where templates get instantiated? -- James Miller
Mar 18 2012
prev sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 14.03.2012 22:00, H. S. Teoh wrote:
 Code:
 	import std.stdio;
 	version(explicit) {
 		void func(dstring s) {
 			dstring t = s;
 			writeln(t);
 		}
 	} else {
 		void func(S)(S s) {
 			dstring t = s;	// line 10
 			writeln(t);
 		}
 	}
 	void main() {
 		func("abc");
 	}

 If version=explicit is set, the program compiles fine. But if not, then
 the compiler complains:

 	test.d:10: Error: cannot implicitly convert expression (s) of type string to
immutable(dchar)[]

 What do I need to do to make the template version of func trigger
 implicit conversion of the string lit to dstring? What I'm trying to do
 is to templatize dstring as well, but still benefit from the
 string->dstring conversion when instantiated with dstring.

 (Ditto with implicit conversion to wstring.)


 T
How about this (untested)? void func()(dstring s) { dstring t = s; //... funcImpl(t); } void func(S)(S s) { dstring t = to!dstring(s); //... funcImpl(t); } -- Dmitry Olshansky
Mar 14 2012
parent "Nick Sabalausky" <a a.a> writes:
"Dmitry Olshansky" <dmitry.olsh gmail.com> wrote in message 
news:jjqnnj$1j86$1 digitalmars.com...
 How about this (untested)?

 void func()(dstring s) {
 dstring t = s;
 //... funcImpl(t);
 }
 void func(S)(S s) {
 dstring t = to!dstring(s);
 //... funcImpl(t);
 }
That fails to compile when passed a dstring because it matches both functions. Adding an "if(!is(S==dstring))" constraint to the second makes it compile, but then func("abc") just calls the second one instead of the first.
Mar 14 2012