June 06, 2021

On Sunday, 6 June 2021 at 14:05:54 UTC, Jack Applegame wrote:

>

On Sunday, 6 June 2021 at 13:21:35 UTC, Mathias LANG wrote:

>

It might, e.g. the following:

enum DEFAULT = foo();
char[] foo () { return null; }
void bar (char[] arg = DEFAULT);

Mutable enum??? WAT?
It's absolutely unacceptable.

char[] foo() @safe { return "hello".dup; }
enum WAT = foo();
void main() @safe {
    WAT[0] = 'w';
    writeln(WAT);
}
Error: program killed by signal 11

This is... interesting. I did a bit of digging in memory and the code was actually using int[] (or at least, not char[]), so it was something like this:

import std.stdio;
int[] foo() @safe { return [42, 42, 42]; }
enum WAT = foo();
void main() @safe {
    bar();
}
void bar(int[] data = WAT) @safe
{
    data[0] = 84;
    writeln(data);
    writeln(WAT);
}

The above works as expected (at least, as I would expect). However, change the type to char[] and it SEGV. That's probably because string literals are special and the compiler makes some (bad) assumptions.

However, the compiler shouldn't allow you to use an enum as an lvalue. It used to be able to recognize this, but it broke at some point after v2.080.0.

June 06, 2021

On Sunday, 6 June 2021 at 15:05:47 UTC, Mathias LANG wrote:

>
import std.stdio;
int[] foo() @safe { return [42, 42, 42]; }
enum WAT = foo();
void main() @safe {
    bar();
}
void bar(int[] data = WAT) @safe
{
    data[0] = 84;
    writeln(data);
    writeln(WAT);
}

The above works as expected (at least, as I would expect). However, change the type to char[] and it SEGV. That's probably because string literals are special and the compiler makes some (bad) assumptions.

It's definetly a code smell.
Here are much better solutions:

char[] foo() pure { return "hello".dup; }
immutable DEFAULT = foo();

void bar(char[] data = DEFAULT.dup) {
    data[0] = '1';
    // DEFAULT[0] = '2'; Error: cannot modify `immutable` expression `DEFAULT[0]`
    writeln(data);
    writeln(DEFAULT);
}

It uses explicit copying instead of the undocumented "feature" of the enum.

Or just use function directly

char[] DEFAULT() pure { return "hello".dup; }

void bar(char[] data = DEFAULT) {
    data[0] = '1';
    DEFAULT[0] = '2';
    writeln(data);
    writeln(DEFAULT);
}

// works too
void baz(string data = DEFAULT) {}
June 07, 2021

On Sunday, 6 June 2021 at 10:47:54 UTC, Mathias LANG wrote:

>

On Sunday, 6 June 2021 at 10:40:13 UTC, Jack Applegame wrote:

>

That's not enough. Let's deprecate any use of enum as a manifest constant.

I wouldn't go that far. enum are like #define, and there are cases where you want them. E.g. when using them as define arguments:

void foo (char[] fmt = DEFAULT_VALUE) { /* ... */ }

Yes, and if the memory layout is like in C, I would expect 'immutable' variables to be addressable (in RO data segment), but not 'enum' constants (which would be simple rvalues, probably directly used as-is in assembly instructions).

June 07, 2021
On 6/6/21 11:05 AM, Mathias LANG wrote:
> On Sunday, 6 June 2021 at 14:05:54 UTC, Jack Applegame wrote:
>> On Sunday, 6 June 2021 at 13:21:35 UTC, Mathias LANG wrote:
>>> It *might*, e.g. the following:
>>> ```D
>>> enum DEFAULT = foo();
>>> char[] foo () { return null; }
>>> void bar (char[] arg = DEFAULT);
>>> ```
>>
>> Mutable enum??? WAT?
>> It's absolutely unacceptable.
>>
>> ```d
>> char[] foo() @safe { return "hello".dup; }
>> enum WAT = foo();
>> void main() @safe {
>>     WAT[0] = 'w';
>>     writeln(WAT);
>> }
>> ```
>> ```shell
>> Error: program killed by signal 11
>> ```
> 
> This is... interesting. I did a bit of digging in memory and the code was actually using `int[]` (or at least, not `char[]`), so it was something like this:
> ```D
> import std.stdio;
> int[] foo() @safe { return [42, 42, 42]; }
> enum WAT = foo();
> void main() @safe {
>      bar();
> }
> void bar(int[] data = WAT) @safe
> {
>      data[0] = 84;
>      writeln(data);
>      writeln(WAT);
> }
> ```
> 
> The above works as expected (at least, as *I* would expect). However, change the type to `char[]` and it SEGV. That's probably because string literals are special and the compiler makes some (bad) assumptions.

Yeah, I can get it to work if I use an array literal of characters:

```d
enum char[] WAT = [42, 42, 42];
// or
char[] foo() @safe { return [42, 42, 42]; }
enum WAT = foo();
```

but if you use .dup on it, then it treats it like a string literal, e.g. instead of allocating a new array, it points at the same array (apparently in the RO segment)

This doesn't happen with an integer array (it's always reallocated on every call).

Seems like this behavior started with 2.066.

-Steve
July 09, 2021

On Sunday, 6 June 2021 at 15:05:47 UTC, Mathias LANG wrote:

> >

Mutable enum???
It's absolutely unacceptable.

    WAT[0] = 'w';
}

However, the compiler shouldn't allow you to use an enum as an lvalue.

It doesn't, at least when taking the statement by word. The thing being an lvalue here is WAT[0], not WAT. It gets clearer when a function f returns an array (by value, of course); then, f()[0] is an lvalue, despite f() not being one. Dynamic array elements always have an address, they're always lvalues. The statement [1, 2, 3][1] = 2; type-checks, compiles (as it should, albeit nonsensical) -- and considering that enums are named literals, WAT[1] = 2; isn't much different.

There's nothing stopping you from typing an enum immutable:

enum immutable(int[]) WAT = [1, 2, 3];

Will refuse to have its elements assigned by virtue of immutable.

1 2
Next ›   Last »