Array literals MUST be immutable.

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


On Fri, 19 Feb 2010 10:32:29 -0500, Denis Koroskin <2korden at gmail.com>  
wrote:

> On Fri, 19 Feb 2010 17:51:26 +0300, Steven Schveighoffer  
> <schveiguy at yahoo.com> wrote:
>
>> The implicit static array is the problem, not the assigning of a  
>> dynamic array from a static array.
>
> Not quite true. Here is your example slightly modified:
>
> int[] foo()
> {
>     int[3] staticArray;
>     int[] dynamicArray = staticArray;
>     return dynamicArray;
> }
>
> It doesn't involve any array literals, but the problem is still there.

Yes, but my point was that initializing a dynamic array with a literal  
should not implicitly promote unsafe code.  When someone uses a literal,  
they are expecting the type to match.  A literal should be the most useful  
type for the range of types it initializes.  I think immutable is better  
than a static because an implicit casting of a static to a dynamic array  
promotes memory corruption.  An implicit conversion from a dynamic to a  
static does not.

>> The literal doesn't look like it's a static array.
>
> It really does to me. [a, b, c] is essentially 3 stack pushes and  
> nothing else (which is the same as allocating stack space for a static  
> array of 3 elements).

It looks like data to me, not stack data.

When you do:

int i = 1;

does the 1 look like stack data?

My point is, where it's stored is not implicit in its usage, so if it's  
stack data, it could be easily interpreted as not stack data.  Storing it  
in the immutable data segment and typing it as immutable is the safest  
option.

>
>> This is already available by using a static array explicitly.
>
> How would you initialize such a static array with 3 given elements (a, b  
> and c). I certainly wouldn't love verbosity of
>
> int[3] array = void;
> array[0] = a;
> array[1] = b;
> array[2] = c;

What I meant was compile-time values could be stored in the array.  I  
agree storing variables in a stack array needs to be solved.  A possible  
solution is to allow variables in array literals only when being assigned  
to or used as a static array.

How do you solve this?

immutable(int)[] i = [1, 2, 3]; // add an idup?

The best thing here is to avoid a heap allocation, because immutable data  
made entirely from literals requiring a heap allocation is just as bad as  
the current situation.

With literals being immutable, going to static array is possible.  With  
literals being a static array, it is not possible.

>
>> The 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.
>
> You can't make [a, b, c] immutable unless all of the a, b and c are  
> immutable (or primitive types). For example, what type would that be:
>
> Object a = new Object();
> Object b = new Object();
> Object c = new Object();
>
> auto array = [a, b, c];

Yes, it's a problem that needs to be solved.  I'd say that literals that  
contain a runtime variable should be typed as static arrays, but I'm  
pretty sure Don doesn't like that.

I'm going to start a new thread about this.  I don't think this particular  
nuance is getting enough attention.

>
> It certainly can't be immutable(Object)[]. I believe it shouldn't be  
> Object[] either (you can always make a dynamic array out of static but  
> not vice versa). What bonuses would does Object[] provide over  
> Object[3]? Object[] doesn't prevent but rather *encourages* escaping  
> reference, because D returns static array by values:
>
> // Your preferred way:
> Object[] toArray(Object a, Object b, Object c)
> {
>      return [a, b, c]; // Bug, escaping reference to stack data
> }

I didn't say I prefer it.  I meant it shouldn't be this easy, even in  
unsafe D.  To anticipate your next argument, I don't think requiring  
slicing brackets is difficult enough to prevent these problems also.

>
> // My suggestion
> Object[3] toArray(Object a, Object b, Object c)
> {
>      return [a, b, c]; // Correct
> }
>
>>>
>>> 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
>>
>> 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.
>>
>
> <sarcasm>Sure, just hide the bug without compiler worrying you about  
> presence of one. </sarcasm>

It's not an imagined problem.  Look at Java's checked exceptions for an  
example.

> You suggestion encourages unsafe by default, which is bad bad bad. It  
> just shouldn't compile. People should just use .dup if they need a  
> dynamic array unless they *really* know what they are doing, and use [].  
> It should never happen in SafeD, and probably not even allowed.

I think you miss out on a whole class of performance gains by preventing  
slicing of static arrays, but this really is an argument for what to do in  
SafeD.

-Steve



More information about the Digitalmars-d mailing list