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 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.: 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 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 Rønne 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 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 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 next 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 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 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

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