Replies: 37 comments
-
I also use the System.ValueTuple with zero items aliased as a Unit and would like to see this baked into the language. |
Beta Was this translation helpful? Give feedback.
-
Well... C# definitely needs official "Unit" type which would be allowed to be used as generic type argument. In the ideal world compiler (and probably CLR) should "know" this official unit type and allow type compatibility between "unit" and "void". So, Such void/unit type compatibility is required to avoid a major rewrite of already existent code base which is practically impossible. Under the hood, C# also shouldn't require explicit return value from function if function result type is Ideally, CLR should recognize well-known For my opinion, C-like
|
Beta Was this translation helpful? Give feedback.
-
There's no such thing as a zero-sized struct in the CLR. A struct with no fields is still a byte wide. at a minimum. And even if there was it's not semantically equivalent. A
The name, maybe. But nearly all imperative non-functional languages have the concept of |
Beta Was this translation helpful? Give feedback.
-
Is interface I<T> { T M(); }
class C : I<void> {
public void M() {
// compiler generates code to return default(Void) under the hood.
}
} |
Beta Was this translation helpful? Give feedback.
-
@alrz It is, see https://github.com/dotnet/coreclr/blob/32f0f9721afb584b4a14d69135bea7ddc129f755/tests/src/JIT/Regression/CLR-x86-JIT/V2.0-Beta2/b353858/b353858.il |
Beta Was this translation helpful? Give feedback.
-
Ok. thanks. But still nothing stops you to emit whatever type instead of I think that having to write |
Beta Was this translation helpful? Give feedback.
-
Practically they're semantically equivalent. When you say about
Imperative languages do use Foremost issue with Technical implementation at CLR level how to internally treat You can argue that if |
Beta Was this translation helpful? Give feedback.
-
I think that you've done pretty well to describe the paradigmic difference between That's the difference. With That's not to say that I'm opposed to the notion of adding |
Beta Was this translation helpful? Give feedback.
-
@HaloFour |
Beta Was this translation helpful? Give feedback.
-
Those implementation details matter. There are IL opcodes representing the slots of where to put stuff and how to move it around. They must be there for generic methods. For This is something that a functional language compiler can gloss over. But the CLR wasn't designed specifically for functional languages, and functional languages only make up a minority of the languages and audience that target the CLR. |
Beta Was this translation helpful? Give feedback.
-
Does not matter. It's a CLR architecture mistake in the first place. There could be a slot with a well-known type "nothing". Clear distinction between "there is a slot" and "there is no slot" is a mistake. It's just a poor architecture design indeed. CLR does have lots of good architecture design decisions, but CLR is designed to be a "language agnostic" to a large extent and C# itself is a multi-paradigm language, but |
Beta Was this translation helpful? Give feedback.
-
Isn't that a little strong language to use? Take it from the CLR perspective. If |
Beta Was this translation helpful? Give feedback.
-
It's not a C-like special case, it's an imperative programming normal case, and it applies to the majority of the programming languages. All CPUs have this exact same design. You don't push/pop nothing. It's the functional language compilers that hide that reality from you, and nothing prevents them from doing that here as well. It's silly to suggest that all of the non-functional languages (read, every language designed by MS in the .NET 1.x timeframe) should have to work around design decisions specific for functional languages. |
Beta Was this translation helpful? Give feedback.
-
"poor design" is a strong language? Well...
Not so pointless as it would allow to chain function invocations and to do many useful tricks as you can do it with any form of homebrew It's like a "type erasure" in Java's generics implementation. Because Java wasn't designed for generics in the first place then generics was implemented in lame way on the top of the existing VM specification. |
Beta Was this translation helpful? Give feedback.
-
Unit is a type which does have only one valid value. Only one valid value means that such a type contains exactly no information. So
What storage? Unit does not contain any information. There is nothing to store. Even if actual
I'm saying it not from the point of view of "functional languages adept", but from the point of view of a person who thinks that OOP, functional, imperative, etc are just convenient abstractions around same things. There is a joke about "closure is a poor man's class" and then "class is a poor man's closure". This joke reflects a fact that OOP and functional languages in reality are abstractions designed to express same things, but from a different convenient points of view. OOP languages and functional languages are both practical applications of same mathematical theories, but for different people and for different real-world tasks. And also
Current understanding of |
Beta Was this translation helpful? Give feedback.
-
Convenient but different abstractions. The CPU, like the CLR, has no concept of "zero-sized structs" or "empty values". You have addresses and you have opcodes to operate on those addresses. Functional approaches "empty" differently from imperative. As a result, unit and void are not the same abstractions for the lack of data.
The concept of It's all moot anyway. This conversation has happened several times and based on the few comments from the LDM they have no appetite to take on such a massive task given that it wouldn't benefit any of the existing APIs. |
Beta Was this translation helpful? Give feedback.
-
Sorry for interrupting but don't you think this discussion is counterproductive? |
Beta Was this translation helpful? Give feedback.
-
I agree. I do like the idea of adding public unit Foo()
{
if (someCondition)
{
return; // no return value required
}
doSomeStuff();
// no return statement required
} It'd also be nice if the JIT could recognize such patterns with this "empty" struct (or any "empty" struct) and perform additional optimizations. |
Beta Was this translation helpful? Give feedback.
-
I think we can take it as read that the CLR was not designed to accommodate a But that is orthogonal to this proposal, as far as I can see. All that's being asked for is that I personally would also like to see unit Foo() => (); It's a simple change that achieves 80% (made up figure) of what's required. so is probably good enough. |
Beta Was this translation helpful? Give feedback.
-
I've recently discovered the need for
|
Beta Was this translation helpful? Give feedback.
-
Creating an official alias/keyword for unit has merit, but I worry that any compiler based magic compatibility has a real risk of causing problems. To illustrate, assume you have the following declarations:
Both
To achieve compatibility between What if we now have these declarations:
(This based on a common code pattern I've seen and used many times.) When we pass
We can't pass The compiler could wrap delta in another delegate to do a conversion, like this:
Unfortunately, this means the delegate actually passed to This is exactly the kind of subtle bug that would lead a team to say "Avoid unit at all costs, it's buggy." and that would be unfortunate. There are other consequences too, including a performance hit for bouncing through the extra delegate (admittedly low, but certainly not zero) and an increase in the heap overhead of using delegates. |
Beta Was this translation helpful? Give feedback.
-
I wonder if simply adding support for For example, it allows consumers to declare this:
instead of
|
Beta Was this translation helpful? Give feedback.
-
You couldn't pass It's my opinion that the addition of Compiler magic to make using System;
public class C {
public void M(Action a) { }
public T M<T>(Func<T> a) => a();
public void M() {
M(() => Console.WriteLine("foo"));
}
} In adding |
Beta Was this translation helpful? Give feedback.
-
Or perhaps we can solve this problem by using aliases: #1170 |
Beta Was this translation helpful? Give feedback.
-
Functional languages need a unit type due to the distinction between a function and a procedure. Since methods can either return "something" or "nothing", representing a new "nothing" type in addition to void adds just more language clutter. The BCL could provide a default Unit type for interop between functional languages, but C# is not one of them. Besides conveniency for generic types, I see no other use. For generic types, I think |
Beta Was this translation helpful? Give feedback.
-
There's a problem with this: public int M<T>(Func<T> func) //'T' is the output, like you said
{
var t = func(); //whoops, can't do this for 'void'
} |
Beta Was this translation helpful? Give feedback.
-
Unless Edit: An example of a use case I can think of: interface ICaller<T>
{
T Call<TArg>(Func<TArg, T> f);
}
|
Beta Was this translation helpful? Give feedback.
-
@IllidanS4, you are wrong! C# is also a functional language. |
Beta Was this translation helpful? Give feedback.
-
@OnurGumus Nop, it support some functional features and it starting to look more and more like one but it lacks other things that functional languages has and C# is not there yet. |
Beta Was this translation helpful? Give feedback.
-
As C# progressing towards being functional, we really need some sort of unit type. And many libraries invent their own unit type that returns nothing causing incompatibilities. System.ValueTyple with zero items is a very good candidate for being a unit type so I use it. I believe it is a good idea to have it aliased as unit. The drawback of this approach is that introducing a new keyword might conflict with existing code. But that can be solved by language versioning anyway.
Beta Was this translation helpful? Give feedback.
All reactions