www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - array of elements of various sybtypes

reply spir <denis.spir gmail.com> writes:
Hello,

This fails:

class T0 {}
class T1 : T0 {}
class T2 : T0 {}

unittest {
     auto t1 = new T1();
     auto t2 = new T2();
     T0[] ts = [t1, t2];
}

Error: cannot implicitly convert expression (t1) of type __trials__.T0 to 
__trials__.T2
Error: cannot implicitly convert expression ([(__error),t2]) of type T2[] to
T0[]

I guess it should be accepted due to explicite typing 'T0[]'. What do you 
think? D first determines the type of the last element (always the last one), 
here T2. Then, /ignoring/ the array's defined type, tries to cast other 
elements to the same type T2. It should instead, I guess, check all elements 
are compatible with the defined array type.
An additional enigma is why the failing element t1 is said to be of supertype 
T0 --which is also correct-- while it retained t2's exact type T2. ???

Anyway, is there a workaround?

Denis
-- 
_________________
vita es estrany
spir.wikidot.com
Jan 26 2011
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 26 Jan 2011 12:27:37 -0500, spir <denis.spir gmail.com> wrote:

 Hello,

 This fails:

 class T0 {}
 class T1 : T0 {}
 class T2 : T0 {}

 unittest {
      auto t1 = new T1();
      auto t2 = new T2();
      T0[] ts = [t1, t2];
 }

 Error: cannot implicitly convert expression (t1) of type __trials__.T0  
 to __trials__.T2
 Error: cannot implicitly convert expression ([(__error),t2]) of type  
 T2[] to T0[]

 I guess it should be accepted due to explicite typing 'T0[]'. What do  
 you think? D first determines the type of the last element (always the  
 last one), here T2. Then, /ignoring/ the array's defined type, tries to  
 cast other elements to the same type T2. It should instead, I guess,  
 check all elements are compatible with the defined array type.
 An additional enigma is why the failing element t1 is said to be of  
 supertype T0 --which is also correct-- while it retained t2's exact type  
 T2. ???

 Anyway, is there a workaround?

auto ts = cast(T0[])[t1, t2]; -Steve
Jan 26 2011
parent spir <denis.spir gmail.com> writes:
On 01/27/2011 03:54 AM, Steven Schveighoffer wrote:
 On Wed, 26 Jan 2011 18:33:45 -0500, spir <denis.spir gmail.com> wrote:

 On 01/26/2011 07:23 PM, Steven Schveighoffer wrote:
 On Wed, 26 Jan 2011 12:27:37 -0500, spir <denis.spir gmail.com> wrote:



 auto ts = cast(T0[])[t1, t2];

Nope, refused for the same reason (tried to construct [t1,t2] before casting it).

Hm.. maybe that only works on array literals with all literal elements. I expected the cast to affect the type the compiler is expecting. For example, this works: cast(ubyte[])[1,2]; // without cast typed as int[]

Yes, but with [1,2] the compiler has no difficulty to create the initial array in the first place ;-) With [t1,t2], it fails in that very first task, before even having a chance to redefine the whole array's type.
 I believe there should be a way to tell the array literal "this is the type you
 should be."

Yes, exactly; I superficially thought specifying it explicitely on the left of '=' would do the job, just like you cast(T[]). But Jonathan is right in saying in any case the array literal must be interpratable first.
  If that's not possible, then it needs to be added. If it's expected
 the cast should work, then I'd file a bug against it.

Yop, but I don't even see the shadow of a solution ;-) Denis -- _________________ vita es estrany spir.wikidot.com
Jan 27 2011
prev sibling next sibling parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
spir Wrote:

 Hello,
 
 This fails:
 
 class T0 {}
 class T1 : T0 {}
 class T2 : T0 {}
 
 unittest {
      auto t1 = new T1();
      auto t2 = new T2();
      T0[] ts = [t1, t2];
 }
 
 Error: cannot implicitly convert expression (t1) of type __trials__.T0 to 
 __trials__.T2
 Error: cannot implicitly convert expression ([(__error),t2]) of type T2[] to
T0[]

D takes the type of the last element. I guess it has been decided to take the common type but hasn't been implemented. Anyway your two reasonable options are: auto ts = to!(T0[])([...]); auto ts = [new T1(), to!(T0)(new T2())] I recommend using std.conv.to instead of a cast because it is safer. Though cast is a no-op and isn't any less safe in this case.
Jan 26 2011
next sibling parent Jesse Phillips <jessekphillips+D gmail.com> writes:
 Right, casting a /single/ element works:
      auto x = [cast(T0)(t1), t2];
      auto y = [t1, cast(T0)(t2)];

So I guess it was implemented as "Common type within the given set."
 But to! fails:
      auto x = [to!(T0)(t1), t2];
      auto y = [t1, to!(T0)(t2)];
 /usr/include/d/dmd/phobos/std/conv.d(99): Error: template std.conv.toImpl(T,S) 
 if (!implicitlyConverts!(S,T) && isSomeString!(T) && isInputRange!(Unqual!(S)) 
 && isSomeChar!(ElementType!(S))) toImpl(T,S) if (!implicitlyConverts!(S,T) && 
 isSomeString!(T) && isInputRange!(Unqual!(S)) && isSomeChar!(ElementType!(S))) 
 matches more than one template declaration, 
 /usr/include/d/dmd/phobos/std/conv.d(559):toImpl(Target,Source) if 
 (implicitlyConverts!(Source,Target)) and 
 /usr/include/d/dmd/phobos/std/conv.d(626):toImpl(T,S) if (is(S : Object) && 
 is(T : Object))
 
 Already had this endless error message once ;-)
 Looks like another bug of non mutually exclusive template constraints?

Yep, looks like. See I told you 'to' was safe, can't be more safe than not allowed :)
Jan 26 2011
prev sibling parent spir <denis.spir gmail.com> writes:
On 01/27/2011 01:17 AM, Jesse Phillips wrote:
 Right, casting a /single/ element works:
       auto x = [cast(T0)(t1), t2];
       auto y = [t1, cast(T0)(t2)];

So I guess it was implemented as "Common type within the given set."
 But to! fails:
       auto x = [to!(T0)(t1), t2];
       auto y = [t1, to!(T0)(t2)];
 /usr/include/d/dmd/phobos/std/conv.d(99): Error: template std.conv.toImpl(T,S)
 if (!implicitlyConverts!(S,T)&&  isSomeString!(T)&&  isInputRange!(Unqual!(S))
 &&  isSomeChar!(ElementType!(S))) toImpl(T,S) if (!implicitlyConverts!(S,T)&&
 isSomeString!(T)&&  isInputRange!(Unqual!(S))&&  isSomeChar!(ElementType!(S)))
 matches more than one template declaration,
 /usr/include/d/dmd/phobos/std/conv.d(559):toImpl(Target,Source) if
 (implicitlyConverts!(Source,Target)) and
 /usr/include/d/dmd/phobos/std/conv.d(626):toImpl(T,S) if (is(S : Object)&&
 is(T : Object))

 Already had this endless error message once ;-)
 Looks like another bug of non mutually exclusive template constraints?

Yep, looks like. See I told you 'to' was safe, can't be more safe than not allowed :)

Yep, greatest safety ever ;-) I'll file a bug (as soon as I have time to search whether it does already exist on the issue tracker). Denis -- _________________ vita es estrany spir.wikidot.com
Jan 26 2011
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On 01/26/2011 07:23 PM, Steven Schveighoffer wrote:
 On Wed, 26 Jan 2011 12:27:37 -0500, spir <denis.spir gmail.com> wrote:

 Hello,

 This fails:

 class T0 {}
 class T1 : T0 {}
 class T2 : T0 {}

 unittest {
 auto t1 = new T1();
 auto t2 = new T2();
 T0[] ts = [t1, t2];
 }

 Error: cannot implicitly convert expression (t1) of type __trials__.T0 to
 __trials__.T2
 Error: cannot implicitly convert expression ([(__error),t2]) of type T2[] to
 T0[]

 I guess it should be accepted due to explicite typing 'T0[]'. What do you
 think? D first determines the type of the last element (always the last one),
 here T2. Then, /ignoring/ the array's defined type, tries to cast other
 elements to the same type T2. It should instead, I guess, check all elements
 are compatible with the defined array type.
 An additional enigma is why the failing element t1 is said to be of supertype
 T0 --which is also correct-- while it retained t2's exact type T2. ???

 Anyway, is there a workaround?

auto ts = cast(T0[])[t1, t2];

Nope, refused for the same reason (tried to construct [t1,t2] before casting it). Denis -- _________________ vita es estrany spir.wikidot.com
Jan 26 2011
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On 01/26/2011 07:29 PM, Jesse Phillips wrote:
 spir Wrote:

 Hello,

 This fails:

 class T0 {}
 class T1 : T0 {}
 class T2 : T0 {}

 unittest {
       auto t1 = new T1();
       auto t2 = new T2();
       T0[] ts = [t1, t2];
 }

 Error: cannot implicitly convert expression (t1) of type __trials__.T0 to
 __trials__.T2
 Error: cannot implicitly convert expression ([(__error),t2]) of type T2[] to
T0[]

D takes the type of the last element. I guess it has been decided to take the common type but hasn't been implemented. Anyway your two reasonable options are: auto ts = to!(T0[])([...]); auto ts = [new T1(), to!(T0)(new T2())] I recommend using std.conv.to instead of a cast because it is safer. Though cast is a no-op and isn't any less safe in this case.

Right, casting a /single/ element works: auto x = [cast(T0)(t1), t2]; auto y = [t1, cast(T0)(t2)]; But to! fails: auto x = [to!(T0)(t1), t2]; auto y = [t1, to!(T0)(t2)]; /usr/include/d/dmd/phobos/std/conv.d(99): Error: template std.conv.toImpl(T,S) if (!implicitlyConverts!(S,T) && isSomeString!(T) && isInputRange!(Unqual!(S)) && isSomeChar!(ElementType!(S))) toImpl(T,S) if (!implicitlyConverts!(S,T) && isSomeString!(T) && isInputRange!(Unqual!(S)) && isSomeChar!(ElementType!(S))) matches more than one template declaration, /usr/include/d/dmd/phobos/std/conv.d(559):toImpl(Target,Source) if (implicitlyConverts!(Source,Target)) and /usr/include/d/dmd/phobos/std/conv.d(626):toImpl(T,S) if (is(S : Object) && is(T : Object)) Already had this endless error message once ;-) Looks like another bug of non mutually exclusive template constraints? Denis -- _________________ vita es estrany spir.wikidot.com
Jan 26 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 26 Jan 2011 18:33:45 -0500, spir <denis.spir gmail.com> wrote:

 On 01/26/2011 07:23 PM, Steven Schveighoffer wrote:
 On Wed, 26 Jan 2011 12:27:37 -0500, spir <denis.spir gmail.com> wrote:

 Hello,

 This fails:

 class T0 {}
 class T1 : T0 {}
 class T2 : T0 {}

 unittest {
 auto t1 = new T1();
 auto t2 = new T2();
 T0[] ts = [t1, t2];
 }

 Error: cannot implicitly convert expression (t1) of type __trials__.T0  
 to
 __trials__.T2
 Error: cannot implicitly convert expression ([(__error),t2]) of type  
 T2[] to
 T0[]

 I guess it should be accepted due to explicite typing 'T0[]'. What do  
 you
 think? D first determines the type of the last element (always the  
 last one),
 here T2. Then, /ignoring/ the array's defined type, tries to cast other
 elements to the same type T2. It should instead, I guess, check all  
 elements
 are compatible with the defined array type.
 An additional enigma is why the failing element t1 is said to be of  
 supertype
 T0 --which is also correct-- while it retained t2's exact type T2. ???

 Anyway, is there a workaround?

auto ts = cast(T0[])[t1, t2];

Nope, refused for the same reason (tried to construct [t1,t2] before casting it).

Hm.. maybe that only works on array literals with all literal elements. I expected the cast to affect the type the compiler is expecting. For example, this works: cast(ubyte[])[1,2]; // without cast typed as int[] I believe there should be a way to tell the array literal "this is the type you should be." If that's not possible, then it needs to be added. If it's expected the cast should work, then I'd file a bug against it. -Steve
Jan 26 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 27 Jan 2011 07:49:06 -0500, spir <denis.spir gmail.com> wrote:

 On 01/27/2011 03:54 AM, Steven Schveighoffer wrote:
 On Wed, 26 Jan 2011 18:33:45 -0500, spir <denis.spir gmail.com> wrote:

 On 01/26/2011 07:23 PM, Steven Schveighoffer wrote:
 On Wed, 26 Jan 2011 12:27:37 -0500, spir <denis.spir gmail.com> wrote:



 auto ts = cast(T0[])[t1, t2];

Nope, refused for the same reason (tried to construct [t1,t2] before casting it).

Hm.. maybe that only works on array literals with all literal elements. I expected the cast to affect the type the compiler is expecting. For example, this works: cast(ubyte[])[1,2]; // without cast typed as int[]

Yes, but with [1,2] the compiler has no difficulty to create the initial array in the first place ;-)

But the cast affects how the array is created. See my post elsewhere in this thread. -Steve
Jan 28 2011
prev sibling next sibling parent reply Don <nospam nospam.com> writes:
spir wrote:
 Hello,
 
 This fails:
 
 class T0 {}
 class T1 : T0 {}
 class T2 : T0 {}
 
 unittest {
     auto t1 = new T1();
     auto t2 = new T2();
     T0[] ts = [t1, t2];
 }
 
 Error: cannot implicitly convert expression (t1) of type __trials__.T0 
 to __trials__.T2
 Error: cannot implicitly convert expression ([(__error),t2]) of type 
 T2[] to T0[]
 
 I guess it should be accepted due to explicite typing 'T0[]'. What do 
 you think? D first determines the type of the last element (always the 
 last one), here T2. Then, /ignoring/ the array's defined type, tries to 
 cast other elements to the same type T2. 

No, it's not supposed to do that. What is supposed to happen is, to use ?: to determine the common type of the array. This will give a T0[] array. Then, it attempts to implicitly cast to the defined type. Your code should work. You've just hit an implementation bug.
Jan 28 2011
parent spir <denis.spir gmail.com> writes:
On 01/31/2011 09:06 PM, Steven Schveighoffer wrote:
 On Fri, 28 Jan 2011 16:59:20 -0500, Don <nospam nospam.com> wrote:

 spir wrote:
 Hello,
 This fails:
 class T0 {}
 class T1 : T0 {}
 class T2 : T0 {}
 unittest {
 auto t1 = new T1();
 auto t2 = new T2();
 T0[] ts = [t1, t2];
 }
 Error: cannot implicitly convert expression (t1) of type __trials__.T0 to
 __trials__.T2
 Error: cannot implicitly convert expression ([(__error),t2]) of type T2[] to
 T0[]
 I guess it should be accepted due to explicite typing 'T0[]'. What do you
 think? D first determines the type of the last element (always the last
 one), here T2. Then, /ignoring/ the array's defined type, tries to cast
 other elements to the same type T2.

No, it's not supposed to do that. What is supposed to happen is, to use ?: to determine the common type of the array. This will give a T0[] array. Then, it attempts to implicitly cast to the defined type. Your code should work. You've just hit an implementation bug.

I don't think it should do that. But I'm not sure. It seems it can have several choices as to what base to use. For example, what if both T1 and T2 implement the X interface, wouldn't X be just as good a choice? I'm really unsure what the right thing to do is. But regardless of all this, I think there should absolutely be a way to say "I absolutely need this array literal to be typed as a U[]" and let the compiler fail if it's not possible. -Steve

Yes. Denis -- _________________ vita es estrany spir.wikidot.com
Jan 31 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 28 Jan 2011 16:59:20 -0500, Don <nospam nospam.com> wrote:

 spir wrote:
 Hello,
  This fails:
  class T0 {}
 class T1 : T0 {}
 class T2 : T0 {}
  unittest {
     auto t1 = new T1();
     auto t2 = new T2();
     T0[] ts = [t1, t2];
 }
  Error: cannot implicitly convert expression (t1) of type __trials__.T0  
 to __trials__.T2
 Error: cannot implicitly convert expression ([(__error),t2]) of type  
 T2[] to T0[]
  I guess it should be accepted due to explicite typing 'T0[]'. What do  
 you think? D first determines the type of the last element (always the  
 last one), here T2. Then, /ignoring/ the array's defined type, tries to  
 cast other elements to the same type T2.

No, it's not supposed to do that. What is supposed to happen is, to use ?: to determine the common type of the array. This will give a T0[] array. Then, it attempts to implicitly cast to the defined type. Your code should work. You've just hit an implementation bug.

I don't think it should do that. But I'm not sure. It seems it can have several choices as to what base to use. For example, what if both T1 and T2 implement the X interface, wouldn't X be just as good a choice? I'm really unsure what the right thing to do is. But regardless of all this, I think there should absolutely be a way to say "I absolutely need this array literal to be typed as a U[]" and let the compiler fail if it's not possible. -Steve
Jan 31 2011