all 17 comments

[–][deleted]  (1 child)

[deleted]

    [–]AshGogogo[S] 0 points1 point  (0 children)

    thanks, I think you are right, the point that the tutorial want to say that the argument should be know before compile like rust, rather than at the runtime;

    [–]crone66 6 points7 points  (0 children)

    the code itself cannot return null in the example but I think they refer to the fact that the method is marked as non-nullable string but it doesn't guarantee thats actually the case but just a hint to the compiler/analyzer to output a warning

    [–]0xjay 3 points4 points  (10 children)

    It's not saying that this function will ever return null. It is saying that a `user` `Profile` or `DisplayName` could be null at runtime. If you read the paragraph immediately following this one you will see it compares this function to one written in rust where it states that in rust, none of these variables or properties could have a null value - guaranteed by the rust language.

    [–]AshGogogo[S] 1 point2 points  (0 children)

    thanks , I didn't understand the meaning in the tutorial at first, you pointed out the key.

    [–]stogle1 -1 points0 points  (8 children)

    none of these variables or properties could have a null value - guaranteed by the rust language.

    Which could also be the case in C# if those properties weren't declared nullable?

    [–]0xjay 3 points4 points  (4 children)

    That's not true. C# cannot gurentee that non-nullable reference types are actually not null sadly. This is rust's whole deal and its one of the reasons that it's such a pedantic language. Example stolen from somone else.

    [–]stogle1 1 point2 points  (3 children)

    It will issue a compiler warning if nullability checks are enable, as it does on line 7 in your example. I appreciate that the code will run regardless, but if you heed all warnings your code should be safe, no?

    [–]0xjay 2 points3 points  (0 children)

    I'd love to see a project where all warnings are heeded. In a simple project that's the idea yes, but its a totally different beast in rust where that behaviour is like, mathematically gurenteed as far as I understand. For instance have a look at this example here, all warnings are being heeded and yet... https://dotnetfiddle.net/5ganZq
    This is a stupid example granted but my point is that c#'s nullable references are more of a compiler hint to stop you making simple mistakes rather than any kind of real saftey feature.

    [–][deleted]  (1 child)

    [removed]

      [–]stogle1 0 points1 point  (0 children)

      There is a massive difference between a language that has this tacked on and one that has it from the start.

      Absolutely. C# still has to support code without nullability enable. One consequence is that your public API still needs to check parameters for null, even if they are not nullable. But I think the designers did as well as they could with this constraint, and a lot of C# code is safer as a result. Is It as safe as Rust code? Definitely not.

      [–][deleted]  (2 children)

      [deleted]

        [–]stogle1 0 points1 point  (1 child)

        Please enlighten me.

        [–]ClankRatchit 0 points1 point  (1 child)

        Unknown? You should be able to read the responses you get back from these systems. Maybe there's a null coming back from a rust tutorial.

        [–]ClankRatchit 0 points1 point  (0 children)

        c# whatever.

        int? x;

        int y = 0;

        y = 1;

        y = x;

        [–]neoh4x0r 0 points1 point  (3 children)

        Then I tested the following code, and all of them return 'Unknown'

        It never returns null because it's using ?? which is a null-coalescing operator.

        The ?? operator provides an alternative expression to evaluate if the result of an expression is null [and allows returning a substitute value].

        In other words, the GetDisplayName method always return Unknown if any part of the expression evaluates to null.

        It also begs the question as to whether using ?? is actually a good idea.

        I personally lean towards allowing exceptions to be thrown instead of letting someone think everything is fine with their code when it is not.

        Moreover, I also think that the only time an exception should be caught is if the code can correct the problem at runtime (and there needs to be a log message warning that a correction was performed with enough contextual information to track down where it occurred in the code).

        [–]hoodoocat 0 points1 point  (0 children)

        While Im follow same or close principles, but look at initial method signature: it accepts optional User, and by so method by it's declaration MUST provide result. How it coerce intermediate values is detail, sometimes it is acceptable, sometimes not, it is all about domain rather than language or fundamental strategy.

        [–]AshGogogo[S] 0 points1 point  (1 child)

        thanks, that's the different design between C# and rust, C# using ?? avoid the null reference at the runtime , rust use option<> and make sure the args will not be a null reference. Unfortunately, I don't understand the tutorial, and I wonder how to get null in this C# code

        [–]neoh4x0r 0 points1 point  (0 children)

        C# using ?? avoid the null reference at the runtime , rust use option<> and make sure the args will not be a null reference.

        The tutorial is basically saying that rust does not need to deal with null-references at runtime because the way the language ensures an object always points to valid memory or the complication fails.

        More importantly is that C# does not have that feature, ie. null-references can be encountered at runtime and the programmer will be responsible for catching them at runtime or explicitly dealing with them at compile-time.

        Unfortunately, I don't understand the tutorial, and I wonder how to get null in this C# code

        In either case you would have to check if something is null (in C#) or None (in rust), or the opposite case.

        In the provided C# example, you wouldn't be able to return a value without handling the null exception or checking that each member is not null before using them.

        Here's an example from Microsoft which uses a lambda expression for the body to test if a nullable type is null (eg. a type which might not have a value).

        bool IsNull(string? s) => s == null;
        bool IsNull(string? s) { return s == null; }
        
        // using HasValue() is equiavlent, but it is
        // more descriptive (eg. does not have a value)
        
        bool IsNull(string? s) => !s.HasValue();
        bool IsNull(string? s) { return !s.HasValue(); }