May 23, 2013
On 5/23/13, Vladimir Panteleev <vladimir@thecybershadow.net> wrote:
> 2) it doesn't know which file is the "main"
> program file (the file which must be present for the test script
> to succeed), if there is one.

Does https://github.com/D-Programming-Language/dmd/pull/1732 help? It was merged a while back.
May 23, 2013
On Thursday, 23 May 2013 at 13:01:25 UTC, Don wrote:
> I don't think it's legal in C++:
>
> struct S
> {
>   const int x = 5;
> };
>
> w.cpp:4:17: error: ISO C++ forbids initialization of member ‘x’ [-fpermissive]

That is legal C++11 code. The non-static data member initializer (=5) simply adds an implicit entry (if not present) for that particular data member to each constructor initialization list. Thus, the struct S above is the same as:

struct S
{
    const int x;

    S() : x (5) { }
};

The fact that the field is const doesn't play any significant role here.
May 23, 2013
On 05/23/13 23:06, Steven Schveighoffer wrote:
> On Thu, 23 May 2013 16:42:30 -0400, Artur Skawina <art.08.09@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@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
May 24, 2013
On 5/23/2013 2:05 AM, Don wrote:
> NO NO NO NO. I am violently opposed to this release.
>
> This beta contains the worst language misfeature of all time. It's silently
> snuck in under the guise of a bugfix.

Don has an excellent point. His case is bolstered by this causing Tango2 to fail to compile with error messages that have no obvious relationship with this change.

Worse, as Don points out, this can result in silent breakage. Not everyone writes code that is 100% tested, and shipping code that no longer works would make someone justifiably very upset.

The -transition=field detects such cases, but the user will not necessarily know to run it.

So, I agree with Don. As it is, this is unacceptable, despite my agreement that it does make the language better. Therefore, I propose the following addition of a warning:

------------------------------
   const int q = 5;

Warning: const field with initializer should be static or enum.
------------------------------

Over time, this can be upgraded to a deprecation and then an error.

After a suitably long period of time as an error, then we can allow it with the new behavior.


May 24, 2013
On 5/23/2013 1:22 AM, Jacob Carlborg wrote:
> On 2013-05-23 09:08, Walter Bright wrote:
>
>> Is this the case with previous zips, or is it new for this one?
>
> Never mind. It was my tool. I tried a different one and it's not executable there.
>

Phew!
May 24, 2013
On Thu, 23 May 2013 19:03:25 -0400, Artur Skawina <art.08.09@gmail.com> wrote:

> On 05/23/13 23:06, Steven Schveighoffer wrote:

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

My example is essentially:

const int x = 0;

It is default initialized to 0, and then the ctor can initialize it to something else.

To say that

const int x = 42;

is different is inconsistent.  Both are consts stored inside each instance, written by the compiler before the ctor is called.  Then the ctor is free to initialize them away from the default.

What you want is a feature that defines a struct field as always a certain value and NOT changeable, even in the ctor.  As far as I know, that does not exist in D, and seems specialized to protocol layouts (normally you do not want to waste memory with a field that never changes and is always known at compile-time).  As the initializer syntax already is taken, you will need a new syntax, or improve the optimizer to be able to prove this is the case.

-Steve
May 24, 2013
On Thu, 23 May 2013 20:01:19 -0400, Walter Bright <newshound2@digitalmars.com> wrote:

> On 5/23/2013 2:05 AM, Don wrote:
>> NO NO NO NO. I am violently opposed to this release.
>>
>> This beta contains the worst language misfeature of all time. It's silently
>> snuck in under the guise of a bugfix.
>
> Don has an excellent point. His case is bolstered by this causing Tango2 to fail to compile with error messages that have no obvious relationship with this change.
>
> Worse, as Don points out, this can result in silent breakage. Not everyone writes code that is 100% tested, and shipping code that no longer works would make someone justifiably very upset.
>
> The -transition=field detects such cases, but the user will not necessarily know to run it.

What about making it an error UNLESS you pass a compiler flag.  The user will be informed, and the new behavior (which I find useful) is possible.

-Steve
May 24, 2013
Walter Bright:

> Therefore, I propose the following addition of a warning:
>
> ------------------------------
>    const int q = 5;
>
> Warning: const field with initializer should be static or enum.
> ------------------------------
> Over time, this can be upgraded to a deprecation and then an error.
>
> After a suitably long period of time as an error, then we can allow it with the new behavior.

Given the current rate of DMD releases this change path will take a good amount of time.

In the next weeks I suggest to write down the most complete as possible list of desired or expected breaking language changes, and start performing them as early as possible (like during the development of dmd 2.064).

Packing all (or most) of such changes in parallel (instead one after the other along successive compiler versions, as it's mostly currently done) will reduce code breakages later or much later. Bugzilla contains several of such issues (often they are enhancement requests). If we fix only 3-5 every year, D will take many more years to ""stabilize"".

----------------------

Steven Schveighoffer:

> What about making it an error UNLESS you pass a compiler flag.  The user  will be informed, and the new behavior (which I find useful) is possible.

This idea seems able to significantly speed up the transition.

Bye,
bearophile
May 24, 2013
On 5/23/2013 5:35 PM, Steven Schveighoffer wrote:
> What about making it an error UNLESS you pass a compiler flag.  The user will be
> informed, and the new behavior (which I find useful) is possible.

While that idea has significant merit, I oppose it on the following grounds:

1. It forces a very abrupt change. We've followed a policy of gradual change, giving people plenty of time to adapt their codebase. This does not.

2. Having optional errors like that leads to unfortunate problems inside generic code that tests whether some constructs compile or not.
May 24, 2013
On 5/23/13 8:56 PM, Walter Bright wrote:
> On 5/23/2013 5:35 PM, Steven Schveighoffer wrote:
>> What about making it an error UNLESS you pass a compiler flag. The
>> user will be
>> informed, and the new behavior (which I find useful) is possible.
>
> While that idea has significant merit, I oppose it on the following
> grounds:
>
> 1. It forces a very abrupt change. We've followed a policy of gradual
> change, giving people plenty of time to adapt their codebase. This does
> not.

I don't understand this. It's change under 100% user control.

> 2. Having optional errors like that leads to unfortunate problems inside
> generic code that tests whether some constructs compile or not.

The warning has the same problem.

I'm not seeing a comparison between the warning and the opt-in, but instead weak arguments against the opt-in and no comparison with the warning.


Andrei