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

C# 7.3: New forms of generic constraints unmanaged, System.Enum, and System.Delegate #3964

Closed
BillWagner opened this issue Dec 15, 2017 · 12 comments

Comments

@BillWagner
Copy link
Member

There are three new forms of generic constraints being introduced.

"blittable" for unmanaged types: dotnet/csharplang#187
"enum" to specify that the type must be derived from System.Enum dotnet/csharplang#104
"delegate" to specify that the type must derive from System.Delegate dotnet/csharplang#103

Reading the comments, a good part of the explanation will need to be explaining the blittable constraint and its name. There are a lot of subtleties to the types that can be members of a blittable type.

This will be new articles for the new constraint types, and updating general descriptions of generics where class and struct constraints are discussed.

@mairaw mairaw added this to the Backlog milestone Dec 18, 2017
@BillWagner BillWagner changed the title C# 7.3: New forms of generic constraintsblittable, enum, and delegate constraints C# 7.3: New forms of generic constraints blittable, enum, and delegate constraints Jan 25, 2018
@mairaw mairaw added the P1 label Feb 12, 2018
@nietras
Copy link

nietras commented Mar 15, 2018

Isn't "blittable" constraint called unmanaged, it would be good to lose "blittable" wording as it is not exact and confusing.

@BillWagner
Copy link
Member Author

@nietras I create placeholder tasks based on proposals. I do update the titles and notes after the syntax is finalized and before I start writing the documentation. I'll update many of the 7.3 tasks early next week, when I go through all the updated proposals, many of which now have initial implementations.

@dangi12012
Copy link

Blittable/unmanaged needs to happen! Maybe even contraints for operators and casts? Since operators cannot be added in an interface I cannot add 2 generic Variables together. Would be cool for a generic math library where we dont want a class for every single valuetype.

where T : blittable,
where T : ValueType (int, byte, long, etc. but no generic struct so we know it is a framework type)
where T : Castable to T1
where T : Operator+(T1,T2)

@BillWagner
Copy link
Member Author

The proposal has been updated and is posted here

@BillWagner BillWagner modified the milestones: Backlog, Sprint 133 (3/17/18 - 4/06/18) Mar 26, 2018
@BillWagner BillWagner self-assigned this Mar 26, 2018
@BillWagner BillWagner changed the title C# 7.3: New forms of generic constraints blittable, enum, and delegate constraints C# 7.3: New forms of generic constraints unmanaged, enum, and delegate constraints Mar 27, 2018
@BillWagner BillWagner changed the title C# 7.3: New forms of generic constraints unmanaged, enum, and delegate constraints C# 7.3: New forms of generic constraints unmanaged Mar 27, 2018
@BillWagner BillWagner changed the title C# 7.3: New forms of generic constraints unmanaged C# 7.3: New forms of generic constraints unmanaged, System.Enum, and System.Delegate Mar 27, 2018
@BillWagner
Copy link
Member Author

BillWagner commented Mar 27, 2018

There are three new constraints that are enabled by this feature:

  1. System.Enum is no longer disallowed as a base class constraint
  2. System.Delegate and System.MulticastDelegate are no longer disallowed as a base class constraint
  3. The new token unmanaged specifies the new "blittable" types constraint.

The following documents would need updates:

Add samples:

  • An extension method that enumerates all the values in an enum as strings.
  • An extension method that invokes a delegate safely using the ?. operator
  • A sample for an unmanaged type that converts the type to an array of bytes for transmission on a wire.

A good location for these samples is the conceptual topic for generic type constraints

@BillWagner BillWagner modified the milestones: Sprint 133 (3/17/18 - 4/06/18) , Sprint 134 (4/9/2018 - 4/27/2018) Apr 9, 2018
@BillWagner
Copy link
Member Author

Closed in #4960

@IS4Code
Copy link

IS4Code commented May 20, 2018

Is enum still a valid constraint? If not, where T : System.Enum allows T to be any enum, but also System.Enum, which is usually not what you would want. I suppose where T : struct, Enum will work then.

@BillWagner
Copy link
Member Author

@IllidanS4 where T : System.Enum would allow T to be System.Enum, but System.Enum is an abstract class. So, at runtime, T would be an enum type, not System.Enum. You could specify System.Enum as the type parameter, but any instantiated object would be an enum. Do you see scenarios where that could make a difference?

@IS4Code
Copy link

IS4Code commented May 22, 2018

@BillWagner I don't understand the argument; at runtime, T would be exactly System.Enum and objects of type T will be boxed enum values. The difference would be in potential null values, which programmers would need to check, causing more confusion. And what about this?

public static string Method<T>(T? arg) where T : Enum
{
	return arg?.ToString();
}

That cannot be expressed right now. If you wanted to pass null, you would have to make it Enum arg at the expense of boxed objects, but then the type safety would have to be handled at runtime. At the moment, constraining T to a concrete enum type would be where T : Enum, new(), but the compiler then must deduce that such type can only be a value type, which makes things more complicated than necessary.

Imagine if instead of where T : struct, you would have to write where T : ValueType. Wouldn't that bring all sorts of problems, confusions and difficulties? (By the way, I hope where T : ValueType will be possible too, just for the sake of consistency.)

@BillWagner
Copy link
Member Author

Thanks for adding more to your comment @IllidanS4 I think I understand your comments better.

First, if you want to propose new language features, I'd write those issues on the dotnet/csharplang repo. The language designers watch that much more closely.

Here, I'll address where I might need to add more clarification:

You said:

at runtime, T would be exactly System.Enum and objects of type T will be boxed enum values.

No, that's not correct. The last sentence of the spec covering generic type parameters says "The run-time execution of all statements and expressions involving type parameters uses the actual type that was supplied as the type argument for that parameter." Therefore, T is replaced with its actual type. If T is an enum, the runtime code uses that enum type, not System.Enum. That means no boxing.

As for your example, this would work for excluding System.Enum as the type:

public static string Method<T>(T? arg) where T : struct, Enum
{
	return arg?.ToString();
}

You could create overloads:

public static string Method<T>(T? arg) where T : struct, Enum
{
	return arg?.ToString();
}
public static string Method(Enum arg)
{
	return arg?.ToString();
}

Overload resolution ensures that the generic method would be better than the non-generic method for any enum type.

/cc @agocke to validate my explanation.

@IS4Code
Copy link

IS4Code commented May 22, 2018

@BillWagner I still might have not explained myself properly. T will of course be replaced with the actual type you supply and not the base type, but my point is that the user could supply actual System.Enum as T, which is, to my knowledge, possible.

However, seeing you use where T : struct, Enum, I see this is also possible now, so that's all what I wanted to know (where T : struct, Type was not possible before). I just hope people will not use where T : Enum when they want where T : struct, Enum. Perhaps where T : enum would still be more clear.

A similar issue is in the delegate constraint. where T : Delegate still allows T to be System.Delegate or System.MulticastDelegate, even though some programmers would expect it to allow concrete types only. Perhaps a new "non-abstract" constraint might be useful.

@agocke
Copy link
Member

agocke commented May 22, 2018

I think both of what you said is correct, depending on the precise meaning of your terms. The simplest explanation I can come up with is T : System.Enum means exactly what it says and no more -- the type substitution for T must inherit from System.Enum or itself be System.Enum. System.Enum cannot be created directly, but it could be a type argument and enums would be boxed during conversion.

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

No branches or pull requests

6 participants