January 27, 2011
On Wed, 26 Jan 2011 22:10:58 -0500, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Wednesday 26 January 2011 18:59:50 Steven Schveighoffer wrote:
>> On Wed, 26 Jan 2011 18:28:12 -0500, Jonathan M Davis <jmdavisProg@gmx.com>
>>
>> wrote:
>> > I believe that it's supposed to take the common type of t1 and t2 and
>> > make the
>> > result an array of that type. So, assuming that the common type is T0,
>> > then it
>> > should work. However, it's not currently implemented that way. You  
>> could
>> > always
>> > create a bug report so that it doesn't get lost (assuming that no such
>> > report
>> > already exists).
>>
>> Object could also be the common type.  When there exists multiple
>> possibilities, and none of the possibilities are types being passed to the
>> array literal, I think it just gives up (D usually gives up in the face of
>> ambiguity, instead of possibly making the wrong decision).
>>
>> But the problem here appears that there is no way to *force* it to make
>> the right decision.
>>
>> I'd like to see cast(T0[])[...] work, I think that should solve the
>> problem.
>
> It probably doesn't for the exact same reason that the assignment didn't do it.
> The expression is evaluated and _then_ it's cast. So, if the expression isn't
> valid in and of itself, it fails.

This works:

cast(ubyte[])[1,2,3] // creates an array of 3 ubytes

So clearly cast has an effect on the type of the array literal in that case.  I'm not sure why this works and the other doesn't, but we definitely need something that allows one to control the array type of a literal.

In D1, the array could be typed by casting the first element (the first element was always used as the type of the array).  In D2 we no longer can control the type of the array that way, we need some way to do it.

It probably can be done in the case of classes by casting an element to the desired type, but it seems rather hoaky to require two different methods of typing an array literal depending on what kinds of data are in the array.  Plus, casting one element does not mean another element doesn't override it.  It's better IMO to say "I want this array to be T0[]" and let the compiler fail if it can't cast all the elements rather then have the compiler do "oh, one of these is Object, so I'm actually going to re-type this as Object[]".

-Steve
January 27, 2011
On 1/27/11, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>  I'm not sure why this works and the other doesn't, but we
> definitely need something that allows one to control the array type of a
> literal.

pragma helps in discovering what DMD does sometime. This will error out but it will give some useful info:

pragma(msg, typeid( [1,2,cast(ubyte)3] ));
error: [1,2,cast(int)cast(ubyte)3] , &D11TypeInfo_Ai6__initZ

So it forces a cast back to int again.

But we can use a postfix to set an unsigned type for the whole array:

writeln(typeid( [1,2,3u] ));  // uint[]

And we can select a string type with a postfix, but we can't use a cast:

void main()
{
    writeln(typeid( ["a"d, "b", "c"] ));    // works
    writeln(typeid( [cast(dchar)"a", "b", "c"] ));  // doesn't work,
// Error: incompatible types for ((cast(dchar)"a") ? ("b")): 'dchar'
and 'string'
}
January 27, 2011
spir:

> Maybe, but (in this case) array literals are OK.

The are not OK. They need to use the lowest common supertype, and in this case they aren't doing it. If this is too much hard or unsafe or ambiguous to do, then D array literals need some syntax to allow the programmer to specify the missing semantics in a nice way.

Bye,
bearophile
January 27, 2011
On 01/27/2011 03:59 AM, Steven Schveighoffer wrote:
> On Wed, 26 Jan 2011 18:28:12 -0500, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
>
>
>> I believe that it's supposed to take the common type of t1 and t2 and make the
>> result an array of that type. So, assuming that the common type is T0, then it
>> should work. However, it's not currently implemented that way. You could always
>> create a bug report so that it doesn't get lost (assuming that no such report
>> already exists).
>>
>
> Object could also be the common type.

Very true.

>  When there exists multiple possibilities,
> and none of the possibilities are types being passed to the array literal, I
> think it just gives up (D usually gives up in the face of ambiguity, instead of
> possibly making the wrong decision).

That's OK.

> But the problem here appears that there is no way to *force* it to make the
> right decision.

Yes, that's what I meant in another post. We should have a way to hint the compiler about intended common type /before/ it even tries to contruct an initial array value (which else fails). But I have no idea how; should be a syntactic trick. There is no "literal-typing" pattern in D, instead the compiler always performs type induction from the form.

> I'd like to see cast(T0[])[...] work, I think that should solve the problem.

See "/before/" above (cast applies on already constructed value).

The only alternative is, I guess, when the compiler initially fails to find a common type, to have it look for a hint by interpreting the target; then explicit array var typing would work:
    T0[] ts = [t1, t2];
But it seems to me rather complicated. (There are many different situations in which literals may appear).

> -Steve

-- 
_________________
vita es estrany
spir.wikidot.com

January 27, 2011
On 01/27/2011 05:05 AM, Steven Schveighoffer wrote:
> On Wed, 26 Jan 2011 22:10:58 -0500, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
>
>> On Wednesday 26 January 2011 18:59:50 Steven Schveighoffer wrote:
>>> On Wed, 26 Jan 2011 18:28:12 -0500, Jonathan M Davis <jmdavisProg@gmx.com>
>>>
>>>
>>> I'd like to see cast(T0[])[...] work, I think that should solve the
>>> problem.
>>
>> It probably doesn't for the exact same reason that the assignment didn't do it.
>> The expression is evaluated and _then_ it's cast. So, if the expression isn't
>> valid in and of itself, it fails.
>
> This works:
>
> cast(ubyte[])[1,2,3] // creates an array of 3 ubytes
>
> So clearly cast has an effect on the type of the array literal in that case.
> I'm not sure why this works and the other doesn't,
[1,2,3] is valid! [t1,t2] is not if one of the elements' type is not implicitely convertible to the other. In your example cast applies to an already constructed array. (Hope you see what I mean)

> but we definitely need
> something that allows one to control the array type of a literal.

Yop! But this hint has to belong to the literal notation syntax itself. Not anything (like cast ot to!) that applies afterwards.

> In D1, the array could be typed by casting the first element (the first element
> was always used as the type of the array). In D2 we no longer can control the
> type of the array that way, we need some way to do it.

Works in D2. If any element is of the inteded common type, then all goes fine.
But I'm not satisfied with that trick. We cast an element instead of typing the array literal. It's just a side-effect. (But I'll go with it as of now.)

> It probably can be done in the case of classes by casting an element to the
> desired type, but it seems rather hoaky to require two different methods of
> typing an array literal depending on what kinds of data are in the array. Plus,
> casting one element does not mean another element doesn't override it. It's
> better IMO to say "I want this array to be T0[]" and let the compiler fail if
> it can't cast all the elements rather then have the compiler do "oh, one of
> these is Object, so I'm actually going to re-type this as Object[]".

Agreed.

Denis
-- 
_________________
vita es estrany
spir.wikidot.com

January 27, 2011
On 01/27/2011 05:40 AM, Andrej Mitrovic wrote:
> On 1/27/11, Steven Schveighoffer<schveiguy@yahoo.com>  wrote:
>>   I'm not sure why this works and the other doesn't, but we
>> definitely need something that allows one to control the array type of a
>> literal.
>
> pragma helps in discovering what DMD does sometime. This will error
> out but it will give some useful info:
>
> pragma(msg, typeid( [1,2,cast(ubyte)3] ));
> error: [1,2,cast(int)cast(ubyte)3] ,&D11TypeInfo_Ai6__initZ
>
> So it forces a cast back to int again.
>
> But we can use a postfix to set an unsigned type for the whole array:
>
> writeln(typeid( [1,2,3u] ));  // uint[]
>
> And we can select a string type with a postfix, but we can't use a cast:
>
> void main()
> {
>      writeln(typeid( ["a"d, "b", "c"] ));    // works
>      writeln(typeid( [cast(dchar)"a", "b", "c"] ));  // doesn't work,
> // Error: incompatible types for ((cast(dchar)"a") ? ("b")): 'dchar'
> and 'string'
> }

The latter fails because because you did an error. Indeed D cannot cast a /string/ of immutable chars to a char type.
    writeln(typeid( [cast(immutable(dchar)[])"a", "b", "c"] ));
    // immutable(dchar)[][]

But your remark is valid: 'd' is a typing hint that belonds to the literal notation itself; not something that applies afterward on an already created thing. We need something similar to /initially/ type arrays literals. By analogy, the only thing I can imagine is postfixing the (element type) to the literal:
     auto ts = [t1, t2]T0;
But it's not really beautiful ;-)

Denis
-- 
_________________
vita es estrany
spir.wikidot.com

January 27, 2011
On 1/27/11, spir <denis.spir@gmail.com> wrote:
> The latter fails because because you did an error. Indeed D cannot cast a
> /string/ of immutable chars to a char type.
>      writeln(typeid( [cast(immutable(dchar)[])"a", "b", "c"] ));
>      // immutable(dchar)[][]

My bad! :)

This is what I should have typed:
writeln(typeid( [cast(dstring)"a", "b", "c"] ));

>  By
> analogy, the only thing I can imagine is postfixing the (element type) to
> the
> literal:
>       auto ts = [t1, t2]T0;
> But it's not really beautiful ;-)
>

Well, I wasn't implying that we need a special postfix syntax for custom types (honestly, at this stage any feature request gets shot down and buried 6 feet under by the D town sheriff and his deputy).

Maybe all that needs changing is the compiler so it can at least try to find a common type.
January 28, 2011
On Wed, 26 Jan 2011 23:40:39 -0500, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:

> On 1/27/11, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>>  I'm not sure why this works and the other doesn't, but we
>> definitely need something that allows one to control the array type of a
>> literal.
>
> pragma helps in discovering what DMD does sometime. This will error
> out but it will give some useful info:
>
> pragma(msg, typeid( [1,2,cast(ubyte)3] ));
> error: [1,2,cast(int)cast(ubyte)3] , &D11TypeInfo_Ai6__initZ
>
> So it forces a cast back to int again.

Right, because int can hold all of the values.

Casting the whole array to ubyte[] makes it cast all the arrays elements.

Essentially, I'm proposing that cast(U[])[e1, e2, ..., en] is translated to [cast(U)e1, cast(U)e2, ..., cast(U)en].

This works for array literals that are composed of literal elements, but for some reason doesn't work for classes.

>
> But we can use a postfix to set an unsigned type for the whole array:
>
> writeln(typeid( [1,2,3u] ));  // uint[]

Because integer promotion rules say ints get "promoted" to uints.  Essentially, uint is considered to be able to hold all int values (even though it technically can't).  So the "common" type chosen between int and uint is uint.

> And we can select a string type with a postfix, but we can't use a cast:
>
> void main()
> {
>     writeln(typeid( ["a"d, "b", "c"] ));    // works
>     writeln(typeid( [cast(dchar)"a", "b", "c"] ));  // doesn't work,
> // Error: incompatible types for ((cast(dchar)"a") ? ("b")): 'dchar'
> and 'string'
> }

The error has been pointed out, but you are still missing the point.  Casting one element has a partial effect on the overall type, but does not "force" the type of the array.  It only forces the type of one element.  The compiler still chooses an array type of the "common" type of all elements.

-Steve
January 28, 2011
On Thu, 27 Jan 2011 08:33:05 -0500, spir <denis.spir@gmail.com> wrote:

> On 01/27/2011 05:05 AM, Steven Schveighoffer wrote:
>> On Wed, 26 Jan 2011 22:10:58 -0500, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
>>
>>> On Wednesday 26 January 2011 18:59:50 Steven Schveighoffer wrote:
>>>> On Wed, 26 Jan 2011 18:28:12 -0500, Jonathan M Davis <jmdavisProg@gmx.com>
>>>>
>>>>
>>>> I'd like to see cast(T0[])[...] work, I think that should solve the
>>>> problem.
>>>
>>> It probably doesn't for the exact same reason that the assignment didn't do it.
>>> The expression is evaluated and _then_ it's cast. So, if the expression isn't
>>> valid in and of itself, it fails.
>>
>> This works:
>>
>> cast(ubyte[])[1,2,3] // creates an array of 3 ubytes
>>
>> So clearly cast has an effect on the type of the array literal in that case.
>> I'm not sure why this works and the other doesn't,
> [1,2,3] is valid! [t1,t2] is not if one of the elements' type is not implicitely convertible to the other. In your example cast applies to an already constructed array. (Hope you see what I mean)

I do, but what do you think the binary value of the array is?  You might be surprised that it is

01h 02h 03h

instead of the binary representation of the int[] [1, 2, 3]:

01h 00h 00h 00h 02h 00h 00h 00h 03h 00h 00h 00h

i.e. all the elements are casted to ubyte *before* the array is constructed.  This is the behavior I think we should have in all cases.

>> but we definitely need
>> something that allows one to control the array type of a literal.
>
> Yop! But this hint has to belong to the literal notation syntax itself. Not anything (like cast ot to!) that applies afterwards.

IMO cast is fair game, because it's a compiler internal operation.  to! is a library function, and should not affect the literal type.

>> In D1, the array could be typed by casting the first element (the first element
>> was always used as the type of the array). In D2 we no longer can control the
>> type of the array that way, we need some way to do it.
>
> Works in D2. If any element is of the inteded common type, then all goes fine.

But this doesn't work to "force" the array type.  It only works to force a different type into consideration for the common type.

It is specifying a different intention to the compiler than I think you want.  If, for example, you *wanted* the type of the array to be T0[], and not Object[], this line still results in an Object[] array:

Object o = new T1;
auto arr = [cast(T0)t1, t2, o];

So wouldn't you rather the compiler say "hey, o can't be a T0, even though you want a T0[]" or would you rather it just happily carry out your order and fail later when you try T0 methods on any of the elements?

-Steve
January 28, 2011
On 01/26/2011 06:27 PM, 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. 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?

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

Denis
-- 
_________________
vita es estrany
spir.wikidot.com