dmd 2.063 beta 5

Artur Skawina art.08.09 at gmail.com
Thu May 23 16:03:25 PDT 2013


On 05/23/13 23:06, Steven Schveighoffer wrote:
> 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;
>    }
> }

It's the 'const int x = 42;' case we're talking about. *That* one does not
compile and doesn't need to. It /could/, but I see no reason to allow this;
the one use case of default init that can be overridden by a ctor is not
enough, not even close.

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

Yes, obviously. It's less convenient, but does not have the problems of a
"run-time-immutable".


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

Umm, no. It *can not* be static. Yes, you can create a proxy enum - it's how
it's done today, because there is no better way, but that means you then have to
handle it manually and the compiler does not get a chance to optimize based on
the static info.

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

The whole point is that the value *isn't* different for any instance. If it /is/
then just omit the initializer and use the ctor(s). You can still have custom
defaults, using the approach you mentioned above.


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

I'm using *exactly* the right tool. What you are suggesting is a work-around for
a language limitation. Which isn't necessary; it's perfectly fine to tell the
compiler 'this field is truly immutable and it's value is always X'. In fact
that's how it used to be, except that the compiler wrongly omitted such fields
when laying out the object. Fixing that does not automatically mean that they
have to be become less constant.


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

Can you show an example where assigning to an already *initialized* immutable
variable is allowed?...
Of course, except the one case we're discussing - inside a ctor (where it should
be (made) illegal, and the argument is only about whether this is a language or
implementation bug).


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

The question is about things like being able to evaluate them at CT, mutate from
mod ctors etc. Changes at the module level have other implications, for example
for cyclic RT mod ctor deps.

artur


More information about the Digitalmars-d-announce mailing list