Thread overview
Implicit conversion from array of class to array of interface
Dec 13, 2009
Phil Deets
Dec 13, 2009
Phil Deets
Dec 13, 2009
Phil Deets
Dec 13, 2009
Frank Benoit
Dec 13, 2009
Phil Deets
December 13, 2009
(D 2.033) I have a need to do something like this code:

interface I {}
class C : I {}
class D : I {}

void f(I[]) {}
void f(bool) {}

void g(T)(T param) {
	f(param);
}

int main()
{
	bool b;
	C[] c;
	D[] d;
	g(b);
	g(c);
	g(d);
	return 0;
}

This results in the output:

temp.d(9): Error: function temp.f (I[] _param_0) is not callable using argument types (C[])
temp.d(9): Error: cannot implicitly convert expression (param) of type C[] to bool
temp.d(18): Error: template instance temp.g!(C[]) error instantiating

As you can see, I can't cast C[] to I[] when I call f because T can be bool too. My workaround for now is:

interface I {}
class C : I {}
class D : I {}

void f(I[]) {}
void f(C[] param) {
	f(cast(I[])param);
}
void f(D[] param) {
	f(cast(I[])param);
}
void f(bool) {}

void g(T)(T param) {
	f(param);
}

int main()
{
	bool b;
	C[] c;
	D[] d;
	g(b);
	g(c);
	g(d);
	return 0;
}

Is there a better way to deal with this? Is this behavior a design bug?

Phil Deets

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
December 13, 2009
On Sun, 13 Dec 2009 03:22:31 -0500, Phil Deets <pjdeets2@gmail.com> wrote:

> (D 2.033) I have a need to do something like this code:
>
> interface I {}
> class C : I {}
> class D : I {}
>
> void f(I[]) {}
> void f(bool) {}
>
> void g(T)(T param) {
> 	f(param);
> }
>
> int main()
> {
> 	bool b;
> 	C[] c;
> 	D[] d;
> 	g(b);
> 	g(c);
> 	g(d);
> 	return 0;
> }
>
> This results in the output:
>
> temp.d(9): Error: function temp.f (I[] _param_0) is not callable using argument types (C[])
> temp.d(9): Error: cannot implicitly convert expression (param) of type C[] to bool
> temp.d(18): Error: template instance temp.g!(C[]) error instantiating
>
> As you can see, I can't cast C[] to I[] when I call f because T can be bool too. My workaround for now is:
>
> interface I {}
> class C : I {}
> class D : I {}
>
> void f(I[]) {}
> void f(C[] param) {
> 	f(cast(I[])param);
> }
> void f(D[] param) {
> 	f(cast(I[])param);
> }
> void f(bool) {}
>
> void g(T)(T param) {
> 	f(param);
> }
>
> int main()
> {
> 	bool b;
> 	C[] c;
> 	D[] d;
> 	g(b);
> 	g(c);
> 	g(d);
> 	return 0;
> }
>
> Is there a better way to deal with this? Is this behavior a design bug?
>
> Phil Deets
>

I found another workaround which doesn't require a bunch of extra overloads. I'll probably update it to use that template someone wrote in that thread about static duck-typing.

//interface I {void h();}
class C /*: I*/ {void h() {}}
class D /*: I*/ {void h() {}}

void f(T)(T param)
{
	static if (__traits(compiles, param[0].h()))
	{
		// do I[] overload here
	}
	else
	{
		pragma(msg, "Unsupported type for f.")
		static assert(0);
	}
}
void f(T:bool)(T param) {}

void g(T)(T param) {
	f(param);
}

int main()
{
	bool b;
	C[] c;
	D[] d;
	g(b);
	g(c);
	g(d);
	return 0;
}

By the way, how do I move the bool specialization into the general function?

void f(T)(T param)
{
	static if (__traits(compiles, param[0].h()))
	{
		// do I[] overload here
	}
	else static if (T is bool) // how do I do this?
	{
	}
	else
	{
		pragma(msg, "Unsupported type for f.")
		static assert(0);
	}
}
December 13, 2009
casting an array of class references to an array of interface references (or vice versa) will not work at runtime. Your program will crash.

This is because if the invisible pointer correction that is done if you cast a single class ref to an interface ref.


C c = new C;
I i = c;

writefln( "c=%d i=%i", cast(uint)cast(void*)c, cast(uint)cast(void*)i);

This shows, the numeric values are not equal.
At the assignment were an imlicit cast is taking place, dmd inserts a
pointer adjustement. If you cast an array, nothing physically is done to
the array content. In fact you need to run a loop over the array and
cast each member on it own.
December 13, 2009
On Sun, 13 Dec 2009 04:16:19 -0500, Frank Benoit <keinfarbton@googlemail.com> wrote:

> casting an array of class references to an array of interface references
> (or vice versa) will not work at runtime. Your program will crash.
>
> This is because if the invisible pointer correction that is done if you
> cast a single class ref to an interface ref.
>
>
> C c = new C;
> I i = c;
>
> writefln( "c=%d i=%i", cast(uint)cast(void*)c, cast(uint)cast(void*)i);
>
> This shows, the numeric values are not equal.
> At the assignment were an imlicit cast is taking place, dmd inserts a
> pointer adjustement. If you cast an array, nothing physically is done to
> the array content. In fact you need to run a loop over the array and
> cast each member on it own.

Thanks for informing me, my newer workaround avoids this problem.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
December 13, 2009
On Sun, 13 Dec 2009 04:08:19 -0500, Phil Deets <pjdeets2@gmail.com> wrote:

> I found another workaround which doesn't require a bunch of extra overloads. I'll probably update it to use that template someone wrote in that thread about static duck-typing.

I looked up this post. It was: "Re: static interface" by Simen kjaeraas at Thursday, November 19, 2009 6:47:08 AM.

> By the way, how do I move the bool specialization into the general function?
>
> void f(T)(T param)
> {
> 	static if (__traits(compiles, param[0].h()))
> 	{
> 		// do I[] overload here
> 	}
> 	else static if (T is bool) // how do I do this?
> 	{
> 	}
> 	else
> 	{
> 		pragma(msg, "Unsupported type for f.")
> 		static assert(0);
> 	}
> }

I figured it out; it's:

else static if (is(T == bool))

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/