www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - Allow Conditional Compilation Inside Enum Declaration

reply IchorDev <zxinsworld gmail.com> writes:
To declare an enum type that may or may not have one or more 
members depending on conditional compilation statements requires 
duplicating the entire enum:
```d
static if(cond){
	enum A{
		x,y,z,w,
	}
}else{
	enum A{
		x,y,z,
	}
}
```

For an enum type with many members—or many conditionals—this 
quickly becomes an insane amount of repetition.

The logical solution is to just allow conditional compilation 
statements inside enums:
```d
enum A{
	x,y,z,
     static if(cond){
		w,
	}
}
```
Mar 30
next sibling parent reply monkyyy <crazymonkyyy gmail.com> writes:
On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:
 To declare an enum type that may or may not have one or more 
 members depending on conditional compilation statements 
 requires duplicating the entire enum:
 ```d
 static if(cond){
 	enum A{
 		x,y,z,w,
 	}
 }else{
 	enum A{
 		x,y,z,
 	}
 }
 ```

 For an enum type with many members—or many conditionals—this 
 quickly becomes an insane amount of repetition.

 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
 	x,y,z,
     static if(cond){
 		w,
 	}
 }
 ```
As a specif case or for all lists? Could you do this for functions `foo(static if(bar){1},2)`? is changing the meaning of {} nessery or should it be for single elements? `enum A{x,y,z, static if(cond) w}`
Mar 30
parent reply IchorDev <zxinsworld gmail.com> writes:
On Saturday, 30 March 2024 at 22:34:46 UTC, monkyyy wrote:
 As a [specific] case or for all lists?

 Could you do this for functions `foo(static if(bar){1},2)`?
I’m not sure if that’s really in the scope of this idea. Maybe that could be another proposal?
 is changing the meaning of {} nessery or should it be for 
 single elements?
 `enum A{x,y,z, static if(cond) w}`
I don’t see why that would be necessary? Ideally it should work just like any existing conditional compilation. (e.g. also allowing `version(Something):`, etc.)
Mar 30
next sibling parent monkyyy <crazymonkyyy gmail.com> writes:
On Sunday, 31 March 2024 at 02:36:40 UTC, IchorDev wrote:
 On Saturday, 30 March 2024 at 22:34:46 UTC, monkyyy wrote:
 As a [specific] case or for all lists?

 Could you do this for functions `foo(static if(bar){1},2)`?
I’m not sure if that’s really in the scope of this idea. Maybe that could be another proposal?
 is changing the meaning of {} nessery or should it be for 
 single elements?
 `enum A{x,y,z, static if(cond) w}`
I don’t see why that would be necessary? Ideally it should work just like any existing conditional compilation. (e.g. also allowing `version(Something):`, etc.)
While I can't mimik what the mathy compiler devs will say I'm pretty sure existing static if must be in a very different level of the compiler then enum parsing. One of the bugs I reported was about meta programming enums using user types op overloads (where +1, would be treated as x2 for flags) I think x,y,z,w are fragile order of operation values and any attempt to meta program them would be "you have to go full string mixin and do everything all at once" So in my head this compile time version of if as a code block and ternary if and a version of this feature with the logic "if static condation is met, parse this element to parent node, otherwise skip" that works like the auto flattening of sequences seems more likely
Mar 31
prev sibling parent reply Hipreme <msnmancini hotmail.com> writes:
On Sunday, 31 March 2024 at 02:36:40 UTC, IchorDev wrote:
 On Saturday, 30 March 2024 at 22:34:46 UTC, monkyyy wrote:
 As a [specific] case or for all lists?

 Could you do this for functions `foo(static if(bar){1},2)`?
I’m not sure if that’s really in the scope of this idea. Maybe that could be another proposal?
 is changing the meaning of {} nessery or should it be for 
 single elements?
 `enum A{x,y,z, static if(cond) w}`
I don’t see why that would be necessary? Ideally it should work just like any existing conditional compilation. (e.g. also allowing `version(Something):`, etc.)
My main take against that, is that it would be harder to make it compatible when using libraries. One value could change: ```d enum A { static if(cond) w, x, y, z } ``` And boom! Depending on how you're using, one may: 1. Break 2. Worse: create surprising behavior because, if you use X, it will become Y which is still valid. Although the idea does make sense in some aspects, I fear for the worst
Apr 02
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, April 2, 2024 11:19:54 AM MDT Hipreme via dip.ideas wrote:
 On Sunday, 31 March 2024 at 02:36:40 UTC, IchorDev wrote:
 On Saturday, 30 March 2024 at 22:34:46 UTC, monkyyy wrote:
 As a [specific] case or for all lists?

 Could you do this for functions `foo(static if(bar){1},2)`?
I’m not sure if that’s really in the scope of this idea. Maybe that could be another proposal?
 is changing the meaning of {} nessery or should it be for
 single elements?
 `enum A{x,y,z, static if(cond) w}`
I don’t see why that would be necessary? Ideally it should work just like any existing conditional compilation. (e.g. also allowing `version(Something):`, etc.)
My main take against that, is that it would be harder to make it compatible when using libraries. One value could change: ```d enum A { static if(cond) w, x, y, z } ``` And boom! Depending on how you're using, one may: 1. Break 2. Worse: create surprising behavior because, if you use X, it will become Y which is still valid. Although the idea does make sense in some aspects, I fear for the worst
Well, you can already do that. It's just that you have to wrap the entire enum declaration to do it. Really, this is exactly the same as using static ifs to compile members into a struct or not, which we do all the time. So, there's nothing special here, and the fact that we can't do it with enums regularly causes issues any time that you're dealing with enum declarations that need to vary based on stuff like the OS (both for when the list of enum members needs to change and when the values of those members needs to change depending on the system). Fortunately, most enums aren't in that boat, but it surprises me every time that I run into it. I suspect that enum declarations are the only place in the language where you can put ddoc comments on individual symbols, but you can't actually version those symbols with version statements or static ifs. And it definitely feels inconsistent that we're not allowed to use conditional compilation with their declarations. And yes, it could be abused, but that's no different from any other place that conditional compilation is used to control whether symbols get compiled in or not. - Jonathan M Davis
Apr 02
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:
 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
 	x,y,z,
     static if(cond){
 		w,
 	}
 }
 ```
It's not very elegant, but you can do it with a string mixin: ```d enum string enumMembers = "x, y, z, " ~ (cond ? "w, " : ""); mixin("enum A { " ~ enumMembers ~ " }"); ```
Apr 01
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 4/2/24 00:00, Paul Backus wrote:
 On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:
 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
     x,y,z,
     static if(cond){
         w,
     }
 }
 ```
It's not very elegant, but you can do it with a string mixin: ```d enum string enumMembers = "x, y, z, " ~ (cond ? "w, " : ""); mixin("enum A { " ~ enumMembers ~ " }"); ```
A drawback of this approach is that the enum name is only visible after the mixin has been expanded, which can lead to forward reference issues.
Apr 25
prev sibling next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:
 To declare an enum type that may or may not have one or more 
 members depending on conditional compilation statements 
 requires duplicating the entire enum:
 ```d
 static if(cond){
 	enum A{
 		x,y,z,w,
 	}
 }else{
 	enum A{
 		x,y,z,
 	}
 }
 ```

 For an enum type with many members—or many conditionals—this 
 quickly becomes an insane amount of repetition.

 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
 	x,y,z,
     static if(cond){
 		w,
 	}
 }
 ```
I agree and the idea is not novel, [for example that], from memory it's been seen several times in the NG too. Risk for a DIP on this is that it could get rejected with a rationale such as "you can do that with metaprog, which is the D way". That is more or less what what Paul has replied, if you read under the lines. [for example that]: https://issues.dlang.org/show_bug.cgi?id=9761
Apr 02
parent reply Basile B. <b2.temp gmx.com> writes:
On Tuesday, 2 April 2024 at 17:10:07 UTC, Basile B. wrote:
 On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:
 To declare an enum type that may or may not have one or more 
 members depending on conditional compilation statements 
 requires duplicating the entire enum:
 ```d
 static if(cond){
 	enum A{
 		x,y,z,w,
 	}
 }else{
 	enum A{
 		x,y,z,
 	}
 }
 ```

 For an enum type with many members—or many conditionals—this 
 quickly becomes an insane amount of repetition.

 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
 	x,y,z,
     static if(cond){
 		w,
 	}
 }
 ```
I agree and the idea is not novel, [for example that], from memory it's been seen several times in the NG too. Risk for a DIP on this is that it could get rejected with a rationale such as "you can do that with metaprog, which is the D way". That is more or less what what Paul has replied, if you read under the lines. [for example that]: https://issues.dlang.org/show_bug.cgi?id=9761
forgot to say you can use a struct filled with anonymous enum members too. ```d struct A { enum T x = 0; enum T y = 1; enum T z = 2; static if (cond) enum T w = 3; } ``` However RN I cant confirm that the usage is 100% equivalent. Use of the members is likely but use of the container may not, e.g in std.traits (esp. the EnumMembers template ...).
Apr 02
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, April 2, 2024 11:30:39 AM MDT Basile B. via dip.ideas wrote:
 forgot to say you can use a struct filled with anonymous enum
 members too.

 ```d
 struct A
 {
      enum T x = 0;
      enum T y = 1;
      enum T z = 2;
 static if (cond)
      enum T w = 3;
 }
 ```

 However RN I cant confirm that the usage is 100% equivalent. Use
 of the members is likely but use of the container may not, e.g in
 std.traits (esp. the EnumMembers template ...).
They aren't equivalent at all, because you haven't declared any actual enums. Even though the keyword enum is used, those are all manifest constants within a struct, whereas an enum declaration declares its own type which will be treated as an enum by the type system, and that affects a number of things, including is experessions. For instance, is(A == enum) would be false, and is(A == struct) would be true, whereas if it were an enum declaration, the opposite would be true. Even if the enum's base type were a struct is(E == struct) would still be false, because the enum itself wouldn't be a struct. It would just implicitly convert to its base type which was a struct. Similarly, you can't use final switch with such a struct. You need an actual enum. You also couldn't do something like auto foo(A a) {...} and pass it A.x, because x is a T, not an A. Now, syntactically, such a struct is very similar to an enum declaration, so you can do stuff like A.x, and it would be syntactically the same, but the types would be different, and the way that the type system treats them would be different. So, depending on what you're doing, a struct with a bunch of manifest constants might do the trick, but really, all you're doing is putting a bunch of manifest constants within a namespace. You're not declaring an enum type. - Jonathan M Davis
Apr 02
prev sibling next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, March 30, 2024 8:57:00 AM MDT IchorDev via dip.ideas wrote:
 To declare an enum type that may or may not have one or more
 members depending on conditional compilation statements requires
 duplicating the entire enum:
 ```d
 static if(cond){
   enum A{
       x,y,z,w,
   }
 }else{
   enum A{
       x,y,z,
   }
 }
 ```

 For an enum type with many members—or many conditionals—this
 quickly becomes an insane amount of repetition.

 The logical solution is to just allow conditional compilation
 statements inside enums:
 ```d
 enum A{
   x,y,z,
      static if(cond){
       w,
   }
 }
 ```
Yeah, I'm surprised by this every time that I run into it. I don't think that I've ever tried it with static ifs, since usually, I run into it with an enum where I need to change either the list of enum members and/or their values based on the OS, so I'm trying to use version statements, but it definitely comes up when writing code that has to worry about differences between OSes. For instance, for a socket library, if you have an enum for address families (e.g. inet, inet6, unix, etc.), that list is going to differ depending on the OS. Now, if the entire enum actually needs to only exist on a particular system, then it makes sense that the whole thing would be versioned, but in the cases where you need to change the list of members or their values based on conditional compilation, it's definitely annoying that you're forced to version the entire enum declaration. I'm also pretty sure that this is the only place in the language where you can put ddoc comments on individual symbols, but you can't use conditional compilation for those symbols. It acts like a struct with regards to putting ddoc on its members but then acts like an array literal with regards to conditional compilation and its individual members / elements. So, it definitely has inconsistent behavior with regards to other parts of the language. - Jonathan M Davis
Apr 02
parent reply Kagamin <spam here.lot> writes:
Indeed why not use manifest constants? Especially mouse buttons 
and address families are inherently extensible, because they are 
provided by OS. Variable enum may also force client code to be 
needlessly versioned to cope with members with conditional 
existence.
Oct 26
parent IchorDev <zxinsworld gmail.com> writes:
On Saturday, 26 October 2024 at 08:28:43 UTC, Kagamin wrote:
 Indeed why not use manifest constants?
Read the existing discussion.
Oct 31
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:

 For an enum type with many members—or many conditionals—this 
 quickly becomes an insane amount of repetition.

 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
 	x,y,z,
     static if(cond){
 		w,
 	}
 }
 ```
I don't think static if fits here. There are already special cases for enums which allow things that don't make sense elsewhere when using a declaration list. In particular, requiring the trailing comma is troublesome. I think what might be in order is to elevate enums to a more structured type (like Swift does). Something like: ```d enum ??? foo { case x; case y; case z; // constructors? this(int n) { this._value = cast(foo)n; } // operators? opBinary(...) // static if works at a declaration scope! static if(cond) { case a; } } ``` The ??? is because I'm assuming it would be too ambiguous with existing syntax. Maybe `enum struct`? But enums were basically copied from C (with duct-taped on features), and other modern languages (such as swift) have really considered how enums should be designed. -Steve
Apr 03
next sibling parent reply Daniel N <no public.email> writes:
On Wednesday, 3 April 2024 at 17:57:31 UTC, Steven Schveighoffer 
wrote:
 Something like:

 ```d
 enum ??? foo {
    case x;
    case y;
    case z;
    // constructors?
    this(int n) { this._value = cast(foo)n; }
    // operators?
    opBinary(...)
    // static if works at a declaration scope!
    static if(cond) {
      case a;
    }
 }
 ```

 The ??? is because I'm assuming it would be too ambiguous with 
 existing syntax. Maybe `enum struct`?

 But enums were basically copied from C (with duct-taped on 
 features), and other modern languages (such as swift) have 
 really considered how enums should be designed.

 -Steve
How about inheritance? ```d enum A { x,y,z, } static if(cond) enum B : A { w } else alias B = A; ```
Apr 04
parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 4 April 2024 at 07:39:36 UTC, Daniel N wrote:
 How about inheritance?

 ```d
 enum A
 {
   x,y,z,
 }

 static if(cond)
   enum B : A { w }
 else
   alias B = A;
 ```
Doesn't work the way you'd want it to in this case: ```d enum A { x,y,z, } enum B : A { w } pragma(msg, typeof(B.x)); // A ```
Apr 04
prev sibling parent IchorDev <zxinsworld gmail.com> writes:
On Wednesday, 3 April 2024 at 17:57:31 UTC, Steven Schveighoffer 
wrote:
 I think what might be in order is to elevate enums to a more 
 structured type (like Swift does).

 Something like:

 ```d
 enum ??? foo {
    case x;
    case y;
    case z;
    // constructors?
    this(int n) { this._value = cast(foo)n; }
    // operators?
    opBinary(...)
    // static if works at a declaration scope!
    static if(cond) {
      case a;
    }
 }
 ```

 The ??? is because I'm assuming it would be too ambiguous with 
 existing syntax. Maybe `enum struct`?

 But enums were basically copied from C (with duct-taped on 
 features), and other modern languages (such as swift) have 
 really considered how enums should be designed.

 -Steve
Swift's `enum` is a tagged union. I'd love if we got tagged unions, and the `enum struct` syntax isn't bad either. If D tagged unions could functionally replace enums (i.e. if they could have an arbitrary number of empty cases) then this would be a fine replacement in my opinion. Sadly, no such feature exists yet.
Apr 08
prev sibling next sibling parent Dukc <ajieskola gmail.com> writes:
On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:
 For an enum type with many members—or many conditionals—this 
 quickly becomes an insane amount of repetition.

 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
 	x,y,z,
     static if(cond){
 		w,
 	}
 }
 ```
It would be strange if this was enabled just for `enum`s but not for other listings. Other possibilities that come to mind: ```D auto fun(int a, float b, static if(cond){char c, bool d,}) => //... import std.algorithm, std.range, static if(cond){std.conv,}; pragma(msg, "hello", static if(cond){"world!",}); ``` Also I'm not quite sure of the syntax. When you list something with commas, it resembles an expression, since function argument lists and array literals are also listed with commas and expressions. But in D, you can't use `if` or `static if` as an expression - for that you have the conditional operator `cond ? whenTrue : otherwise`. Could this idea would work better with the conditional operator syntax? ```D enum A{x, y, z, cond? w: ()} ``` On second thought, maybe not. You can't do this inside an array literal either unless you also have a value for the "else" case, and you also can't list multiple values for one condition except by defining another array literal outside the original one and concatenating them. Maybe it's time to let us use `if`s and conditional compilation directives as parts of expressions, so it'd be consistent with your proposal? There's another possibility for enums specifically. This could also be solved if you could define them with `;` separators like you define classes, structs and unions. If you could define an enum by defining an `union` with no non-zero members it'd solve this one and also give the [existing sum type proposals](https://forum.dlang.org/post/zgsewqfmijxycppnjjfp forum.dlang.org) a run for their money.
Apr 03
prev sibling next sibling parent HuskyNator <huskynator protonmail.ch> writes:
Another use case I ran into was stuff like:

```d
enum MouseButton: ubyte {
     static foreach(i; 1..9)
         mixin("mouse_"~i.stringof~",");
     mouse_left = mouse_1,
     mouse_right = mouse_2,
     mouse_middle = mouse_3;
}
```
Though it might make more sense specifically for conditional 
compilation like `version(..)`.
Oct 11
prev sibling next sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:
 To declare an enum type that may or may not have one or more 
 members depending on conditional compilation statements 
 requires duplicating the entire enum:
 ```d
 static if(cond){
 	enum A{
 		x,y,z,w,
 	}
 }else{
 	enum A{
 		x,y,z,
 	}
 }
 ```

 For an enum type with many members—or many conditionals—this 
 quickly becomes an insane amount of repetition.

 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
 	x,y,z,
     static if(cond){
 		w,
 	}
 }
 ```
I use a mixin generator for my types and I can switch between 2 columns (different languages)/names with a static if. For example: ```d struct ConsArray(Enum, size_t col) { mixin(makeEnum!col); E[] list; size_t index; enum makeEnum(size_t mod) = () { size_t num; string str = "enum E {"; static foreach(i, e; EnumMembers!Enum) { static if ((i & 1) ^ mod) str ~= e.format!"%s = %s,"(num++); } return str ~ "}"; }(); //... } void main() { enum Names { // mod 1, 0 Andy, Ali, Cindy, Cengiz, Kenny, Kaan, Micky, Mehmet, Sunny, Salih } auto names = ConsArray!(Names, 1)(); enum nameEn {Andy,Cindy,Kenny,Micky,Sunny} } ``` If we wish, I could just give the enum directly with E without declaring a condition on my type. However this gives me error-free matching. SDB 79
Oct 15
prev sibling parent Basile B. <b2.temp gmx.com> writes:
On Saturday, 30 March 2024 at 14:57:00 UTC, IchorDev wrote:
 To declare an enum type that may or may not have one or more 
 members depending on conditional compilation statements 
 requires duplicating the entire enum:
 ```d
 static if(cond){
 	enum A{
 		x,y,z,w,
 	}
 }else{
 	enum A{
 		x,y,z,
 	}
 }
 ```

 For an enum type with many members—or many conditionals—this 
 quickly becomes an insane amount of repetition.

 The logical solution is to just allow conditional compilation 
 statements inside enums:
 ```d
 enum A{
 	x,y,z,
     static if(cond){
 		w,
 	}
 }
 ```
Yesterday I was thinking to add that feature to another language (understand "one where there's no implication", you can experiment and "nobody will loose money") and realized a problem that's not been raised before: That would make the grammar significantly more complex. For now the body of a "EnumDeclaration" can only contain "EnumMembers", whereas if you permit "StaticIfDecl" or "VersionDecl" then you also have to special case those in order to be sure that they can only contain EnumMembers.
Oct 31