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

Cast to Nullable operator #555

Closed
lachbaer opened this issue May 8, 2017 · 20 comments
Closed

Cast to Nullable operator #555

lachbaer opened this issue May 8, 2017 · 20 comments

Comments

@lachbaer
Copy link
Contributor

lachbaer commented May 8, 2017

Syntax Sugar:
When there is the need for an explicit cast to a nullable the nullable type of the operand must be explicitly given.

// without (int?) error CS0173 occurs
int? posvalue = (value>0) ? (int?)value : null;

The type of the cast can however be infered by the compiler, so that the cast can be shortend.

int? posvalue = (value>0) ? (?)value : null;

The same for back casts, but with the ! character.

int value = (!)posvalue;

This is no definite proposal. Just a discussion whether you like it or not.

@erik-kallen
Copy link

IMO, in the ?: operator the cast should not be needed at all.

@jnm2
Copy link
Contributor

jnm2 commented May 8, 2017

This is already being taken care of with #33.

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

@erik-kallen I agree, like ?. is automatically cast to Nullable. But maybe there are existing conditions that forbid the ?: to be changed?

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

@jnm2 Does #33 take care of the back cast to a non-nullable type?

@jnm2
Copy link
Contributor

jnm2 commented May 8, 2017

@lachbaer It does not. I didn't see any reason for (!)posvalue just for nullables because we have posvalue.Value, and also because the non-nullable references proposal might already cover this for more than just nullables.

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

@jnm2 The reason is to use a cast expression rather than .Value. Maybe I am alone (again...?!), but I don't like it to have it a cast one way and a call the other. I like to have it a cast both ways. I think that it looks more coherent in the code.

@jnm2
Copy link
Contributor

jnm2 commented May 8, 2017

@lachbaer If the idea is to frame it as a cast to int, (int)posvalue works today and if I'm not mistaken posvalue! was being discussed for the non-nullable cast.

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

@jnm2

(int)posvalue works today

The idea here is to have that (int) be infered by (!). posvalue! looks okay on first sight, but isn't (!)posvalue more in the sense of cast instead of introducing a new construct to the language? Maybe this discussion should be put over there?

@jnm2
Copy link
Contributor

jnm2 commented May 8, 2017

Perhaps. #36

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

@jnm2 And what do you think about (!)posvalue vs. posvalue!, as a last statement here? 😄

@HaloFour
Copy link
Contributor

HaloFour commented May 8, 2017

@lachbaer

One syntax that has been unofficially proposed is a post-fix "damnit" operator !. It would apply to non-nullable reference types to force the operator to unwrap a nullable but I don't see why it wouldn't also unwrap a nullable value type:

string? name = GetName();
int length = name!.Length; // suppresses the possible nullable reference warning

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

@HaloFour That's rather a !. operator in accordance with ?. than a cast operator.

@jnm2
Copy link
Contributor

jnm2 commented May 8, 2017

@lachbaer I prefer posvalue!.ToString("x") over ((!)posvalue).ToString("x"), for example. It reads better. I also prefer posvalue.Value.ToString("x") over ((int)posvalue).ToString("x") for the same reason. I think the postfix operator is the best of all worlds because I do dislike both the cast and the .Value showing up everywhere.

@jnm2
Copy link
Contributor

jnm2 commented May 8, 2017

@lachbaer No, it's not a !. operator because this would also work: (name!).Length

@HaloFour
Copy link
Contributor

HaloFour commented May 8, 2017

@lachbaer

The member access isn't a part of the operator. All the ! operator does is to treat the nullable value as a non-nullable value. In the case of reference types it would permit member access or other use without a warning. It would also work in the following contexts:

void PrintName(string name) Console.WriteLine(name);

string? name = GetName();
PrintName(name!);
string definitelyNotNull = name!;

For nullable value types it could do the same thing by effectively just compiling down to a call to the Value property.

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

@jnm2 But those are "casts" that have a following operation, no "pure" casts var a = b!;.
The obj! "cast" would make perfect sense to me if there also was a var b = a?;, meaning obj? instead of (T?)obj (where we have that extra 'T' again, coming back to the initial idea). But maybe the team can put some brainpower in sorting out some of the ambiguities when parsing a ? token and make that work, too. A paranthesed expression (obj?) is always a last resort anyway.

@HaloFour
Copy link
Contributor

HaloFour commented May 8, 2017

Converting from a non-nullable type to a nullable type is a widening conversion. There's no need for an explicit cast.

int i = 123;
int? j = i;  // perfectly legal

The only real exception here is when it comes to conditional ternary operations as currently the compiler is unable to determine a common type between null and a value type. That's exactly what #33 seeks to fix. If you can think of other scenarios in which the nullable version would not be correctly inferred I'm sure that the team would be interested to know about it.

As for the inversion, it certainly makes sense to require some kind of cast operation. I think that the "damnit" operator covers those bases. I don't see it included in #36 or the current version of the proposal, so I might open a separate proposal specifically for it.

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

The only real exception here is when it comes to conditional ternary operations

Yeah, that's where I encountered it, too. Then there are probably no other occurances of the problem, otherwise they would already have been reported. About the widening, I sometimes explicitly cast the nullables, simply because I like it more verbose in some places.

I might open a separate proposal specifically for it.

Go ahead 😃

@CyrusNajmabadi
Copy link
Member

but I don't like it to have it a cast one way and a call the other. I like to have it a cast both ways. I think that it looks more coherent in the code.

Language features need to provide huge value to warrant inclusion. Today you have the following options already:

int value = posvalue.Value;
int value = (int)posvalue;

// and also if you don't want to throw on null
int value = posvalue.GetValueOrDefault();

We don't need a third way to do the exact same thing. Our language is not trying to be one where there are 3+ synonyms for non-common stuff. It just does not provide enough value in our eyes.

@lachbaer
Copy link
Contributor Author

lachbaer commented May 8, 2017

It just does not provide enough value in our eyes.

Definite statement. Closed.

@lachbaer lachbaer closed this as completed May 8, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants