H. S. Teoh 
| On Tue, Aug 20, 2013 at 05:01:36PM -0400, Jonathan M Davis wrote:
> On Tuesday, August 20, 2013 13:35:43 H. S. Teoh wrote:
[...]
> > It should be possible to write things like:
> >
> > byte[] a = [1,2,3,4];
> >
> > and *not* incur the overhead of allocating an int[] and then copying it over (with implicit casting) to the byte[].
>
> That doesn't allocate anymore, and there are plenty of cases like that (several of which I'm sure still allocate), but it's essentially an optimization any time that an array literal doesn't end up allocating.
That's what troubles me. Allocations shouldn't be the default; they should be fallback when they can't be avoided.
> > On that note, I find it Very Evil that this doesn't work properly:
> >
> > char[] a = "abc";
> > const(char)[] b = "abc";
> >
> > Instead, you have to do:
> >
> > char[] a = "abc".dup;
> > const(char)[] b = "abc".dup;
> >
> > I can accept that having an explicit .dup or .idup is a good thing when the source string is a variable, but in this case, the compiler *should* be smart enough to know, hey, "abc" is a literal and is being immediately assigned to a char[], so the user must intend that it's used only to initialize the char[], so I don't need to actually allocate a *string* (as in, immutable(char)[]) for the literal and copy it, but instead, I should generate code to initialize each array element.
> >
> > tl;dr, I think D literals are assigned a type far too early in the compilation process. The intended meaning of a literal shouldn't be bound until the compiler is able to infer from context what type is actually required.
>
> Honestly, I have no problem with this. The type of string literal is immutable(char)[], so having to dup it makes sense. And you don't incur any extra allocations, because string literals are part of the generated binary rather than being allocated at runtime (and on Linux, they end up in the read- only portion). So, you're only allocating once (when you dup), which is what what happen if the compiler allowed the code that you're looking for.
[...]
It's not just with strings. What about this:
byte[] a = [1,2,3];
uint[] b = [1,2,3];
long[] c = [1,2,3];
? Will the compiler emit an int[] (or immutable(int)[]?) to hold each
literal, and then copy the contents (with casting) to the target arrays
at runtime?
I argue that [1,2,3] has a different meaning in each of these lines. On
the first line, it should mean [byte(1), byte(2), byte(3)], on the
second line it should mean [1u, 2u, 3u], and on the third line it should
mean [1L, 2L, 3L]. The compiler should not assign it to int[] except as
a fallback (e.g., if you wrote auto d = [1,2,3];, then it would default
to int[]).
This issues shows up in places like IFTI, where [1,2,3] is assigned too early to be int[], so it fails to match a template function that expects byte[]. IFTI can of course be hacked to work around this (and maybe already has), but the fundamental problem is that literals are assumed to be of a particular type far too early on. They really should have flexible type, adaptable to the context they appear in. A literal like [1,2,3] should not be be assumed to be int[] until the compiler determines that the context does not provide sufficient information to deduce the intended type. IOW, int[] should be a *fallback* type for [1,2,3], not something presumed up-front.
T
--
Which is worse: ignorance or apathy? Who knows? Who cares? -- Erich Schubert
|