This project is read-only.

Enums Constraints For generics

Topics: C# Language Design
Apr 30, 2014 at 4:03 PM
Edited Apr 30, 2014 at 4:04 PM
This has been proposed in uservoice: https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2557231-enums-constraint-for-generics

The idea has been presented in point 4 of this article: http://www.gamasutra.com/blogs/PedroGuida/20140113/208518/Regarding_the_future_of_C_.php

Basically, if you want to mimic an enum constraint you will have to write something like ...
   public void OperationX(TEnum myEnum) 
      where TEnum: struct, IComparable, IFormattable, IConvertible ... and so on so forth.
   {
      … usual stuff …
   }
... and also, given that you are dealing with a subset of elements that approximate to an enum, you need to check whether and enum has been passed, generally throwing an exception if not:
   if (!typeof(TEnum).IsEnum)
   {
      throw new ArgumentException("The passed type is not an enum");
   }
So the proposal is having something like the following:
   public void OperationX(TEnum myEnum)
      where TEnum: enum
   {
      … usual stuff …
   }
It would simplify things and open a wide range of handy operations and extension methods.
May 1, 2014 at 10:08 PM
How about this?
  public void OperationX(TEnum myEnum)
      where TEnum: enum(long) // or other integral type, or string?
   {
      … body …
   }
May 1, 2014 at 10:56 PM
I think System.Enum is disallowed because the Runtime would not allow one to do anything in the presence of the constraint which one could not do with a generic constrained only to struct; in the absence of extension methods, such a constraint wouldn't be very useful.

Given the presence of extension methods, however, a System.Enum constraint could be very useful for allowing extension methods to pop up only when it would be appropriate for them to do so. A generic bool HasAny<T>(this T enum1, T enum2) method could run orders of magnitude faster than the non-generic HasFlag method in enum, but there's no way to make it pop up with enumerated types without it also popping up inappropriately on inappropriate types such as Double.
May 2, 2014 at 6:04 PM
@Alekdias: I don't see why not; in fact, we could have both of them: enum for everything and enum<typeofinteger> for specific cases.

supercat wrote:
... a System.Enum constraint could be very useful for allowing extension methods to pop up only when it would be appropriate for them to do so
There are many cases where you can implement extension methods for enums, like GetNext(), GetPrevious(), GoToFirst(), GoToLast(), and so on so forth (currently, I can achieve this, in a cumbersome way). So, this constraint would come really handy.

supercat wrote:
in the absence of extension methods, such a constraint wouldn't be very useful.
As a game developer, I don't agree with that statement at all. You can use them in base classes (and also fields and any kind of concrete/virtual/abstract member operations/properties), for example:
public abstract class StateObject<TEnum>
    where TEnum : enum
{
    public TEnum CurrentState { get; protected set; }

    public TEnum PreviousState { get; protected set; }
    
    internal protected abstract void Update(TimeSpan gametime);

    ...
}

public enum PlayerStates
{
    None = 0,
    Idle = 0,
    Initializing,
    ...
}

public sealed class Player : StateObject<PlayerStates>
{
    ...

    internal protected override void Update(TimeSpan gametime)
    {
       ...

       switch(this.CurrentState)
       {
           case Idle:
              ...
              break;
              ...
       }

       ...
    }

    ...
}

public enum OtherStates
{
    State0,
    State1,
    ...
}

public class OtherStateObject : StateObject<OtherStates>
{
    ...

    internal protected override void Update(TimeSpan gametime)
    {
       ...

       switch(this.CurrentState)
       {
           case State0:
              ...
              break;
              ...
       }

       ...
    }

    ...
}
Currently, you can achieve this with, say, int fields instead of enums on base classes, but you'll have to be careful with casts back and forth.

And this example is just the tip of the iceberg, since there may be other situations to apply something like this.
May 2, 2014 at 6:19 PM
An enum constraint would flag at compile time some code whose Reflection-based calls would otherwise fail at run-time, and there's some value to that, but it's pretty minor compared to the value of having extension methods pop up only when they're applicable. In any case, using a generic is massively better from a performance standpoint than using variables or parameters of type System.Enum.
May 2, 2014 at 6:30 PM
I won't argue which use cases having the proposed constraint bring minor or major added value.

My post was not meant to motivate that discussion. Instead, it was meant to present a case where, even in the absence of extension methods, having such a constraint would be useful, and at least for me, very useful.
Jul 31, 2014 at 9:45 AM
I agree this would be a wonderful idea. Right now I have to implement Any() and All() extension methods for all my enums, and this is a chore.
Jul 31, 2014 at 1:17 PM
This would be very useful for avoiding boxing to/from Enum and writing much cleaner code. It seems like the runtime already supports this (ECMA-335 section II.10.1.7), F# also has something similar.
Jul 31, 2014 at 3:44 PM
You have my vote. I have needed to do exactly this and had to do a type check at run time (Run Time Type checks are bad bad bad...) by having an enum constraint the code becomes my compilers friend and makes the intent of the class more concise. all good things.
Jul 31, 2014 at 4:31 PM
BachratyGergely wrote:
This would be very useful for avoiding boxing to/from Enum and writing much cleaner code. It seems like the runtime already supports this (ECMA-335 section II.10.1.7), F# also has something similar.
All that would be necessary to allow enum type constraints would be to remove the code that rejects them. I suspect such code exists because the implementers of C# were afraid that programmers might expect an enum constraint to allow a type to be used in ways that would be permissible for any particular enumeration type; likewise with delegate types. I would suggest that such fears might be best allayed by forbidding the use of the keywords enum and delegate in the constraints, but allowing the constraints to be specified as System.Enum and System.Delegate.

Use of enum-constrained variables would require Reflection (implying that run-time sanity checks should be performed even if it should be impossible for operations to fail), but it would be relatively simple to design an efficient dispatch mechanism which would only require using Reflection once for each enumerated type.
Aug 4, 2014 at 2:16 PM
Edited Aug 18, 2014 at 12:02 PM
supercat wrote:
All that would be necessary to allow enum type constraints would be to remove the code that rejects them.
I don't think there is much more involved since C# compiler and VS intellisense already totally respect enum type constraints of assemblies created by other languages (F#, Delphi Prism, etc.) when consuming them.


BTW: I would rather need a type constraint which enforces the existence of a defined Attribute class (or an inherited type), but I assume this would require CLR changes -- is there also a forum for such ideas?
Aug 5, 2014 at 2:28 PM
supercat wrote:
I think System.Enum is disallowed because the Runtime would not allow one to do anything in the presence of the constraint which one could not do with a generic constrained only to struct; in the absence of extension methods, such a constraint wouldn't be very useful.
Actually, the runtime does support it; see this article by Jon Skeet:
http://codeblog.jonskeet.uk/2009/09/10/generic-constraints-for-enums-and-delegates

Jon also wrote this library to work around the limitation; actually it's more a POC than anything else (it decompiles the assembly, modifies the IL and recompiles it), but it shows that it is possible. (that, and what mspring said)
Aug 5, 2014 at 2:30 PM
Edited Aug 5, 2014 at 2:31 PM
mspring wrote:
[Whatever is wrong with this text editor, there is no setting for font size so I can't change this ugly post]
Not the editor, but the markdown rendering engine I think... this is caused by the --- in your post, which makes an horizontal line in some markdown flavors, but apparently in this one it means that the text above is a heading. You can use *** instead.
Aug 14, 2014 at 3:16 AM
At some point, someone arbitrarily made the C# compiler not allow type constraints on "enum" for reasons unknown. Fixing this seems like an easy win. I understand it may be low priority, but unless there's a good reason to not allow it, this limitation needs to on the list of things to fix.
Aug 15, 2014 at 8:22 PM
Hope the team decides to add this feature to the roadmap soon.
Aug 15, 2014 at 11:15 PM
tom103 wrote:
supercat wrote:
I think System.Enum is disallowed because the Runtime would not allow one to do anything in the presence of the constraint which one could not do with a generic constrained only to struct; in the absence of extension methods, such a constraint wouldn't be very useful.
Actually, the runtime does support it; see this article by Jon Skeet:
http://codeblog.jonskeet.uk/2009/09/10/generic-constraints-for-enums-and-delegates
What exactly does the runtime allow one to do with a generic type which is constrained to both struct and System.Enum, which it would not allow one to do with a struct constrained only to struct, other than pass it as a generic type parameter to classes or methods that impose similar constraints? One can syntactically invoke HasFlag on an a generic type which is constrained in such fashion without having to explicitly cast to System.Enum first, but because individual enum types don't override HasFlag, calling that method on an enum will be equivalent to casting it to System.Enum and calling the method on that. I don't think the runtime particularly "supports" System.Enum as a generic constraint so much as it simply regards it as being no different from any other.
Aug 18, 2014 at 9:44 AM
supercat wrote:
What exactly does the runtime allow one to do with a generic type which is constrained to both struct and System.Enum, which it would not allow one to do with a struct constrained only to struct, other than pass it as a generic type parameter to classes or methods that impose similar constraints?
Nothing, except the fact that it enforces the constraint, i.e. it won't create a type Generic<T> if T isn't an enum. I agree that it would only be useful in very specific cases, but when you do need to ensure that you're working with an enum type, it would be much better to have the compiler enforce the constraint than checking the type manually at runtime...
Aug 18, 2014 at 12:07 PM
Enum.TryParse<T> currently throws a RUN-TIME exception, if T is not an enum. If they just had used the existing capabilities (not artificically limited by the C# compiler) then it would throw a COMPILE-TIME exception, for which you would not need unit tests at all.
Aug 18, 2014 at 1:14 PM
Would love to know the devs' thoughts about the suggestion and comments under discussion.
Aug 18, 2014 at 2:39 PM
Edited Aug 18, 2014 at 2:40 PM
I suspect that allowing enum and delegate constraints is as simple as commenting the two cases below:
        private static bool IsValidConstraintType(TypeConstraintSyntax syntax, TypeSymbol type, DiagnosticBag diagnostics)
        {
            switch (type.SpecialType)
            {
                case SpecialType.System_Object:
                case SpecialType.System_ValueType:
                //case SpecialType.System_Enum:
                //case SpecialType.System_Delegate:
                case SpecialType.System_MulticastDelegate:
                case SpecialType.System_Array:
                    // "Constraint cannot be special class '{0}'"
                    Error(diagnostics, ErrorCode.ERR_SpecialTypeAsBound, syntax, type);
                    return false;
            }
(in Binder_Constraints.cs)

But since my VS installation is completely messed up right now, I can't test it...
Sep 19, 2014 at 12:20 AM
Really wanted.

I hope the roslyn team will take this in consideration, this is a kind of feature that allows me to write better and safer code.
Sep 23, 2014 at 2:24 PM
Well, unfortunately I haven't seen much change in the list of upcoming features for c# 6, recently. But who knows, maybe they decide to include it close to release time.
Oct 22, 2014 at 12:04 AM
Would love to define extension methods like (with inlining suggested to the compiler):
public static void ContainsFlag<TEnum>(this TEnum myEnum, TEnum flag)
   where TEnum: enum
{
   return (myEnum & flag) == flag;
}
Oct 22, 2014 at 12:43 AM
Ultrahead wrote:
Well, unfortunately I haven't seen much change in the list of upcoming features for c# 6, recently. But who knows, maybe they decide to include it close to release time.
It is really, really, really unlikely we'll add any more language features in the current cycle (other than finishing up nameof() and string interpolation for both languages).
Oct 22, 2014 at 4:39 PM
Ultrahead wrote:
Would love to define extension methods like (with inlining suggested to the compiler):
So would I; I would think allowing enum constraints would be "low-hanging fruit" but the counter-argument is that if the Framework added a few such methods there wouldn't be a whole lot of need for programmers to do likewise. I would rather have VB and C# change so that I could write such methods myself than wait for the Framework group to maybeget around to adding methods which might end up working the way I want or might not be as efficient as the ones I already have.
Nov 14, 2014 at 5:31 AM
It is really, really, really unlikely we'll add any more language features in the current cycle (other than finishing up nameof() and string interpolation for both languages).
There is no reason not to do it. At the first, there is no breaking changes. At the second, this feature already exists in CLR. At the third, there is no problems with third-party plugins & tools: its still must be rewritten and implementation of this feature is simple both to Roslyn and third-party plugins & tools.
Nov 14, 2014 at 3:54 PM
I have to admit that I am disappointed for not including it in the upcoming version of C# since this has been an old-time request: https://www.google.com.uy/webhp?ie=UTF-8#q=enum%20constraint%20generics%20c%23

Besides, as afsherman says, the feature already exists in the CLR, and it's been used by F#.

Finally, imvho, given the opportunity, this feature would prove to be very useful and a great addition to C#.

So I hope MSFT reconsiders its decision, and include it more sooner than later to the language.
Nov 14, 2014 at 4:01 PM
@nmgafter, what was the reason for this restriction in the first place? Would removing it cause any undesirable side effect?
Nov 14, 2014 at 4:01 PM
Btw, Mads if you are reading this thread, you can find a comment of yours from early 2009 on Connect: https://connect.microsoft.com/VisualStudio/feedback/details/386194/allow-enum-as-generic-constraint-in-c

2009! More than five years later and the features is still disregarded ... no matter how many devs suggest it a/o claim for it.
Nov 14, 2014 at 4:16 PM
I created .NET 2 assemblies using Remobjects Oxygene (formerly known as Chrome, also known as Delphi Prism) in 2006 or 2007 containing real enum and even delegate constraints (like F# supports today) and C# was already capable of following these constraints perfectly nearly 10 years ago.

Just someone with balls has to nuke these 2 or 3 lines of insane and totally unnecessary checking code.

This is as frustating as all the wasted time on Microsoft Connect: "closed by design" as the answer to everything, no matter how many upvotes the topic has seen.
Nov 14, 2014 at 10:20 PM
Edited Nov 14, 2014 at 10:20 PM
zeldafreak wrote:
At some point, someone arbitrarily made the C# compiler not allow type constraints on "enum" for reasons unknown. Fixing this seems like an easy win. I understand it may be low priority, but unless there's a good reason to not allow it, this limitation needs to on the list of things to fix.
As I heard the reason, it goes like this. Generics for .NET were invented and prototyped by a crack group of programming-language researchers from MSR Cambridge (including Don Syme who's gone on to do F#). Because they do their language research with rigor, they proved mathematically that generics work the way you'd expect a type system to work -- "subject reduction theorem" and "progress theorem". These proofs were never carried over to constraints, and so there isn't the same level of certainty that existing constraints work with the same rigor, let alone additional constraints.

Prompted by this thread, I chatted with one of those researchers about the topic when he came to visit last month, and asked him to add it to his plate.

I think my dominant conclusion from this thread so far is reaffirmation that a simple enum constraint would be valuable for intellisense purposes, but aside from that the actual code would end up requiring reflection. That'd be unfortunate in a world where (with .NET-Native) we're moving away from reflection. I don't want to be choosing between type safety and efficiency.

The "where T:enum(long)" idea is an interesting one. I'd love to see that fleshed out. Anyone interested in doing that? I think fleshing-out would involve (1) concrete scenarios, (2) syntax+semantics of the proposal, (3) evaluation of its .NET-Native performance, (4) evaluation of its intellisense behavior. (If no one wants to do this then I can, but I won't have time before January). PS. if that seems heavyweight for such a small change, well yes that's how carefully we do language design :) Like a sign I remember in an ancient Chinese monument "Tread carefully for you bear the weight of centuries on your shoulders"...
Nov 14, 2014 at 10:28 PM
mspring wrote:
This is as frustating as all the wasted time on Microsoft Connect: "closed by design" as the answer to everything, no matter how many upvotes the topic has seen.
I sometimes wonder if the purpose of such things is to distract the energies of people who might otherwise develop competing frameworks? When even something as serious as the .NET 4.0 string-compare bug (which makes String.Compare report the ordering "FK" < "fk-" < "-fk" < "FK") gets dismissed as "Closed--won't fix", it's hard to think of anything positive to say about the way MS handles feedback.
Nov 14, 2014 at 11:28 PM
Edited Nov 14, 2014 at 11:39 PM
mspring wrote:
I created .NET 2 assemblies using Remobjects Oxygene (formerly known as Chrome, also known as Delphi Prism) in 2006 or 2007 containing real enum and even delegate constraints (like F# supports today) and C# was already capable of following these constraints perfectly nearly 10 years ago.

Just someone with balls has to nuke these 2 or 3 lines of insane and totally unnecessary checking code.
Removing the constraint would not have the effect you desire. It would still allow System.Enum to satisfy the constraint, for example. There is more design work to get this done right than may appear at first glance. It is too late to do that work for the current product cycle.
Nov 14, 2014 at 11:30 PM
By the way, this suggestion is not being disregarded. It has been on the list of language feature candidates for every revision for years. It just never bubbled to the top of the bang-for-the-buck ranking.
Nov 14, 2014 at 11:30 PM
lwischik wrote:
As I heard the reason, it goes like this. Generics for .NET were invented and prototyped by a crack group of programming-language researchers from MSR Cambridge (including Don Syme who's gone on to do F#).
That's particularly interesting given that F# does allow these types of constraints. But if generics for the entire CLR weren't designed with that in mind why do they work fine and this limitation only enforced in C# and VB.NET?
The "where T:enum(long)" idea is an interesting one. I'd love to see that fleshed out. Anyone interested in doing that? I think fleshing-out would involve (1) concrete scenarios, (2) syntax+semantics of the proposal, (3) evaluation of its .NET-Native performance, (4) evaluation of its intellisense behavior. (If no one wants to do this then I can, but I won't have time before January).
That is interesting, however I think that when most of us think about constraints like this that it does serve to aid in Intellisense primarily and that our use-cases wouldn't be limited to an underlying type. It's more about expanding on what mscorlib offers to assist with working with enums. For example, I have an EnumParser class which supports a lot of scenarios when parsing strings containing enums to an enum value, including strings of flags separated by commas or pipes. These methods are generic and use generic constraints struct, IComparable, IFormattable and IConvertible but internally they still need to double-check that the type parameter is an enum. Such methods likely only would have to be written once and the issue would never come up again, but given that the CLR code is primarily C# it would be similarly a pain to implement there and even if the .NET Core team is willing to entertain PRs from myself and supercat that still leaves potential stuff on the table.

I also have similar helper classes for delegates, particularly atomically subscribing/unsubscribing events, reimplementing the crap that the C# compiler spits out in default event adders/removers that really should have a reference implementation in the framework.

I am curious about this argument from a .NET Native perspective. Until .NET Native covers all of the framework it's frankly not on my radar as I will never write a Windows Store app (or an app for any mobile platform). This kind of code is inherently reflection-driven due to lack of an alternative and I definitely don't know what constraints that .NET Native puts on said code.
Nov 14, 2014 at 11:40 PM
nmgafter wrote:
By the way, this suggestion is not being disregarded. It has been on the list of language feature candidates for every revision for years. It just never bubbled to the top of the bang-for-the-buck ranking.
Your point of view is a little bit hard to defend since in C# 6 there are some new features (e.g. #Disable Warning BC40008) that IMHO is not so usefull or community requested as Enum constraint or !is for example. Looks like the bubble up process is not driven by customers request.
Nov 14, 2014 at 11:51 PM
Edited Nov 14, 2014 at 11:53 PM
iLMaX wrote:
Your point of view is a little bit hard to defend since in C# 6 there are some new features (e.g. #Disable Warning BC40008) that IMHO is not so useful or community requested as Enum constraint or !is for example. Looks like the bubble up process is not driven by customers request.
Disable Warning is an essential part of "Analyzers". They're not a community request. They're the team at Microsoft pushing forward in a new and innovative direction, one that we invented and believe will dramatically change the way people think about and use code -- for the better. No one asked ask specifically for async either, but we perceived a general industry need and stepped up to it.

Community requests influence what we do. But a prerequisite for doing anything at all is to have a good proposal on the table, or someone interested and willing to drive it, who believes they have a better solution than the status quo. I personally don't yet see a solution better than the status quo, and in my mind the ideas in this thread might turn out better but they're not there yet. Personally I'm going to put more effort into metaprogramming investigation than into enum-constraint investigation over the next half year.

We started getting more open part way through the design of C#6 and VB14. I think that once we start C#7 and VB15 open from the get-go, and everyone sees more of the process, it'll make more sense.

-- Lucian (from the VB/C# team)
Nov 15, 2014 at 12:30 AM
iLMaX wrote:
nmgafter wrote:
By the way, this suggestion is not being disregarded. It has been on the list of language feature candidates for every revision for years. It just never bubbled to the top of the bang-for-the-buck ranking.
Your point of view is a little bit hard to defend since in C# 6 there are some new features (e.g. #Disable Warning BC40008) that IMHO is not so usefull or community requested as Enum constraint or !is for example. Looks like the bubble up process is not driven by customers request.
@iLMaX I think you missed the part about the "bang-for-the-buck". If the cost of implementing the feature is high relative to the benefits, then they are unlikely to do the feature. Though I too have code that would benefit from this feature, the benefits to the language are admittedly tiny: use cases of these two constraints would be rare and don't actually enable any functionality that is currently impossible. If the features require substantial planning and design work to accomplish, they'd fall close to the bottom of the list of features that I'd like to see the team spend time working on.

Something tells me disabling warnings was probably a relatively cheap feature in terms of design, so I think that's not a great comparison.
Nov 17, 2014 at 5:13 PM
MgSam wrote:
@iLMaX I think you missed the part about the "bang-for-the-buck". If the cost of implementing the feature is high relative to the benefits, then they are unlikely to do the feature.
Yeah, but this seems more like a case of "pop for the penny". The cost of rolling the feature in with other changes should be extremely low. The benefits aren't huge, but they're not trivial. While it's possible that the Framework might someday include some methods written in CIL which would accept a generic enum type and operate efficiently upon it (using Reflection the first time it is invoked with each particular generic type argument, and using a cached delegate or interface implementation every time thereafter), removing two lines from the compiler would allow programmers to make use of such things today. Further, some projects may need to define multiple enumerated types which should have some extension methods in common. While being able to specify that particular enum types implement interfaces and constrain to those would be more helpful than having an extension method which is offered up for all enum types, it would still be better than having the extension method get offered up for all integer numeric types.
Nov 17, 2014 at 5:24 PM
supercat wrote:
removing two lines from the compiler would allow programmers to make use of such things today
Supercat, we do language design with a lot more rigor than that. I outlined in an earlier post four things I'd expect to see in a proposal about enum constraints. I'm sure everyone would be happy with enum constraints once they're done, but we definitely won't move forwards until we have a solid fleshed-out proposal on the table. As I said, that proposal can come from the community, or if no one steps up then I'll work on it some time next year.
Nov 17, 2014 at 5:34 PM
nmgafter wrote:
Removing the constraint would not have the effect you desire. It would still allow System.Enum to satisfy the constraint, for example. There is more design work to get this done right than may appear at first glance. It is too late to do that work for the current product cycle.
So constrain to enum, struct, or else design code which includes System.Enum among the types it can work with. To be sure, usefully employing an enum constraint would require a certain amount of boilerplate code, and having some of it in the Framework would be nicer than requiring user code to implement it, but it's not that bad.
Nov 17, 2014 at 6:07 PM
lwischik wrote:
Supercat, we do language design with a lot more rigor than that. I outlined in an earlier post four things I'd expect to see in a proposal about enum constraints. I'm sure everyone would be happy with enum constraints once they're done, but we definitely won't move forwards until we have a solid fleshed-out proposal on the table. As I said, that proposal can come from the community, or if no one steps up then I'll work on it some time next year.
I appreciate that compiler changes should not be made lightly, but I don't remember exactly what you had indicated would be a suitable amount of rigor here. The checks do not merely indicate that a coding construct should not be considered for overloading and should instead fall back to some other overload, but force an unconditional error. As such, I see no plausible mechanism by which they could change the meaning of any code which presently compiles (unless there's something I'm missing)? The fact that other languages have for years allowed the use of a System.Enum constraints, and that C# has for years been willing to interoperate with things that are constrained in such fashion would suggest that if they caused any problems at the Framework level such problems would have been observed already.

It might be nice to have a means by which the compiler could automatically turn something like:
public static bool HasAll<T>(this T v1, T v2) where T:enum, struct
{ return (v1 & v2)==v2; }
into:
static class EnumHelper
{
   public static bool HasAll<T>(this T v1, T v2) where T:System.Enum, struct
   { 
     return ProcHolder<T>.hasAll(v1,v2);
   }

   static class ProcHolder<T> { Func<T,T,bool> hasAll(T v1, T v2) = EnumHelper.defaultHasAll<T>; }

   bool hasAll(Int32 v1, Int32 v2) { return (v1 & v2)==v2; }
   bool hasAll(Int64 v1, Int64 v2) { return (v1 & v2)==v2; }
   ...
   bool defaultHasAll<T>(T v1, T v2)
   {
     EnumHelper<T>.hasAll = [[ reflection to get method ]];
     return EnumHelper<T>.hasAll(v1, v2);
   }
}
but that would require considerable extra complexity, and I'm not sure that it would be sufficiently useful to favor it over simply having user code write out the latter.
Nov 17, 2014 at 6:16 PM
supercat wrote:
I appreciate that compiler changes should not be made lightly, but I don't remember exactly what you had indicated would be a suitable amount of rigor here.
I think fleshing-out would involve (1) concrete scenarios, (2) syntax+semantics of the proposal, (3) evaluation of its .NET-Native performance, (4) evaluation of its intellisense behavior

I liked your EnumHelper. The concrete scenarios should scrape together it and all of the ones posted in this thread, and those on uservoice, and a survey of questions that had been asked on stackoverflow that had been met with "sorry you can't do this" answers. It would include scenarios that aren't helped by the proposal too. And detailed perf+reflection considerations/tradeoffs.
Nov 17, 2014 at 7:35 PM
lwischik wrote:
supercat wrote:
I appreciate that compiler changes should not be made lightly, but I don't remember exactly what you had indicated would be a suitable amount of rigor here.
I think fleshing-out would involve (1) concrete scenarios, (2) syntax+semantics of the proposal, (3) evaluation of its .NET-Native performance, (4) evaluation of its intellisense behavior

I liked your EnumHelper. The concrete scenarios should scrape together it and all of the ones posted in this thread, and those on uservoice, and a survey of questions that had been asked on stackoverflow that had been met with "sorry you can't do this" answers. It would include scenarios that aren't helped by the proposal too. And detailed perf+reflection considerations/tradeoffs.
Where can we submit this? As mentioned I have numerous examples of helpers for both enums and delegates that I think would qualify.
Nov 17, 2014 at 11:59 PM
Halo_Four wrote:
Where can we submit this? As mentioned I have numerous examples of helpers for both enums and delegates that I think would qualify.
Halo, for now please do what we did with the "nameof" and "string interpolation" threads - i.e. start new a thread with a comprehensive spec proposal, then close off the previous thread with a redirect message. (Ultimately we hope to keep proposal documents in a cleaner form on github, but we're not there yet).
Nov 18, 2014 at 3:03 AM
lwischik wrote:
Halo_Four wrote:
Where can we submit this? As mentioned I have numerous examples of helpers for both enums and delegates that I think would qualify.
Halo, for now please do what we did with the "nameof" and "string interpolation" threads - i.e. start new a thread with a comprehensive spec proposal, then close off the previous thread with a redirect message. (Ultimately we hope to keep proposal documents in a cleaner form on github, but we're not there yet).
I'd love to dive into something that deeply in the near future. Perhaps one of the other interested parties can spearhead it. In the meantime I've been looking through my code where I think that these constraints would be of benefit and trying them under .NET Native. It's been trying mostly because of the limitations on the framework imposed by Windows apps.

For enum most of the code works. I can get the Type instance, I can call Enum.GetUnderlyingType to get the underlying primitive and I can call Enum.GetNames() to get the list of names. Since Type.GetCustomAttributes doesn't exist I can't test obtaining FlagsAttribute. Calling Enum.GetValues() also fails as internally it tries to call Array.UnsafeCreateInstance, but calling Enum.Parse works so I could obtain the values and cache them as I checked the names. So, short of knowing whether the specified enum was flags everything I have written should work with some minor tweaks.
MyEnum e;
if (EnumParser.TryParse("Foo | Bar", out e)) { ... }
My delegate code mostly doesn't do reflection, it just uses the generic type to cast from Delegate back to the specified type since most of the useful methods return raw Delegate. I do have one extension method where I unwrap a delegate into an IEnumerable of the invocation list which checks to see if the target is the Invoke method of another delegate in which case it recursively unwraps that delegate. That I can't test as Delegate doesn't expose the Method property in Windows Store apps.
class Foo {
    private EventHandler myEventField;

    public event EventHandler MyEvent {
        add { Event.AddWeakHandler(ref myEventField, value); }
        remove { Event.RemoveWeakHandler(ref myEventField, value); }
    }
}
I'm sure that supercat has a bunch of his own interesting helper methods as well.
Nov 18, 2014 at 4:34 PM
Edited Nov 18, 2014 at 4:37 PM
lwischik wrote:
Halo, for now please do what we did with the "nameof" and "string interpolation" threads - i.e. start new a thread with a comprehensive spec proposal, then close off the previous thread with a redirect message. (Ultimately we hope to keep proposal documents in a cleaner form on github, but we're not there yet).
What should a "comprehensive spec proposal" contain beyond "remove the code that squawks when using enum or delegate constraints" [requiring the constraints to be specified as Enum or Delegate, rather than enum or delegate], effectively extending the definition of the language by replacing any verbiage that would forbid those constraints with a note that while the constraints are legal, the generic abilities do not gain anything from them other than being able to use members of System.Delegate and System.Enum?

Code illustrating how things like EnumHelper<T>.HasAny would work have already been posted on other threads, and the fact that such extension methods are boatloads faster than Enum.HasFlag is already pretty well known. Using a generic reduces the cost of HasAny to that of a delegate invocation; it could probably be reduced further--to the cost of an interface dispatch--if one used Reflection.Emit, but I don't know how to do that. In any case, the language itself wouldn't have to concern itself with such details.
Nov 18, 2014 at 4:43 PM
Edited Nov 18, 2014 at 4:44 PM
supercat wrote:
What should a "comprehensive spec proposal" contain beyond "remove the code that squawks when using enum or delegate constraints"
(1) concrete scenarios, (2) syntax+semantics of the proposal, (3) evaluation of its .NET-Native performance, (4) evaluation of its intellisense behavior.
Code illustrating how things like EnumHelper<T>.HasAny would work have already been posted on other threads, and the fact that such extension methods are boatloads faster than Enum.HasFlag is already pretty well known.
Well good -- that will make (1) a bit easier to assemble into the proposal! :)


Seriously, we just don't add features through quick code changes. We do it after long and careful analysis of the problem domain, looking at as wide a variety as we can of different workarounds that people have used, looking to see if the feature would open up new doors beyond the narrow cases we've identified. We gather a wide range of problems, some of which are helped by the proposal, some of which aren't, and see how they stand. We assess how frequently people are blocked or inconvenienced by the change. It's the job of the proposer to gather all these together, so that the language team can weigh them up.
Nov 18, 2014 at 5:53 PM
Halo_Four wrote:
I'm sure that supercat has a bunch of his own interesting helper methods as well.
How about, as a delegate helper:
    static class DelegateTransformer<T> where T:class
    {
        public static System.Runtime.CompilerServices.ConditionalWeakTable<Delegate, T> lookup =
            new System.Runtime.CompilerServices.ConditionalWeakTable<Delegate, T>();
        public static T help(Delegate d)
        {
            var arr = d.GetInvocationList();
            if (arr.Length == 1)
                return (T)(Object)Delegate.CreateDelegate(typeof(T), d.Target, d.Method);
            else
            {
                for (int i=0; i<arr.Length; i++)
                    arr[i] = (Delegate)(Object)Fix<T>((T)(Object)arr[i]);
                return (T)(Object)Delegate.Combine(arr);
            }
        }
    }
    static T Fix<T>(T it) where T:class
    {
        if (it == null) return it;
        if (it.GetType() == typeof(T)) return it;
        return DelegateTransformer<T>.lookup.GetValue((Delegate)(Object)it, DelegateTransformer<T>.help);
    }
This may be used to correct the somewhat-broken delegate covariance in .NET. Given:
Action<Cat> catAction1 = meow1, catAction2 = meow2; // Assume meow1, meow2 are methods
Action<Animal> animalAction1 = sleep; // Assume sleep is a method
Action<Animal> actions = null;
actions += catAction1; // Works--stores reference to an Action<Cat>
actions += catAction2; // Works--stores reference to an Action<Cat>
actions += animalAction1; // KABOOM!
The first two attempts to add actions succeeded even though the type of action being added was not an Action<Animal>, but rather an Action<Cat>; the last one fails even though the delegate exactly the right type for the variable. The problem is that the Delegate.Combine method has no way of knowing when starting with an empty list that code was really expecting an Action<Animal>, and thus goes with the type of the first action added.

Invoking Fix on a delegate which "derives" from type T will yield a delegate which is of type T. Invoking Fix multiple times on the same delegate will yield the same delegate out, and I believe invoking it multiple times on a equivalent delegates will yield equivalent delegates out. It's only lightly tested, but I believe it works and preserves equivalence in both single-cast and multi-cast scenarios.

Additional helpers could be used for Plus and Minus, which would then chain to the + and - operators after using Fix to ensure that the delegates really were of the proper types.
Nov 18, 2014 at 9:03 PM
Edited Nov 18, 2014 at 9:06 PM
A common helper method for delegates: compiling reflection-acquired methods into .NET delegates.
public static TDelegate ToDelegate<TDelegate>(this MethodInfo method) 
    /* where TDelegate: delegate */
{
     var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
     MethodInfo invokeMethod = typeof (TDelegate).GetMethod("Invoke");
     var @params = 
        invokeMethod.GetParameters()
                    .Select((p, i) => Expression.Parameter(p.ParameterType, "arg" + i))
                    .ToArray();
     MethodCallExpression methodCall = Expression.Call(method, 
        @params.ZipWith(parameterTypes).Select(t => Expression.Convert(t.Item1, t.Item2)));
     return Expression.Lambda<TDelegate>(
        Expression.Convert(methodCall, invokeMethod.ReturnType), @params).Compile();
 }
I use it to compile a MethodInfo to a delegate that can be reused multiple times without performance penalties:
public delegate ICommand CommandCreator(Engine engine, Configuration config);
// ...
MethodInfo mi = commandFactoryType.GetMethod("Create", 
    BindingFlags.Public | BindingFlags.Static);
CommandCreator createCommand = mi.ToDelegate<CommandCreator>();
foreach (Configuration c in _availableConfigs)
    _commands.Add(createCommand(this, c));
Nov 19, 2014 at 3:02 AM
I've posted a simple proposal at the following thread:

Enum and Delegate as Generic Type Constraints Proposal

I've kept it relatively simple for now and I invite others to add use cases.