Mutable enums

Steven Schveighoffer schveiguy at yahoo.com
Wed Nov 16 12:00:16 PST 2011


On Wed, 16 Nov 2011 14:26:57 -0500, Timon Gehr <timon.gehr at gmx.ch> wrote:

> On 11/16/2011 02:22 PM, Steven Schveighoffer wrote:
>> On Tue, 15 Nov 2011 13:45:02 -0500, Timon Gehr <timon.gehr at gmx.ch>  
>> wrote:
>>
>>> Note that this is an explicit allocation:
>>>
>>> int[] a = [1,2,3]; // just as explicit as a NewExpression
>>>
>>> Only the enums "hide" it sometimes, but actually you should know the
>>> involved types.
>>
>> As I've said, there are already ways to explicitly allocate memory. A
>> suggested replacement for this is:
>>
>> int[] a = array(1, 2, 3);
>>
>> And you could always do:
>>
>> int[] a = [1, 2, 3].dup;
>>
>> Nobody complains about having to do:
>>
>> char[] a = "hello".dup;
>>
>> I don't see why we couldn't do the same for all array literals.
>>
>
> Because 'immutable' behaves nicely on built-in value types, but not on  
> arbitrary reference types.

string is a reference type.  We hear no complaints about strings being  
stored in ROM and the type of literals being immutable.

Make no mistake, this doesn't cover every current instance array literals,  
such as ones which contain necessarily-heap-allocated entities.  Those  
would be covered by a library function (e.g. array(...)).  But those are  
not array literals anyways, they are constructors.

>>> Well, there is a function called writeln that can do that. That is a
>>> different function. But the one that gets actually called is not const
>>> correct as well.
>>>
>>>
>>> This is writeln:
>>>
>>> // Most general instance
>>> void writeln(T...)(T args)
>>> if (T.length > 1 || T.length == 1 && !is(typeof(args[0]) :
>>> const(char)[]))
>>> {
>>> stdout.write(args, '\n');
>>> }
>>>
>>>
>>> =>
>>> writeln([1,2,3]);
>>> // modulo IFTY:
>>> writeln!(int[])([1,2,3]);
>>> // const correct?
>>> writeln!(int[])([1,2,3].idup); // nope!
>>>
>>> Error: cannot implicitly convert expression (_adDupT(&
>>> _D11TypeInfo_Ai6__initZ,[1,2,3])) of type immutable(int)[] to int[]
>>
>> I'm not sure what this means. If [1, 2, 3] is typed as immtuable(int)[],
>> it will compile.
>>
>> Simple test:
>>
>> immutable(int)[] a = [1, 2, 3];
>> writeln(a);
>>
>> works with 2.056.
>
> That is like saying
>
> void foo(int[] a){...}             // prints a
> void bar(immutable(int)[] a){...}  // prints a
>
> int[] a = [1,2,3];
> immutable(int)[] b = [1, 2, 3];
> foo(a);
> bar(b);
>
> "=> Oh, bar is const correct because I can call foo with mutable data  
> and bar with immutable data."
>
> foo is writeln!(int[])
> bar is writeln!(immutable(int)[])
>
> in effect, if you do:
>
> writeln("hello".dup);
>
> The compiler cannot assume that the IFTI'd writeln!(char[]) will not  
> change the argument, ergo it cannot optimize away the .dup, even though  
> it would be a valid transformation as long as the programmer does not  
> make the program semantics depend on the identity relation on immutable  
> references (doing so defeats the purpose of immutability).

writeln is not contractually const correct, but that's only because most  
of D is not const correct either.  For example, Object.toString is not  
const, so if you const-ified all writeln args, you couldn't print  
objects.  But writeln itself does not change any data (a rogue toString  
might change data, but that is not common practice).

Once D becomes const correct, writeln *can* apply const to all it's  
parameters.

>> If the data is stored in ROM, it should be typed as immutable. If it's
>> not, then it could be modified. The only other option is heap allocation
>> and construction on use, which I've already said is undesirable.
>>
>> If we start from "all array literals and enums that contain references
>> store the referenced data in ROM," then we will find ways to deal with
>> any inconveniences. It's all a matter of what's more important in a
>> system language, performance or convenience.
>
> Both are more important. It is D.
> Everything you need to do is make the enum static immutable instead.
> D is also a scripting language and an application programming language.
>
> auto a = [new Foo, new Bar, new Qux]; // I want that to work.

auto a = array(new Foo, new Bar, new Qux);

The one case which is difficult to do is initializing a fixed-size array  
with a literal that uses runtime data.  I suppose we'd need a function  
that returns a fixed-sized array made of its arguments, and doing the init  
builds it in place.  i.e.:

Object[3] objs = array_fixed(new Foo, new Bar, new Qux);

would not do any moving of references, it would construct the fixed sized  
array in-place.  Initializing fixed sized arrays with array literals  
already needs attention anyway.

-Steve


More information about the Digitalmars-d-learn mailing list