Added: C# Language Design Review, Oct 4, 2017 #975
Replies: 46 comments
-
I kinda agree with "checking dotted names makes sense, since that's what people do", but at the same time I don't. Multithreaded programs are already hard to debug, and if developers are taught to rely on nullability checkers they will likely miss cases where dotted chains are mutated from another thread. Then nullability checks on dotten names will join other "C# gotchas". What if there was a lightbulb fix for the warning? if (foo.bar.baz != null) HandleNonNullable(foo.bar.baz);
//a lightbulb proposes to turn this into
if (foo.bar.baz is var baz && baz != null) HandleNonNullable(baz);
//of, if declaration expressions are implemented
if ((var baz = foo.bar.baz) != null) HandleNonNullable(baz); |
Beta Was this translation helpful? Give feedback.
-
Fair choice, but I would prefer philosophy like "the language design makes the guarantee possible, but a particular compiler/IDE implementation might choose to loosen/tighten it over the time; we recognize that C# developers come in all skill levels and thus deserve to have options".
I don't know, Rust-style would look appetizing: var array = new string[] = [""; 10]; |
Beta Was this translation helpful? Give feedback.
-
Is there any word on what this comment from back on the Roslyn thread mentioned, specifically the auto-insertion of a temp variable? I see so many people here being gung-ho about wanting a new construct like if (foo.Bar.Baz is var baz) or something so they have a null-check and local reference in one go, whereas that comment says the compiler could just take the existing |
Beta Was this translation helpful? Give feedback.
-
It would be really nice to have an analyzer to "infer" nullability of types and annotate them accordingly. It wouldn't be a simple analyzer but it would be a great win in the adoption story. |
Beta Was this translation helpful? Give feedback.
-
var array = new string[10];
I don't get this logic. What is unappetizing about changing this to: var array = new string?[10]; // array is string?[] which is all that would be needed to fix the warning? Or alternatively, lying to the compiler to suppress the warning: var array = new string[10]!; // array is string[] Not warning on this would be irresponsible in my view as it creates a glaring hole in the reliability of any analysis. Given that it's irresponsible, along with the option of marking the array as |
Beta Was this translation helpful? Give feedback.
-
@Joe4evr, if (foo.Bar.Baz is let baz)
if (foo.Bar.Baz is value baz) would address the "null-checked variable without having specify the type" desire. I've checked the raw notes that @MadsTorgersen has put up but there's no mention of them (or anything similar). SO I'm guessing it hasn't been discussed yet. |
Beta Was this translation helpful? Give feedback.
-
@dsaf I have created #976 to support creation of initialized arrays. |
Beta Was this translation helpful? Give feedback.
-
I must have missed something; this seems a dramatic departure from recent meetings.
Same with this, but I'm pleased with this philosophy. |
Beta Was this translation helpful? Give feedback.
-
I tend to agree with @orthoxerox's proposed solution to the multi-thread or intervening call situation. Not quite satisfied with the analyzer decision on this. |
Beta Was this translation helpful? Give feedback.
-
I agree that nullability should be tracked across dotted chains. I do not agree that this should be scrapped or modified in some way because of the possibility of cross-thread modifications. Most assumptions about the evaluation order of your code are off if you're writing that kind of shared-state multi-threaded code. Unless you're an expert in it you probably should be avoiding it anyway. It doesn't make sense to gimp new features because they won't work well in cross-thread contexts, or else we'd never get new features. |
Beta Was this translation helpful? Give feedback.
-
@MgSam threading is only an example of the problem. the real problem is any "other" code, which could be a hard-to-track race condition or it could be an innocuous method call. Consider:
I actually don't mind this behavior; I'd rather have it catch some bugs than no bugs. I guess the counter-argument is that some devs will assume their code is safe if the compiler doesn't give a warning. Interesting thought: if we could mark something as somehow "fully verified", Roslyn could potentially optimize things a little better -- simplest probably being to emit |
Beta Was this translation helpful? Give feedback.
-
I understand that. I agree with the sentiment in the proposal. Code like you example is the exception, and its better to make the feature useful in the majority case. If people can't do if(foo.Bar == null) return;
foo.Bar.Baz();
foo.Bar.Bark();
foo.Bar.Items.Add(...); without getting warnings all over the place they're just going to turn the feature off (or ignore the warnings) and never look back. |
Beta Was this translation helpful? Give feedback.
-
@MgSam Poor example because calling if (foo.Bar == null) return;
foo.Baz();
foo.Bark();
foo.Bar.Items.Add(...); |
Beta Was this translation helpful? Give feedback.
-
No lie, I just got bitten by this: foo.Bar.Baz();
if (foo.Bar.Qux) // Bam, foo.Bar is null.
{ That's code I wrote in February. |
Beta Was this translation helpful? Give feedback.
-
FWIW, the behaviour I've observed from Code Contracts - and this behaviour works quite well in practice - is:
|
Beta Was this translation helpful? Give feedback.
-
I wonder if the only feasible way — is for C# compiler to analyze IL and flows of the binary DLL dependencies. |
Beta Was this translation helpful? Give feedback.
-
Yes. Also, another part of the proposal is an optional mechanism to let the compiler generate a runtime check for your method parameters, if you really wanted to be sure.
Uhm? You can put
Probably quite a bit, but I take it that it's part of the effort. If nothing else, I can see MS starting off with the core types, and adding more annotations over time.
Not all that much you can do here, I think. The main idea is that from the moment you get an object ready to consume that the annotations will show which properties can and cannot be expected to contain
IIRC, if you opt-in but one of your dependencies did not, that dependency is considered "null-oblivious" and the compiler won't give warnings when calling in/dereferencing returns from those APIs (exact same behavior as today). |
Beta Was this translation helpful? Give feedback.
-
@Joe4evr lack of C# use cases leads to haphazard guesses. That's why it would be prudent for the compiler team to do that early. I wouldn't want to discuss your assumptions on how it might work, as they paint a rather grim prospect (lots of effort to refactor existing code etc.) Hoping C# code examples would be sunnier. |
Beta Was this translation helpful? Give feedback.
-
Does it really? Let me provide an example. I work on an extraordinarily large .NET enterprise application. For one project, we invested rather heavily in Code Contracts, primarily for the purposes of detecting null references early and preventing us shipping such bugs. This has been incredibly valuable (though at this point, the cost of Code Contracts is starting to outweigh the benefits). I can count on my hands the number of times that we've had a By contrast, Why would you want to pay developers to clean up mistakes in arrears when you can have the computer prevent that mistake in advance? Similarly, I often have to dig into documentation or into implementation code to figure out if a function can actually return null, and if so, what I should do about it. But, when writing Swift for some small personal iOS projects, I have absolutely none of these concerns. Something is either After using a language with strict nullability rules for about 30 minutes, you really can't go back to languages where anything could be an object, or could be null, whoops we won't tell you until runtime.
Would it really? The general case - and hence the problem with nulls - is that I expect a value to be non-null in a majority of cases. If you could have a look at the codebase I mentioned above, you'd see that almost every single reference typed field or parameter has
Code Contracts technically aren't binding unless you jump through a very long series of hoops. Also, it's not a "C# feature". I agree on this point, however. I would love it if, like Swift, nullability was part of the method signature and runtime enforcable. However, I do acknowledge that doing so would fully break compatibility on every level, and is not worth the cost for .NET.
I would argue that this should only be done on public API surface (including private implementations of public interfaces), and perhaps should be left as manual. Once you're into the internals of a library, the compiler should have been able to prove already that your value is not null, so further checks are worthless. |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h totally 100% agree with your long journey with Contracts, and the ultimate judgement (and the general industry sentiment): the cost of Code Contracts is starting to outweigh the benefits By the way, thanks for your intuition/speculation, but can it replace a concrete C# example? * can libraries declare non-null inputs and skip manual null checks? ... |
Beta Was this translation helpful? Give feedback.
-
Is it really that hard to understand? public void Foo(string! s) //compiler-generated null-check
{
} |
Beta Was this translation helpful? Give feedback.
-
@Joe4evr now you're on the right track — would be awesome if your example looked more real, and showed valueadd. |
Beta Was this translation helpful? Give feedback.
-
😄 I think regarding examples though, you're barking a bit up the wrong tree at this stage. You don't need a large complicated function to see what one small tweak would do and how it should behave. For flow analysis, perhaps, but not for syntactic markers. |
Beta Was this translation helpful? Give feedback.
-
The beauty of nullability is too bright for mortal eyes. |
Beta Was this translation helpful? Give feedback.
-
Lol... wut... |
Beta Was this translation helpful? Give feedback.
-
Real C# code examples for a C# feature is a reasonable requirement, neither lol nor wut nor barking at a tree. |
Beta Was this translation helpful? Give feedback.
-
The last three things you had said still don't make sense together... |
Beta Was this translation helpful? Give feedback.
-
That's what the strawman proposals are for, to test the various flavors of the implementation against real-world code bases. This conversation is well past the point of gathering requirements and use cases. The value-add has already been established. We're at the point of hammering out the nitty gritty details and measuring the impact to developers who wish to opt-in. |
Beta Was this translation helpful? Give feedback.
-
Is void M(string o) { // or string?
Debug.Assert(o != null);
// ...
var x = o.Length; // No warnings on debug?
} Also it would be helpful to take existing null checks into account when we warn possible nulls, void M(string o) {
var x = o?.Length; // there is a null check in pre-NRT code so nulls are expected
// ...
var y = o.Length; // this is possible null dereference!
} We could first suggest to convert |
Beta Was this translation helpful? Give feedback.
-
Debug.Assert is not present in release builds, yet I would rather always have the warning or it would take me by surprise. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
C# Language Design Review, Oct 4, 2017
We looked at nullable reference types with the reviewers, Anders Hejlsberg and Kevin Pilch.
Please discuss!
Beta Was this translation helpful? Give feedback.
All reactions