Thread overview
[Issue 24837] Can't version() or static if() to include keys in an enum
Oct 29
apham
October 29
https://issues.dlang.org/show_bug.cgi?id=24837

Jonathan M Davis <issues.dlang@jmdavisProg.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |issues.dlang@jmdavisProg.co
                   |                            |m
         Resolution|---                         |DUPLICATE

--- Comment #1 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
I would _love_ to be able to do this, but Walter's response has been what it often is with version-related stuff - that duplicating the whole thing is less error-prone and avoids the huge mess that you often get with #ifdefs in C/C++.

*** This issue has been marked as a duplicate of issue 9761 ***

--
October 29
https://issues.dlang.org/show_bug.cgi?id=24837

Max Samukha <maxsamukha@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |maxsamukha@gmail.com

--
October 29
https://issues.dlang.org/show_bug.cgi?id=24837

--- Comment #2 from Max Samukha <maxsamukha@gmail.com> ---
(In reply to Jonathan M Davis from comment #1)
> I would _love_ to be able to do this, but Walter's response has been what it often is with version-related stuff - that duplicating the whole thing is less error-prone and avoids the huge mess that you often get with #ifdefs in C/C++.
> 
> *** This issue has been marked as a duplicate of issue 9761 ***

What's next? Ban 'if's because a programmer can abuse them? I recently had to port a >500 member C enum and resort, again, to string mixins to work around this poorly justified limitation.

--
October 29
https://issues.dlang.org/show_bug.cgi?id=24837

--- Comment #3 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
(In reply to Max Samukha from comment #2)
> (In reply to Jonathan M Davis from comment #1)
> > I would _love_ to be able to do this, but Walter's response has been what it often is with version-related stuff - that duplicating the whole thing is less error-prone and avoids the huge mess that you often get with #ifdefs in C/C++.
> > 
> > *** This issue has been marked as a duplicate of issue 9761 ***
> 
> What's next? Ban 'if's because a programmer can abuse them? I recently had to port a >500 member C enum and resort, again, to string mixins to work around this poorly justified limitation.

The best one to explain Walter's stance would be Walter, but from what I understand, he's of the opinion that #ifdefs in C/C++ are routinely misused and result in an unmaintainable mess - in large part because of boolean logic, which is why version statements don't have boolean logic.

And when it comes to stuff like differences in OS-specific declarations, he's of the opinion that the least error-prone approach is to duplicate them all for each OS rather than do something like is discussed here. Even the symbols that are the same across multiple OSes typically end up with their own, separate declarations in druntime. Of course, in many cases, they actually differ slightly, and combining them wouldn't work anyway, but he wants each OS to be distinct so that you get errors on other OSes which haven't had those symbol bindings added yet rather than getting something that might be wrong. Honestly, I'm kind of surprised that he ever agreed to the Posix version identifier, but that was probably based on the idea that POSIX-specific symbols were standardized and could be declared that way (when in reality, there's enough leeway in the standard that you still need separate declarations; typically, at best, you can make it so that the code calling POSIX functions is shared across OSes; the declarations typically couldn't be even if you wanted to).

This is a position that Walter has been adamant on for years, and I wouldn't expect it to change.

Of course, in many cases, you can work around the issue with static ifs (and people frequently do), and there are cases where people will refuse to duplicate code and will do stuff like use string mixins like you're talking about. But Walter sees such as bad code and wants to discourage it.

Runtime stuff such as if statements do not have anywhere near the same level of issues as #ifdefs do, and we really have no choice but to have them. So no, Walter isn't going to look to ban them, but there are plenty of other cases in the language where problematic stuff has been banned. You can't have an if statement or loop with ; for a body precisely because it's error-prone (and it only saves you a single token over {}). We no longer have implicit fallthrough on case statements unless they're empty. There are errors with regards to variables shadowing one another inside a function in order to prevent bugs with those. The list goes on. In cases where Walter decided that he could prevent common bugs and encourage good code without actually restricting what you can do with the language, he's done it (and he's done it in cases where others have convinced him that it was a good idea). Naturally, there won't be complete agreement on such features, and sometimes, his choices are going to annoy people.

Personally, I think that in many cases, duplicating declarations is very much the right call, since it makes it much less likely to accidentally have a symbol that only works on a single OS versioned for multiple OSes. But it does sometimes get annoying how much code duplication you end up with in bindings.

However, with regards to enum declarations, I very much wish that we could use version statements or static ifs. I think that that particular case is different enough that the risk is worth the reduced code duplication. But Walter doesn't agree, and he's rejected the idea whenever he's responded to it.

--
October 29
https://issues.dlang.org/show_bug.cgi?id=24837

--- Comment #4 from anonymous4 <dfj1esp02@sneakemail.com> ---
Note there's no such versioning in other OSes, they just declare everything without caring what was in older versions and what was in recent versions, only man pages document it sometimes.

--
October 29
https://issues.dlang.org/show_bug.cgi?id=24837

apham <apz28@hotmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |apz28@hotmail.com

--- Comment #5 from apham <apz28@hotmail.com> ---
If D supports this extension (similar to class) as below

enum FILE_INFO_BY_HANDLE_CLASS_BASE
{
    FileBasicInfo,
    FileStandardInfo,
    FileNameInfo,
    FileRenameInfo,
    FileDispositionInfo,
    FileAllocationInfo,
    FileEndOfFileInfo,
    FileStreamInfo,
    FileCompressionInfo,
    FileAttributeTagInfo,
    FileIdBothDirectoryInfo,
    FileIdBothDirectoryRestartInfo,
    FileIoPriorityHintInfo,
    FileRemoteProtocolInfo,
    FileFullDirectoryInfo,
    FileFullDirectoryRestartInfo,
}

enum FILE_INFO_BY_HANDLE_CLASS_NTDDI_WIN8 :
enum(FILE_INFO_BY_HANDLE_CLASS_BASE)
{
    FileStorageInfo,
    FileAlignmentInfo,
    FileIdInfo,
    FileIdExtdDirectoryInfo,
    FileIdExtdDirectoryRestartInfo,
}

enum FILE_INFO_BY_HANDLE_CLASS_NTDDI_WIN10_RS1 :
enum(FILE_INFO_BY_HANDLE_CLASS_NTDDI_WIN8)
{
    FileDispositionInfoEx,
    FileRenameInfoEx,
}

enum FILE_INFO_BY_HANDLE_CLASS_NTDDI_WIN10_19H1 :
enum(FILE_INFO_BY_HANDLE_CLASS_NTDDI_WIN10_RS1)
{
     FileCaseSensitiveInfo,
     FileNormalizedNameInfo,
}

static if (NTDDI_VERSION >= NTDDI_WIN10_19H1)
{
    enum FILE_INFO_BY_HANDLE_CLASS :
enum(FILE_INFO_BY_HANDLE_CLASS_NTDDI_WIN10_19H1)
    {
        MaximumFileInfoByHandleClass
    }
}
else static if (NTDDI_VERSION >= NTDDI_WIN10_RS1)
{
    enum FILE_INFO_BY_HANDLE_CLASS :
enum(FILE_INFO_BY_HANDLE_CLASS_NTDDI_WIN10_RS1)
    {
        MaximumFileInfoByHandleClass
    }
}
else static if (NTDDI_VERSION >= NTDDI_WIN8)
{
    enum FILE_INFO_BY_HANDLE_CLASS : enum(FILE_INFO_BY_HANDLE_CLASS_NTDDI_WIN8)
    {
        MaximumFileInfoByHandleClass
    }
}
else
{
    enum FILE_INFO_BY_HANDLE_CLASS : enum(FILE_INFO_BY_HANDLE_CLASS_BASE)
    {
        MaximumFileInfoByHandleClass
    }
}

--