Array literals MUST be immutable.

Steven Schveighoffer schveiguy at yahoo.com
Fri Feb 19 08:03:30 PST 2010


On Fri, 19 Feb 2010 10:22:15 -0500, grauzone <none at example.net> wrote:

> Steven Schveighoffer wrote:
>> On Thu, 18 Feb 2010 20:47:16 -0500, Denis Koroskin <2korden at gmail.com>  
>> wrote:
>>
>>> On Fri, 19 Feb 2010 00:46:05 +0300, Steven Schveighoffer  
>>> <schveiguy at yahoo.com> wrote:
>>>> That would be bad,  T[] is implicitly casted from T[N].  Consider  
>>>> that you could easily escape stack data using this.  In other words,  
>>>> the type system would allow the assignment without the dup.
>>>>
>>>> -Steve
>>>
>>> I don't think so. First of all, it is consistent with current behavior:
>>>
>>> int[] foo()
>>> {
>>>     int[3] staticArray = [0, 1, 2];
>>>     int[] dynamicArray = staticArray;
>>>
>>>     return dynamicArray;
>>> }
>>  Here is the case I'd say looks bad to me:
>>  int[] foo()
>> {
>>    int[] dynamicArray = [0, 1, 2];
>>    return dynamicArray;
>> }
>>  If [0, 1, 2] is a static array, then it escapes its scope and  
>> corruption ensues.  The implicit static array is the problem, not the  
>> assigning of a dynamic array from a static array.  The literal doesn't  
>> look like it's a static array.
>
> SafeD will take care of it. As the compiler has to support SafeD anyway,  
> the same mechanisms can be used to create warnings or even errors in  
> normal D code.

I'm not sure where Andrei will draw the line for SafeD.  SafeD still has  
to be UsefulD ;)

But I think slicing a static array makes the compiler lose all knowledge  
that it is a scoped entity.  Until scope (or something equivalent) is a  
proper type constructor, we will not have full escape analysis, just  
simple tricks and hacks that prevent certain errors.

The other option is to disallow slicing static arrays in SafeD, which IMO  
is a mistake, but I can see validity in the argument behind it.

But besides this, I want non-safe D still to be as safe as it can be!

>
> Don wants to make array literals immutable; that means you couldn't just  
> assign them to int[] anyway. In both cases, you'd have to use .dup to  
> use them as normal, mutable arrays.

That's fine, if I don't specify dup by accident, the compiler would  
complain.  In Denis' proposal, the compiler doesn't complain it just  
silently compiles.

> Array literals being static arrays would be very handy in other places.  
> Wouldn't it be nice if you could just use them for small fixed size  
> vectors (wasn't that one of the reasons to make static arrays value  
> types)? Then you could write assert([1, 2] + [3, 4] == [4, 6]). No silly  
> struct vector "classes" needed.

Does this work with static arrays?  I thought you needed to use the  
slicing notation.  In any case, using literals in array operations would  
be nifty.  I don't think you need to have array literals be statically  
sized to accomplish this.

>
>>> Second, it's very useful to prevent unnecessary heap allocations.
>>  This is already available by using a static array explicitly.  The
>
> Static arrays still suck a bit, although making them value types  
> improved the situation.
>
> Inside functions, this still allocates an array on the heap and copies  
> it into the static array:
>
> int[2] array = [1, 2];

The allocation goes away if the literal is immutable.  I think we all  
agree the current situation is sucky.

> I don't quite know why it can't just behaves as if "array" was declared  
> on module level (or as, um, the other "static").

Essentially, that is what an immutable array is.  The difference is in  
type inference.

>
>> question is, what should be the default?  I think making it immutable  
>> and non-static is the right choice because it can always escape scope,  
>> and does not require an allocation.  From there you can do either a  
>> static array if you know it won't escape scope, or a dynamic array (via  
>> dup) if you need to modify it and it will escape scope.
>
> How would you "do" a static array from an immutable array?
>
> As I understood, immutable array literals would still require heap  
> allocations sometimes. Because even runtime dependent values can be  
> immutable.

Requiring array literals to be immutable prevents you from including  
runtime values.  This would work fine and not allocate:

int[3] arr = [1, 2, 3];

But your point is well taken.  I remember you brought it up before, and I  
argued a while with someone about it to no avail (can't remember what or  
with whom I was arguing :)

If array literals become immutable, being able to initialize static arrays  
easily from runtime values *without* heap allocation would be a very nice  
feature to have.  Perhaps you could use variables in an array literal only  
if they are used to initialize statically sized arrays.  This problem  
needs to be discussed if we are to get immutable array literals.

>>>
>>> I would prefer static arrays not to cast to dynamic ones implicitly,  
>>> but using opSlice syntax instead:
>>>
>>> int[] arr = [0, 1, 2]; // error
>>> int[] arr = [0, 1, 2][]; // fine, use on your own risk
>
> I agree. I wonder how static arrays will be handled in SafeD. Maybe just  
> disallow using them as normal arrays? Require an explicit .dup? Anyway,  
> it will be safe.

I have a feeling that safeD will disallow taking the address of a local,  
which includes slicing a static array, but IMO this would be a huge  
deterrent from using safeD.  Might as well call it slowD at that point :)

>
>> This is just an annoyance error.  What will happen is people will  
>> constantly just use the brackets to shut up the compiler without  
>> thinking about what it really means.
>
> Not really an argument, when array literals will be immutable, you could  
> as well say:
>
> //the cast is only there to shut up the stupid dmd!
> int[] arr = cast(int[])([0, 1, 2]);

Yes, but a cast is a red flag.  A simple appending of brackets is not.  It  
is well established that casts are to let you do things that in most  
contexts are not a good idea.  Brackets are not the same.

Beside all these points, if array literals are static, then obtaining an  
immutable array literal requires a dup or a global.  I don't think that's  
a good strategy.  Another point is IFTI and auto type detection -- what is  
most useful as an automatic type for array literals?  I'd say immutable  
arrays are more useful because they can be easily converted to all other  
types of arrays, and it is consistent with string literals.  The only  
caveat as you brought up is using runtime values inside a literal to  
initialize a static array.  I think this can be special-cased by the  
compiler, but I'm not sure.

-Steve



More information about the Digitalmars-d mailing list