dmd 2.063 beta 5

Steven Schveighoffer schveiguy at yahoo.com
Thu May 23 14:06:57 PDT 2013


On Thu, 23 May 2013 16:42:30 -0400, Artur Skawina <art.08.09 at gmail.com>  
wrote:

> On 05/23/13 18:26, Steven Schveighoffer wrote:
>> On Thu, 23 May 2013 11:36:00 -0400, Artur Skawina <art.08.09 at gmail.com>  
>> wrote:
>>
>>> If it wasn't clear - it is about the _language_, not what some compiler
>>> currently happens to do. Being able to mutate /initialized/ immutables
>>> is a bad idea. IOW you should not be able to modify 'Packet.type'  
>>> above.
>>
>> The immutable isn't initialized.  The memory it happens to be using  
>> before initialization happens to have the '7' bit pattern in it.
>>
>> Once it is initialized, I agree it should be immutable from that point  
>> on.
>
> It's all about the definition. Again, I'll point out that the code that  
> we're
> talking about here *can not* exist right now - until now the compiler  
> has not
> allowed mutation.

compiles:

struct S
{
    const int x;
    this(int n)
    {
	x = n;
    }
}

> So this is about a /change/ to the language, and isn't really
> related to fixing that implicit-static bug - it's just that once that  
> change
> is made it then becomes possible to support the in-ctor re-initialization
> of immutable fields. Which isn't really all that useful, but carries a  
> cost.

The change to the language allows something that wasn't easily allowed  
before -- defining the pre-initialization bit pattern that is blitted to  
the const member.  Until now, the only way to have a const member that is  
ctor-initialized is to make it have the default bit pattern for that type.

Hm... I just figured out something interesting.  We can mimic the "new"  
behavior in old compilers by creating a type that has a different default  
initialization:

import std.stdio;
struct myInt
{
    int x = 7;
}

struct S
{
    const myInt m;
    this(int n)
    {
        m.x = n;
    }
}

void main()
{
    S s;
    auto s2 = S(5);
    writefln("%d %d", s.m.x, s2.m.x");
}

Output on 2.061:
7 5

>>> Keep in mind that modifying Packet.type is illegal /right now/. Even  
>>> from
>>> a ctor or static-ctor. This does not need to change when such fields  
>>> are
>>> no longer always implicitly static. While allowing re-initialization
>>> of immutables from a ctor is possible, it does not really give you  
>>> much,
>>> while weakening const. (eg by making CT evaluation of such fields  
>>> impossible).
>>
>> That's an issue of where Packet.type lives.  It doesn't live inside an  
>> instance right now, in the new version it does.
>>
>> If Packet.type is not given an initializer, it's inside the instance  
>> and it (correctly IMO) can be modified inside a ctor until it is used.
>>
>> These rules are perfectly consistent.
>>
>> I don't see how they make CT evaluation impossible.
>
> The old way meant that the value was statically known and could be  
> accessed at CT.

And it still can, as long as you *properly* declare it as static (as it  
should have been).

> Allowing ctors to modify the fields means that the compiler can not make  
> any
> assumptions about the value. [1] Which affects CT and constant  
> folding/propagation
> etc.

And it shouldn't be able to on a value that is different for every  
instance, but constant for that instance.  However, it can make  
assumptions based on the fact that it can't change.  For example:

writeln(x.constmember);
....
auto n = x.constmember + 5; // can assume constmember is the same as  
before.

> For example you couldn't then do this:
>
> struct Packet(uint TY) { /*...*/immutable uint type=TY; immutable ubyte  
> len=PLen(TY); /*...*/ }
> auto PProcess(PT)(PT* p) { static if (p.type<128) if (p.type==42)  
> sendp(p, p.len*4); }

static if(TY < 128) if(TY == 42) ....

> Even w/o the static-if it would be much less efficient. Yes, there are  
> other
> ways to achieve a similar effect, but they are significantly more  
> complicated.

No, you are using the WRONG tool for the job.  If you want to make  
compile-time decisions, don't use run-time constants.

> The most conservative approach is to initially disallow mutation from  
> ctors - this
> restriction can always be lifted later and doing so does not affect any  
> existing
> program.
> Treating 'const' differently from 'immutable' is also a possibility, and  
> could
> be a future option.

It's already allowed.  Disallowing it would break code.

> Then there's the issue of 'immutable one=1;' being very misleading; it  
> certainly
> would be misinterpreted often enough (by assuming that ODR applies here).

use enum for compile-time constants, or static if you need an addressable  
constant.  There is no loss of functionality here, only gains.

> [1] BTW, I'm wondering if these changes also affect module-level  
> const/immutable
>     members... No DMD here to test, though.

Of course not, there is no changing of what is const and what is not.  All  
that is changing is whether a default-initialized member becomes a static  
member or not.  The original rules as to when a const value can be  
initialized still apply.

-Steve


More information about the Digitalmars-d-announce mailing list