Added: C# Language Design Notes for Jul 24 and 26, 2017 #791
Replies: 16 comments
-
Consider overlap with nullable ref types? e.g. |
Beta Was this translation helpful? Give feedback.
-
I don't understand why ? should be on |
Beta Was this translation helpful? Give feedback.
-
@MadsTorgersen The the following is really weird:
Many times, in this case, you may want to also check that the name is empty and throw so why would you add a special syntax for one but not the other? Yes, checking for nulls is probably more common but it also really weird that we have special way to express it in the language whereas we can't do it for say strings and arrays which probably comes after checking for nulls. I'd really prefer to have proper support for contracts in the language then to poison the code with a special syntax, I mean what's next? |
Beta Was this translation helpful? Give feedback.
-
@alrz that's a different thing that is null; its saying the pointer points at null; vs the pointer variable itself is null You can't do static ref int Find(int[] array, int value)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] == value) return ref array[i];
}
// What do you return here? null, default etc?
} Suggestion would be something like static ref? int Find(int[] array, int value)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] == value) return ref array[i];
}
return null; // or default
} However a |
Beta Was this translation helpful? Give feedback.
-
You can't initialize a by-reference variable with a "value", I'm thinking that it should always point to a "ref" so it doesn't even make sense to say private static int dummy = default;
static ref int Find(int[] array, int value)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] == value) return ref array[i];
}
return ref dummy;
} In Rust, |
Beta Was this translation helpful? Give feedback.
-
That would result in an incorrect algo as you wouldn't know if it was found; so it would instead need to be private static int dummy = default;
static (ref int, bool) Find(int[] array, int value)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] == value) return (ref array[i], true);
}
return (ref dummy, false);
} At which point you are creating an new ValueTuple for each return.
Looking at what's going on at a lower level its more like: static IntPtr int Find(int[] array, int value)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] == value) return &array[i];
}
return null; // or default
} As a Except... a ref being null would be a violation of what a A null |
Beta Was this translation helpful? Give feedback.
-
The If you have a "rarely null" object, maybe the right course of action is to rethink the design rather than add an operator that allows undercutting the feature. |
Beta Was this translation helpful? Give feedback.
-
Am I understanding this correctly? This bothers me deeply:
If you are setting the property this is fine, but if you are getting the value, the property's contract promises that it will never return |
Beta Was this translation helpful? Give feedback.
-
Agreed. "Rarely nullable" is still nullable and justifying the violation of that contract smacks of nothing less than sloppy design. Expediency is never an excuse. The fact that the Roslyn codebase exhibits some of these patterns is only evidence that it will also arise in other codebases written and maintained by developers less adept than I assume the C# team is. As such, Roslyn should strive to demonstrate idiomatic migration and use of this feature. It should be no less painful for you guys, especially as you are now debating through just how painful it should be. Swallow your own medicine, do it thoughtfully and encourage proper use of this feature. |
Beta Was this translation helpful? Give feedback.
-
This comment is retracted: see my reply to @Joe4evr for reasons why. |
Beta Was this translation helpful? Give feedback.
-
Having had time to thing about our discussion around #pragma warning disable xxxx
T Foo()
{
...
}
#pragma warning enable xxxx wins out in my view. It has the same effect. It is far more glaringly obvious that a special case, "rarely null", is being handled. And it's a pain to write, thus ensuring it will genuinely only be used in those edge cases where a rarely null reference absolutely is unavoidable without compromising the code in some other significant way. |
Beta Was this translation helpful? Give feedback.
-
The idea behind public class Foo
{
public Bar? Bar { get; }
public bool HasABar => Bar != null;
public async Task Baz()
{
if (HasABar)
{
//compiler would warn here because the flow analysis is ignorant of what the previous line does
await Bar.DoTheThing();
}
}
}
I keep coming back to wanting a |
Beta Was this translation helpful? Give feedback.
-
So we have a situation that flow analysis will be used to determine "nullness" of a reference. But that flow checking will only analyse the local context (eg the code within a method, not other methods/properties called by that code). As a result, for folk that like to structure their code such that explicit expressions are replaced with small methods and properties, that flow analysis will fail. This is a bad place to be, as it discourages this good practice. So the proposed solution is a shorthand "hey compiler, don't worry, I know what I'm doing" syntax that suppresses warnings resulting from the limited flow analysis that the compiler performs. However, the fact remains, most developers really do not know what they are doing half the time, so they'll misuse this feature to suppress warnings they do not properly understand and they'll be left uttering "dammit"... I am really beginning to sympathise with the team here. I really want this feature and I really want it to be done right. But it's clear that really doing it right is a nigh on impossible task. I still feel that |
Beta Was this translation helpful? Give feedback.
-
Of course, the solution is to not allow public class Foo
{
public Bar Bar { get; }
public async Task Baz() => await Bar.DoTheThing();
} but not only would re-educating folk to avoid |
Beta Was this translation helpful? Give feedback.
-
I have to disagree. I was thinking through how the framework would cope with nullable reference types. By way of an example, I'll use public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate)
{
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
return WhereIterator<TSource>(source, predicate);
} My initial thought was that this could just be changed to: [assembly: NonNull]
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate) =>
WhereIterator<TSource>(source, predicate); But that would break backward compatibility with previous language versions in a horrific way. So those null checks are needed. Those null checks are really common in code and need to be kept for backward compatibility, but since public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source!,
Func<TSource, int, bool> predicate!) =>
WhereIterator<TSource>(source, predicate); Which is a much neater version in my view. Sure, when handling strings, one might check for empty strings too. When handling class public string FullName(string givenName!, string familyName!) =>
givenName.Length > 0 && familyName.Length > 0
? $"{givenName} {familyName}"
: throw new BadNameException("Both given and family name must be specified"); To my mind, this is such a useful feature, it stands on its own and could even be introduced prior to nullable reference types being added to the language. |
Beta Was this translation helpful? Give feedback.
-
@DavidArno I see your point, I agree. ;) p.s. I said it's weird and not that it isn't useful because my thoughts were about adding proper contracts support to the language but then this feature doesn't really negate the possibility so it's all good. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
C# Language Design Notes for Jul 24 and 26, 2017
We started putting a series of stakes in the ground for nullable reference types, based on the evolving strawman proposal here. We're doing our first implementation of the feature based on this, and can then refine as we learn things from usage.
Please discuss!
Beta Was this translation helpful? Give feedback.
All reactions