Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] ValueEnum - (Random Thought) #1325

Closed
RandyBuchholz opened this issue Feb 14, 2018 · 7 comments
Closed

[Proposal] ValueEnum - (Random Thought) #1325

RandyBuchholz opened this issue Feb 14, 2018 · 7 comments

Comments

@RandyBuchholz
Copy link

There are many proposals/issues related to Enum. Many of them are constrained by underlying technologies and backwards compatablilty. ValueTuple did wonders for the issues with Tuple. Consider taking the same approach with enums by introducing the ValueEnum.

@HaloFour
Copy link
Contributor

Could you be more specific as to how a ValueEnum type would solve which problems and how?

@Unknown6656
Copy link
Contributor

Unknown6656 commented Feb 14, 2018

Maybe I am missing something important, but as far as I was aware, any current enum-type is handled as a value type (especially as the "inherit" integral value-types). The class System::Tuple<...> is a reference type - opposed to the value-type System::ValueTuple<...>. Therefore, the type ValueTuple will be passed by value instead of by reference as is the case with Tuple.

What exactly to you expect from a hypothetical ValueEnum-type -- keeping in mind, that any current enum will be passed by value?

@RandyBuchholz
Copy link
Author

This is just brainstorming, but I'm taking a step back and looking at it from the idea of not what a current enum is, but how do people want/try to use enum like (real-world) "enumerations".

For example, an ordered list of strings is a "string enumeration". A common way people use (or misuse depending on your perspective) enum is as a list of string constants. It provides an easy to use, constrained list at design time.

enum Crud { Create, Read, Update, Delete }  
performAction(Crud.Update);

But, enum is picky about some things. I'm just pulling from distant memory, but there are complexities in using them as constraints on generics, and in attributes.

You can't do this

    enum AnEnum { a, b,  c  }
    class Foo<T> where T : AnEnum { }

I recall working with attributes and having to use object as a type because enum "isn't a compile-time constant" (IIRC). (syntax likely wrong here...)

    enum AnEnum {a, b, c}
    
    [SomeAttribute(Attrib = AnEnum.a)]
    class Foo{}

   class SomeAttribute : Attribute {
      AnEnum Attrib { get; set; } // Can't do this. Need to use object, the check and cast
   }

I've seen proposals for a more "class-like" enum, with things like inheritance.
class Foo{ }

   enum BaseSet { A, B, C }
   enum ExtendedSet : BaseSet { D }

I wanted to do something with an enum today that I knew I couldn't. It got me thinking about a bunch of discussions and ideas people had about a year ago around enum. In many cases the result was, "good ideas, but can't be done with the current way enum is implemented in the framework". The framework enum isn't likely to change, at least this drastically. So maybe a "PseudoEnum" is an option.

@Unknown6656, ValueEnum was probably a bad choice of name, because it misleads. I didn't intend to imply Value Type, but more just the idea of xxxEnum to say it's related to enum. Maybe Enumeration would be better. Enumeration<T> even better aligns with some of the idea, because it could be an enumeration of anything. But it shouldn't (always) be a generic. It could be a constrained list of objects, classes, or functions, that can be referenced using dot-notation.

Again, this is thinking not about what an enum currently is, but what many people might want from an enum, (or even think an enum is). Having "dottable" lists of values or references, at design time - group.item, that I can use where I might normally expect, is one for me.

@tannergooding
Copy link
Member

Some of these (like being able to use an Enum constraint) are already being fixed in 7.3

Others (like poor performance for various Enum methods) have been fixed in the runtime.

@HaloFour
Copy link
Contributor

HaloFour commented Feb 14, 2018

@RandyBuchholz

But, enum is picky about some things. I'm just pulling from distant memory, but there are complexities in using them as constraints on generics,

That is strictly a compiler limitation, and one that is likely to be lifted. #104

I recall working with attributes and having to use object as a type because enum "isn't a compile-time constant" (IIRC).

Yes it is. Look at AttributeUsageAttribute:

[AttributeUsage(AttributeTargets.All)] // <-- AttributeTargets is an enum
public class MyAttribute : Attribute { }

I've seen proposals for a more "class-like" enum, with things like inheritance.

Which might be interesting, but value types can't be inherited either. There might be ways via syntax candy to pseudo-inherit the existing members of one enum into another, which is something that could be solved through source generators. But that would be a disparate enum. True inheritance would involve classes, heap allocations and all of that overhead to represent what is effectively an integral value.

Maybe Enumeration would be better. Enumeration<T> even better aligns with some of the idea, because it could be an enumeration of anything.

Also painfully close to IEnumerable<T> and IEnumerator<T>.

There's probably going to be more conversation around enums of other values when pattern matching explores algebraic data types or discriminated unions along with records, like this example in Swift:

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

var productBarcode = Barcode.upc(8, 85909, 51226, 3)

switch productBarcode {
    case .upc(let numberSystem, let manufacturer, let product, let check):
        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
    case .qrCode(let productCode):
        print("QR code: \(productCode).")
}
// Prints "UPC: 8, 85909, 51226, 3

@svick
Copy link
Contributor

svick commented Feb 14, 2018

You can't do this

enum AnEnum { a, b,  c  }
class Foo<T> where T : AnEnum { }

That doesn't make any sense, AnEnum is effectively a sealed type (all value types are), so it can't have any derived types. Unless that changes, such constraint would not be useful, because the only type that could be T is exactly AnEnum.

If you're talking about a general Enum constraint, that's #104 and I don't see how would xxxEnum help with that.

I recall working with attributes and having to use object as a type because enum "isn't a compile-time constant" (IIRC).

// Can't do this. Need to use object, the check and cast

Yes, we can.

I've seen proposals for a more "class-like" enum, with things like inheritance.

That sounds like dotnet/roslyn#9120, which was closed and not moved to this repo ("I don't have confidence that the LDM would likely consider doing this."). How would xxxEnum help with that?

@bondsbw
Copy link

bondsbw commented Feb 15, 2018

@svick

That doesn't make any sense, AnEnum is effectively a sealed type (all value types are), so it can't have any derived types. Unless that changes, such constraint would not be useful, because the only type that could be T is exactly AnEnum.

Another possibility is nested/composite enums (#587, #1079). Though I'm not entirely sure how that would be implemented without struct inheritance, or without lowering/magic that may break across assemblies/versions/languages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants