Proposal: Allow Void type as a Generic parameter #696
Replies: 59 comments 14 replies
-
How so? You can create an array of type
There's no such thing as a 0 length value type. Your long distance(Void* p1, Void* p2) => p2 - p1; |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Strictly speaking it's not even a type. If it weren't for pointers (where it has to sort of behave like a type for consistency and simplicity) maybe it wouldn't even exist. |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
This suggestion was already argued over on Roslyn. The issue is that it would require quite a few changes to the CLR and at this point wouldn't help much since many of the core APIs are already written. Rather than trying to shoe-horn the existing concept of |
Beta Was this translation helpful? Give feedback.
-
But what is it?
No, subtracting pointers gives you a |
Beta Was this translation helpful? Give feedback.
-
I think the fact that subtracting two pointers in C# giving you a long is an implementation detail. If C# had proper support for |
Beta Was this translation helpful? Give feedback.
-
Sure but that doesn't change the fact that subtracting 2 0-sized type pointers is not possible. If 0-sized types would be allowed then subtracting such pointers should be a compile time error, just like subtracting 2 |
Beta Was this translation helpful? Give feedback.
-
Well, this whole part of the discussion got started because of the fact that specifying |
Beta Was this translation helpful? Give feedback.
-
@Joe4evr, specifying
|
Beta Was this translation helpful? Give feedback.
-
Which is entirely separate from what a language decides to return when the delta between two pointers is taken, where the return type is up to the language and not defined by the runtime. |
Beta Was this translation helpful? Give feedback.
-
Can be made with ValueTuple |
Beta Was this translation helpful? Give feedback.
-
Whatever it is, I hope we use interface I<T> { T M(); }
class C : I<void> { public void M(){} } // the compiler automatically emits `return` |
Beta Was this translation helpful? Give feedback.
-
I feel like this conversation starts going slightly wrong direction. Let's set aside all thinking about void pointers, which are not allowed in generic methods (correct me if I'm wrong). I'd rather scope this down to particular feature request to allow
T Method<T>()
{
return default(T);
} with
As @tannergooding mentioned the CLI specification, there must be no value type of 0 size, and [StructLayout(LayoutKind.Sequential, Size = 1)]
public struct Void { } What makes it a pseudo non-unit type. I.e. there must be no issues with having fields and parameters of a value type that is 1 byte (or more) in size. |
Beta Was this translation helpful? Give feedback.
-
The method translation that you described is not possible. C# the compiler can only emit said method exactly once and the IL must work for any possible generic type argument. A method that returns a value must At best you can treat |
Beta Was this translation helpful? Give feedback.
-
I think they are many pitfall in treating
I think we may just forbid It's just an idea, it looks a bit hacky, but doesn't have mentioned issues and I see no drawbacks except some uglyness. |
Beta Was this translation helpful? Give feedback.
-
@Pzixel again, there are no restrictions needed. Infact your proposed restrictions would invalidate the whole purpose of the unit type. If you cannot compare ( It's not harmful to use the unit type as what it actually is/should be: a normal value type. |
Beta Was this translation helpful? Give feedback.
-
@quinmars why whould you like to run If you thing the opposite provide any use case when it's necessary to declare a variable of type |
Beta Was this translation helpful? Give feedback.
-
static T Default<T>(T o) => default(T);
static Object ToObject<T>(this T v) => v; Both are valid generic methods.
So how does that fit together? |
Beta Was this translation helpful? Give feedback.
-
@quinmars I think these methods are allowed to be used by the compiler but not by the user. If you are comparing two |
Beta Was this translation helpful? Give feedback.
-
@Pzixel |
Beta Was this translation helpful? Give feedback.
-
@quinmars it's the same thing as empty statement |
Beta Was this translation helpful? Give feedback.
-
Even with all your restrictions, things like I don't think there's any reason to limit usage of this type. Yes, it's silly to have a variable of type void. It's also possible to make a lot of silly-looking expressions with the As you admit, there's a really easy "workaround" to get this to work - by making the method generic. I don't think we should introduce inconsistencies around having a generic vs non-generic version of the same thing. I don't think there's going to be an epidemic of people making void variables just for the sake of it. It's not like we're gonna have to explain to people "don't do that! it's actually useless" - people will be aware of that. Nobody writes code like this today, just because they can: It's also silly to create an empty local function. And then call it. Or make a function that you don't call at all. But all of that should be legal. I don't think this is going to cause bugs either and therefore it doesn't warrant that we should ban it. There's no reason why we should pick and choose specific usages and make a list of what we think you don't need to do.
Do you understand what it is? The point of the unit type is that it does have a value - there's exactly one. No matter how useless it is. That's why it's called a unit type. Therefore comparison should always return true.
Then what is this thread all about?
We don't need any extra rules here either. |
Beta Was this translation helpful? Give feedback.
-
@Neme12 I admit that I have to agree. At least I have checked this code and it's pretty valid in Rust: fn main() {
let _ = ();
foo((), ());
}
fn foo(_: (), __:()) -> () {
} It's one of best designed language I know so if they are working this way then it's probably better than my silly proposal. I originally said that it looks |
Beta Was this translation helpful? Give feedback.
-
I think it is realizable this as user-code based syntax sugar in many case. How do you think?
I think there are some advantages:
|
Beta Was this translation helpful? Give feedback.
-
If we just do for Generic arguments, why not operates on the generic parser? We can use keyword "out?" to hold the void only for output. to define a delegate: use "_" to be a placeholder, and replace Action with NewFunc<T, _>. so, we dont' change the void, don't need a new type,and don't worry about the old code. we only use the new speciation if we need. |
Beta Was this translation helpful? Give feedback.
-
I actually came across this thread when searching for a solution to this exact problem. I have a function that takes a
As long as the value is not used (by passing it to other functions), I believe it should be possible, even if it's as simple as the CLR automatically returning |
Beta Was this translation helpful? Give feedback.
-
Even if C# doesn't allow void as generic parameter, I think at least the CLR should not block the use case. Otherwise it would prevent introducing a new language on top of .NET which has support for void as first-class type. |
Beta Was this translation helpful? Give feedback.
-
This is something that should be considered for C# 13, or 14, with the theme of bringing more functional programming constructs to C# - like Discriminated unions. The issue is backwards compatibility with existing APIs. It would certainly break stuff. That is probably why it will never happen. Adding stuff to the language without supporting it fully in the framework would make .NET seem bloated. Perhaps we need a new language for this - if we want to make drastic changes to C#. |
Beta Was this translation helpful? Give feedback.
-
This feature can also be useful once we have union types. |
Beta Was this translation helpful? Give feedback.
-
Currently,
void
is not allowed as a generic parameter for a type or a method, what makes it hard in some cases to implement a common logic for a method, that's why we haveTask
andTask<T>
for instance.However, nothing stops you from defining your own
Void
type like this:and use it as a generic parameter for any type or method.
This solves the problem is your app, but your own
Void
type is not the same as built-inSystem.Void
, even though they are semantically equal, what introduces a confusion for a consumer that does type analysis when using reflection for instance.Now with your own
Void
type you are obliged to use thereturn
statement in methods:what is not a requirement for
System.Void
. This optional use of thereturn
statement should be considered as an optimization for well-known 0-length value types.Thus, the
System.Void
must support thenew
operator, and must be allowed (but not required) to be explicitly returned as the result of a method.Such behavior intersects with another feature request: Allow return void function with void function.
Beta Was this translation helpful? Give feedback.
All reactions