Replies: 1 comment
-
The proposed solution at https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-05-15.md#user-content-unconstrained-t sounds like it fits my needs here. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
@bkoelman commented on Tue Mar 22 2016
I propose to no longer issue
CS0453
on methods with the next signature in the features/NullableReferenceTypes branch:but instead, consider the signature equivalent to:
where
[Nullable]
refers to the inaccessible compiler-builtin annotation for a nullable reference type.I believe this will not break existing code, as the construct is currently not allowed:
Applying this proposal would enable callers to pass in value types (which get boxed), nullable value types (get boxed), never-null reference types and nullable reference types.
To clarify: In this proposal, the unconstrained generic type
T?
is interpreted as[Nullable] T
, notNullable<T>
.This proposal aims to not:
From what I understand, this seems very straightforward. Without asking for alternative proposals (or potential theoretical scenarios), are there any reasons that make doing this impossible?
I am aware this proposal makes it impossible to have these two overloads:
as their signatures (from a CLR perspective) are not overloads. That does not bother me, though.
I would appreciate to center the discussion around the current prototype, not other directions it may or may not take in the future. Therefore, I'd kindly ask you to verify your assumptions against the actual prototype before responding. This prevents the discussion steering somewhere else, based on (incorrect) assumptions.
@bkoelman commented on Tue Mar 22 2016
CC @MadsTorgersen @AlekseyTs
@HaloFour commented on Tue Mar 22 2016
So the net result of this proposal is the following:
That may be confusing.
Is it really necessary to have this proposal be separate from #9932 ?
@alrz commented on Tue Mar 22 2016
@bkoelman
How this is supposed to work?
@alrz commented on Tue Mar 22 2016
I'll also note that
This is already a compile-time error. How possibly this proposal aims to _NOT_ require CLR changes?
@bkoelman commented on Tue Mar 22 2016
Did you verify that it's a compile error?
@alrz commented on Tue Mar 22 2016
@bkoelman arg can never be null if
T
is a value type. I think that is the point.@alrz commented on Tue Mar 22 2016
@bkoelman If you are talking about
M3<int?>(null)
then I have no idea howM3<T>(T arg, T? arg2)
would work.@HaloFour commented on Tue Mar 22 2016
My preference would be that if you wanted to abuse the new attributes then you should do so explicitly and that the
?
suffix shouldn't blindly mean to apply said attribute in cases when the type isn't a reference type. Even if nullable equivalence is not possible in the C# 8.0 time frame (or whenever this might ship) I'd rather leave that syntax open to better future enhancement.@bkoelman commented on Tue Mar 22 2016
@HaloFour
@alrz
I get that T? in this case means "reference type only". That's because T is unconstrained. You may not like that, but that is actually what I am proposing.
@HaloFour
@alrz commented on Tue Mar 22 2016
@bkoelman
No,
T
is not a reference type, it is just a generic type.Actually the title doesn't make sense to me, "Allow unconstrained generic type parameters to be nullable references" an unconstrained generic type is not a value type nor a reference type.
@bkoelman commented on Tue Mar 22 2016
@alrz That is the key point of my proposal.
Today, for an unconstrained T parameter, you can pass in
int
,int?
andstring
. That's stays as-is.For an unconstrained T? parameter, you get a compile error today. I propose to change that to: consider T? a nullable reference type, which allows you to pass in
int
(auto-boxed),int?
(auto-boxed),string
andstring?
.Obviously, when adding
where T : struct
orwhere T : class
this rule no longer applies.That's all.
@HaloFour commented on Tue Mar 22 2016
@alrz Oops, updated comment.
@bkoelman I haven't toyed with the branch yet, but how is the attribute inaccessible? The type would need to be public and have a public constructor if the compiler were going to apply it, so I don't know how you wouldn't then be able to apply it manually unless the compiler was explicitly forbidding you from using that attribute manually. This is what the compiler does with
System.Runtime.CompilerServices.ExtensionAttribute
so that's not without precedent. And if the compiler were to be strictly preventing you from using the attribute manually in arbitrary/inappropriate cases then I would think that the compiler should also prevent you from using it where it doesn't make sense, like an unconstrained generic type.@bkoelman commented on Tue Mar 22 2016
@HaloFour I'm not sure why. Maybe you can fetch the branch and give it a try?
@HaloFour commented on Tue Mar 22 2016
@bkoelman
So, wait, you're proposing that it be possible that
M<T>(T? value)
be able to accept anint?
whenT
isint
?@alrz commented on Tue Mar 22 2016
That was also my question when I said I don't know how
M3<T>(T arg, T? arg2)
would work (forint
).@bkoelman commented on Tue Mar 22 2016
void M3<T>(T arg, T? arg2)
without constraints translates to:@alrz commented on Tue Mar 22 2016
M3(5, null). BOOM.
@alrz commented on Tue Mar 22 2016
I think you have no idea why we would want to use nullable generics.
@bkoelman commented on Tue Mar 22 2016
That would be a compile error, just like today. It's ambiguous.
This would work, though:
"We?" I cannot look into your head, only explain what I want. If you don't like it, feel free to explain why or walk away, not accuse me of "having no idea". It helps to have a compiler at hand and show actual working code samples, like I do. I'm inviting you to do the same.
@alrz commented on Tue Mar 22 2016
because we might want to pass null.
No it wouldn't.
@bkoelman commented on Tue Mar 22 2016
error CS0411: The type arguments for method 'Program.M3<T>(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
So if it fails today, I'm fine with the proposal also failing on that. Or am I missing something?
@alrz commented on Tue Mar 22 2016
@bkoelman Here you go.
@bkoelman commented on Tue Mar 22 2016
@alrz I honestly don't get what you are implying. The proposal is not about nullable type unification. Passing in a
int
and astring
for the sameT
does not work today and the proposal does not solve that. Point taken. Any other objections?@alrz commented on Tue Mar 22 2016
@bkoelman Yes it does not and it has nothing to do with nullable generics I guess.
My question is, that if it fails if I pass
null
, why on Earth would I want to make itNullable
?@bkoelman commented on Tue Mar 22 2016
You can pass in
null
:You just cannot mix value types and reference types. That's a limitation.
@alrz commented on Tue Mar 22 2016
@bkoelman So close. However
M((int)5, (int?)null);
is actuallyM<int?>(5, null)
which callsM<int?>(int?,int?)
but I didn't define the first parameter as nullable right? So what if someone passnull
as the first argument likeM<int?>(null, null)
?@bkoelman commented on Tue Mar 22 2016
If I run that:
It prints:
5 null
null 5
In that case, they all are nullable value types. The [Nullable] annotation (added by compiler) is ignored. It prints what I would expect. What is the problem with that?
@alrz commented on Tue Mar 22 2016
The fact that type parameter itself can be nullable should not confuse you. For example,
You won't be able to call this method like
M<int?>( .. )
because you can't have a nullable of a nullable. Same would apply to nullable reference types.PS: That was a lot of nullables in one sentence.
@bkoelman commented on Tue Mar 22 2016
That's why the proposal only concerns unconstrained generics. Constrained generics are a different story, out of scope for this proposal. From a puristic point of view, you are right that it feels somewhat strange or inconsistent. In practice though, its working out great for me.
@alrz commented on Tue Mar 22 2016
@bkoelman "It works" doesn't mean that it should compile. Sometimes it means that you should get a compile-time error. In this example you must not be able to pass null as the first argument.
@alrz commented on Tue Mar 22 2016
Nullable types have an inherent constraint: the type itself must not be nullable short of being a value type or reference type.
@bkoelman commented on Tue Mar 22 2016
Ok, thanks for pointing that out.
Beta Was this translation helpful? Give feedback.
All reactions