Skip to content

Conversation

@LemonBoy
Copy link
Contributor

The value of an EnumMember is given by its AssignExpression. If there is no AssignExpression and it is the first EnumMember, its value is the .init property of the EnumMember's type.

@dlang-bot
Copy link
Contributor

dlang-bot commented Mar 10, 2018

Thanks for your pull request and interest in making D better, @LemonBoy! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the annotated coverage diff directly on GitHub with CodeCov's browser extension
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub fetch digger
dub run digger -- build "master + dmd#7996"

@thewilsonator
Copy link
Contributor

This changes the value of a in and subsequently causes b to give an error. This is the cause of the Semaphore failure.

enum X : char
{
    a,
    b
}

ditto for wchar and dchar.

@ibuclaw ibuclaw self-assigned this Mar 11, 2018
@LemonBoy
Copy link
Contributor Author

I see, the use of float as base type also gives different results since float.init is NaN.
I wonder how many dub packages are broken by this change, the testing pipeline shows a single case so far.

@wilzbach
Copy link
Contributor

I wonder how many dub packages are broken by this change, the testing pipeline shows a single case so far.

According to Jenkins (the project tester) this triggers a segfault in libasync.

@wilzbach
Copy link
Contributor

Also fails in Phobos with:

std/stdio.d(3818): Error: enum member `std.stdio.__unittest_L3808_C9.EC.B` initialization with `EC.A+1` causes overflow for type `char`

@marler8997
Copy link
Contributor

@LemonBoy
Copy link
Contributor Author

Hmm, this change may end up breaking some stuff...let's do a deprecation cycle first (or add some warnings/errors) ?

@wilzbach
Copy link
Contributor

let's do a deprecation cycle first (or add some warnings/errors)

Warnings are often set to errors in some downstream projects, so deprecations are probably better here.

@WalterBright
Copy link
Member

It clearly will need a deprecation cycle. If defaultInitLiteral does not return 0, then issue the deprecation.

@WalterBright WalterBright changed the title Initialize the enum as written in the specification Fix Issue 18578 - First enum value assigned 0 instead of EnumBaseType.init Mar 26, 2018
@WalterBright
Copy link
Member

Please include test case from https://github.com/dlang/dmd/pull/8090/files

@LemonBoy LemonBoy force-pushed the enum-init branch 4 times, most recently from 21fad14 to 6181a6f Compare March 27, 2018 16:24
@LemonBoy
Copy link
Contributor Author

I've rebased this on top of #8090, what's missing is to adjust the failures in phobos.

@marler8997
Copy link
Contributor

This PR should fix the phobos issues: dlang/phobos#6368

@n8sh
Copy link
Member

n8sh commented Mar 28, 2018

Maybe it would be better to change the language specification than to change this, because this utterly breaks for floating point types. See further on in the specification:

If there is no AssignExpression and it is not the first EnumMember, it is given the value of the previous EnumMember+1. If the value of the previous EnumMember is EnumBaseType.max, it is an error. If the value of the previous EnumMember+1 is the same as the value of the previous EnumMember, it is an error. (This can happen with floating point types.)

So you'll get an enum whose every member is NaN or just a compile-time error, depending on which kind of equality is meant by "the same as".

It also breaks for any char enum with more than one member, since char.max is char.init. Same for wchar.

@marler8997
Copy link
Contributor

marler8997 commented Mar 28, 2018

Yeah maybe there is a better way to define how enum values are determined. However, we are talking about a case that doesn't make much sense in the first place, i.e.

enum Foo : float
{
    a, b
}

What would you expect the value of a and b to be? This is such an odd usage of enums that having them default to NaN may actually be fine since this doesn't really make sense in the first place. You could make a case for the char type...but I can't really think of a use case where you would use char as a base type for an enum...

@n8sh
Copy link
Member

n8sh commented Mar 28, 2018

This is such an odd usage of enums that having them default to NaN may actually be fine since this doesn't really make sense in the first place.

That is worse than failing to compile IMO.

@marler8997
Copy link
Contributor

That is worse than failing to compile IMO.

Maybe...having all the members of an enum default to the same values does sound counter-intuitive to what an enum does, namely, enumerate a set of values. But I can't think of a use case where you would ever enumerate a set of values where float is the base type, unless you were explicitly assigning values to them, can you?

@marler8997
Copy link
Contributor

Oh wait...I think I misunderstood you a bit. I guess you were saying it would be better to fail in this case rather than assigning every value to NaN. Yes I agree that failing in that case would be better.

@JackStouffer
Copy link
Contributor

Please don't forget to update dlang.org's deprecation page as well. Please see dlang/DIPs#108 for an in draft process for deprecations of this nature.

@RazvanN7
Copy link
Contributor

ping @LemonBoy . what's the status on this?

Let's deprecate this behaviour that, according to the specification, is
incorrect.
Builds up on dlang#8090.
@thewilsonator
Copy link
Contributor

@RazvanN7 status is rebased and green.

{
deprecation(em.loc,
"Enum `%s` has base type `%s` with non-zero .init; " ~
"initialize the enum member explicitly",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message should indicate why. Namely that the default value will change in a later release.
Also, there's no changelog entry.

@Geod24
Copy link
Member

Geod24 commented Nov 22, 2018

Removed auto-merge to give time to address feedback. I think it's important to tell the user why they need to take a certain action when something is deprecated. Also, deprecations need a changelog entry.

@n8sh
Copy link
Member

n8sh commented Nov 22, 2018

I urge you all again to reconsider this. "The first element of an enum with base type T defaults to T.init" is very reasonable. "For every T, T.init should be an invalid value if possible" is reasonable. But combining the two leads to something very unreasonable.

Removed auto-merge to give time to address feedback. I think it's important to tell the user why they need to take a certain action when something is deprecated. Also, deprecations need a changelog entry.

This is going to break existing code. People will right ask why a char enum's first element being 0xff is useful or helps anyone write better programs. This new behavior is a bear trap.

@Geod24
Copy link
Member

Geod24 commented Nov 22, 2018

People will right ask why a char enum's first element being 0xff is useful or helps anyone write better programs.

At the same time, I don't think enums based on char are that common. Why wouldn't you use [u]byte instead ? The language does support it, but it's by no means a first class citizen.

@WalterBright
Copy link
Member

I suspect we should just fix the spec to match the behavior. This won't break existing code, and seems to be what people expect anyway.

@marler8997
Copy link
Contributor

Write a DIP

@thewilsonator
Copy link
Contributor

@WalterBright in reality this affects enums of char, wchar, dchar, float double and real none of which enums of are particularly common nor useful. OTOH for char, it is what C would do. Please confirm that you want to change the spec, I don't think a DIP is necessary for this, this is making the spec match the implementation.

Note that the special enum __c_wchar_t seems to already have this behaviour without this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.