Mutable enums

Steven Schveighoffer schveiguy at yahoo.com
Wed Nov 16 05:22:52 PST 2011


On Tue, 15 Nov 2011 13:45:02 -0500, Timon Gehr <timon.gehr at gmx.ch> wrote:

> On 11/15/2011 04:53 PM, Steven Schveighoffer wrote:

>> Yes, but this is spelled out because copying a static array requires
>> moving data. However, this does *not* require a hidden allocation (even
>> though it does do a hidden allocation currently).
>>
>> I'm not worried about copying data as much as I am about hidden
>> allocations. Hidden allocations are a huge drag on performance. Every
>> time you allocate, you need to take a global GC lock, and it's an
>> unbounded operation (doing one allocation could run a collection cycle).
>
> You don't actually _need_ a global GC lock. It is just how it is  
> implemented in this case.

This is all fine in theory.  I haven't seen any implementations.  But  
memory allocations are not cheap, even without a GC lock.

> 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.

>> That is the idea. Get rid of the hidden allocation. Writeln *is* const
>> correct, it can certainly print immutable(int)[].
>
> 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.

>> The issue is not
>> writeln, it's what the type of the array literal/enum is.
>>
>
>> Technically, an array literal is equivalent to an enum, and should
>> follow the same rules.
>>
>
> Remember that immutable is transitive. That can really get in your way  
> in this case.

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.

>> What about this idea:
>>
>> At a global level, expressions that result in CTFE being triggered, can
>> be implicitly cast from mutable to immutable and vice versa via a
>> deep-dup. This allows you to use enums as parameters to functions
>> accepting mutable references. Then enums that are derived from other
>> enums do not need to follow the same rules as runtime code that uses the
>> enums.
>>
>> This of course, only happens at the global-expressions level, as
>> function internals must compile at runtime as well.
>>
>> What I thought of as a solution was to create CTFE only functions that
>> wrap other functions to do a dup. But you wouldn't want to do this
>> during runtime, because dup is expensive. During compile time, dup costs
>> nothing. This idea essentially takes the place of that boilerplate code.
>
>
> That could work, but I think this is cluttering up the semantics a bit.

It's just a shortcut.  In essence, during compile time execution, .dups  
are added for you because they are free.  During runtime, they are not  
free, so you must add them.

-Steve


More information about the Digitalmars-d-learn mailing list