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
Ref returns can't easily return null #1201
Comments
Ha ha, people are willing to stand on their heads to get rid of nulls and you want to add more? |
@mikedn |
@MohammadHamdyGhanem Why are you returning a |
@jnm2 |
@HaloFour |
Why do you have an opinion on whether they should be allowed to be null, then? |
@MohammadHamdyGhanem
|
@HaloFour |
@MohammadHamdyGhanem The safe way to do this is to have the caller pass a value for the default value: static string[] Students = { "Ali", "Hani", "Shady", "Hala" };
static ref string FindStudent(string name, ref string defaultValue)
{
for (int i = 0; i < Students.Length; i++)
{
ref string student = Students[i];
if (string.Equals(student, name))
{
return ref student;
}
}
return ref defaultValue;
} The reason to do this is that the caller can directly mutate the return value since it is a |
Why? Besides, if you try hard enough you may find that a solution to this problem actually exists. I suspect (I haven't tried) that it's possible to create a In any case, allowing |
@HaloFour
It can be used like this:
Thanks. |
@MohammadHamdyGhanem No, tuples were supposed to end the era of using Either way works. Although I prefer specifying that default value. |
That's a pretty bad idea. Imagine what happens if people forget to check if |
Or if the array is empty ... If anyone has any doubt to the complexity of this subject just enjoy the diatribe from Eric Lippert in the comments of the MSDN docs. He ain't wrong, but explaining this feature to a general purpose audience is going to be inherently tricky. |
@HaloFour |
Shouldn't this work with "ref-reassignment" and "declaration expression" features? static bool TryFind(string name, ref Student result) {
foreach (ref Student student in array) {
if (student.Name != name) continue;
result = ref student;
return true;
}
return false;
}
if (TryFind(name, ref var result = null) {
// found
} |
Suddenly, I realized why this is not a problem to solve easily. |
@MohammadHamdyGhanem
Sure it does. It solves a problem that can't be solved efficiently otherwise. "Modern" programming still relies on efficiency. The use cases which pushed the implementation of these features came primarily from CoreCLR in implementing the CLR on platforms other than Windows. So you might not rely on these features directly, but you (and everyone) benefits from the fact that critical components in the underlying frameworks do take advantage of them. |
@MohammadHamdyGhanem Please don't post identical content on multiple issues. #497 (comment) |
There are two types of null ref returns. The first, where the content of the ref is null, which requires you to declare some variable with its value set to null and then return a ref to that (as per the OP). The second is where the ref itself is null, which today can be simulated using The latter is not expressible directly in C# today, but is still useful in a number of scenarios, such as Interop code. |
Ah, so we're already in a world where any ref could be null. |
Not really. The language doesn't have such a concept. And somewhat strangely, the ECMA spec too claims that byrefs cannot be null.
That's an abomination. Or in the more civilized C++ speak (C++ too doesn't support null references but you can produce one by dereferencing a null pointer) it is "undefined behavior". |
Doesn't matter if the language has syntax for it. It was never possible before to make public unsafe static void Main()
{
ref var x = ref System.Runtime.CompilerServices.Unsafe.AsRef<object>(null);
UseRef(ref x);
}
public static void UseRef(ref object someRef)
{
var local = someRef;
} The only protection is to do something like this: public static void UseRef(ref object someRef)
{
unsafe
{
if (System.Runtime.CompilerServices.Unsafe.AsPointer<object>(ref someRef) == null)
throw new ArgumentNullRefException(nameof(someRef));
}
var local = someRef;
} |
It was always possible, it was only more difficult (you likely needed to write something like |
Of course the language doesn't have the concept. Like I said, that's not the point I was making. We're in a world where such a method is in the BCL and such null references are for the first time likely to start happening in the wild. |
Yes, I understand that. And the point I was trying to make is that it probably doesn't make sense to worry about null refs too much. Just like the existence of void foo(string s) {
if (s.GetType() != typeof(string)) {
throw new ArgumentException("?!"); // A suitable error message for a suitable situation
}
} |
@mikedn Oh, that's insane. Okay. I agree with the point that such checks don't scale and won't have ROI, so we may as well not do them. But we'll still need to know about them more often now that a BCL method call in a non- |
@mikedn, @jnm2. I think that a null ref is a bit different from lying about a type. Receiving a ref that is null can easily happen by writing P /Invoke or COM Interop method that uses ref instead of pointers on a blittable type. It doesn't necessarily require you to use S.R.CS.Unsafe (where-as there are actual checks for managed types that would prevent you from doing the equivalent of As{T} since they require actual marshaling). |
So there are actual places where checking if a ref is null may be required and where they make sense. Although I am not sure if that qualifies it for needing language support. |
Examples? The claim is dubious as until recently |
return by reference needs a place in memory (valid reference) so if caller wants to assign to returned reference it can do so.
If you call if you were to return null reference then you could get lot of unexpected exceptions. you can not assign. you cant access to any member of that object simply because there is no reference. |
Ref Returns Docs says:
"The return value cannot be a null. Attempting to return null generates compiler error CS8156, "An expression cannot be used in this context because it may not be returned by reference."
If a method with a ref return needs to return a null value, you can either return a null (uninstantiated) value for a reference type or a nullable type for a value type."
So I have to do this:
I have to declare a non local variable without any purpose except to allow my function to return null!! It can't be a local variable because it can't be used as a ref return!
What on earth is that? Why can't I simply write:
return null
?!
Please fix this ugliness!
EDIT:
Suddenly, I realized why this is not a problem to solve easily.
Returning null doesn't mean a null reference. This is a high level ref not a pointer, and when we read it's value, we get the actual stored value not the storage address(pointer)! So, when we check the return value to be null, this means the reference carries a null value, not itself is null.
So, this can't be a valid test for a function failure, because if the function deals with objects, and returned the ref of one of them, it is possible that this object is null and this is a valid result not an indication for not finding a result!!
Oh, man! It is very confusing. We lived happily ever before ref returns!
The text was updated successfully, but these errors were encountered: