[Issue 5498] New: array of elements of subtypes of a common supertype

d-bugmail at puremagic.com d-bugmail at puremagic.com
Fri Jan 28 07:01:58 PST 2011


http://d.puremagic.com/issues/show_bug.cgi?id=5498

           Summary: array of elements of subtypes of a common supertype
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody at puremagic.com
        ReportedBy: denis.spir at gmail.com


--- Comment #0 from Denis Derman <denis.spir at gmail.com> 2011-01-28 06:59:48 PST ---
Hello,

Seems there is no way to create an array of elements which types are subtypes
of a common supertype:

void test0 () {
    auto t1 = new T1();
    auto t2 = new T2();
    T0[] array = [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[]

The array value is obviously correct. But there is here no common compatible
type between T1 & T2 that D could directly choose; instead, they have a common
super-type, which is the one intended as array element type.
D logically does not take our specification of the wished common type, in the
target part of the assignment, into account; since the source array must in any
case first exist at all. And it does not try to guess a common supertype by
climbing up the type hierarchy tree. This would be naughty-bug-prone since D
could find a common type which is not the intended one, precisely in case of
programmer error. And anyway Object would always be convenient, while this is
certainly not the programmer intention in the general case.
The core issue is that the language must first create a valid array value,
before any attempt to convert to any explicitely specified type (if ever this
feature was implemented). For this reason, cast or to! applied on the array
cannot help neither; the original array must first initially be correct
according to D rules for literal:

    T0[] array = cast(T0[])[t1, t2];
==>
Same error.

A workaround is to cast one of the elements, instead of the array, to the
intended common type (*):

void test2 () {
    auto t1 = new T1();
    auto t2 = new T2();
    T0[] array1 = [cast(T0)t1, t2];     // ok
    T0[] array2 = [t1, cast(T0)t2];     // ok
}

But this trick raises a conceptual problem: what we mean is specifying the
array literal's common type; what is in fact written is a cast of an element.
Far to be obvious.

A library solution can be made via an "array-feeding" helper function; it uses
a variadic argument to avoid the user writing an array literal:

void feed (T) (ref T[] array, T[] elements...) {
    array ~= elements;
}
void test3 () {
    auto t1 = new T1();
    auto t2 = new T2();
    T0[] array;
    array.feed(t1, t2);    // means: array = [t1,t2];
    array.feed(t2, t1);    // means: array ~= [t2,t1];
    writeln(array);
}
==>
[arraydef.T1, arraydef.T2, arraydef.T2, arraydef.T1]

As shown, feed can also extend an existing array, replacing "~=" which fails
for the same cause as "=". (Reason why I called the func "feed", not "init".)
This is still a workaround, maybe a better one. Programmers need to know about
the issue and the provided solution, thus this should be mentionned in good
place in doc about arrays.

A true solution would require having a way to hint the compiler about the
intended type, in literal syntax itself --a hint taken into account by the
language before any initial array is created. Just like postfixes 'w' & 'd' for
chars and strings. The best I could think at is, by analogy, postfixing the
element type to the array literal:

    T0[] array = [t1, t2]T0;

Not very nice :-(


Denis


(*) to! cannot be used at all because we hit another, unrelated, bug; namely
one about non mutually exclusive template constraints:

    T0[] array1 = [to!(T0)(t1), 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))

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list