Earnestly thinking NULL is a mistake is a symptom


  • Discourse touched me in a no-no place

    @Gaska said:

    Java 8 introduces @NonNull annotation. Though personally, I'd prefer something like @Strict annotation at package level rather than having to repeat the same annotation over and over again everywhere in all my files (@Strict reduces it to just once in every file; not ideal, but bearable).

    I wonder whether it is inheritable from interfaces. If it is a part of the interface contract like that (I think it ought to be) then it is much more acceptable.


  • Banned

    @NonNull is part of type, it seems. You can think of it as analogous to C/C++ cv-qualifiers.


  • Discourse touched me in a no-no place

    @Gaska said:

    @NonNull is part of type, it seems.

    It used to be that annotations on method arguments were not inherited from interfaces, but I've not checked whether that changed (even as a “you must ask for this by the right meta-annotation”) in Java 8.


  • Banned

    Probably not, given that I can't google it up.

    What a shame.



  • @ben_lubar said:

    Not only that, but Optional<T> can also be null. (Unless Java 8 introduced a primitive that violates Java naming conventions) So you have two kinds of null instead of just one.

    You mean like...

       Optional<String> something = null;
    

    I imagine that would be legal, yes; I don't see how it would be prevented within the language. Violates the principle. Stupid thing to do. But then that's what this site is about: people who do stupid things that violate principles.

    @xaade said:

    Wait, what? What other purpose would Optional serve other to indication non-value result?

    I repeat: people who violate principles! Just because there's a sensible use pattern for a feature doesn't mean the run of the mill idiot is going to use that pattern.



  • @anonymous234 said:

    What writing system is there that's not in Unicode? Is he talking about this guy?

    Seriously. Unicode is nowhere near "done".



  • @Gaska said:

    Have you ever wondered why the IsNullOrEmpty() function was made?

    No, but I have wondered what you are asking about as this seems to be a function for Strings, not Lists.


  • Banned

    Because the rationale for IsNullOrEmpty() is also the answer to your question about lists.



  • A List is a collection of multiple objects. A String is generally treated as a single object. They aren't really comparable.
    I have seen null-or-empty checks a fair bit in code for strings, but never for lists.


  • Banned

    @Salamander said:

    A List is a collection of multiple objects. A String is generally treated as a single object. They aren't really comparable.

    Both have an empty state, and (in a language with nullable references) both can be null instead of just empty (remember that list is an object itself too). And by one of Murphy's laws, if something stupid is possible, someone will do it - like interchangeably use empty list/string and null.

    @Salamander said:

    I have seen null-or-empty checks a fair bit in code for strings, but never for lists.

    I have seen null-or-false checks on fucking booleans.



  • @Gaska said:

    I have seen null-or-false checks on fucking booleans.

    LOL. Now that shows a clear understanding (not!) of quality programming principles.



  • @Gaska said:

    Both have an empty state, and (in a language with nullable references) both can be null instead of just empty (remember that list is an object itself too).

    List itself being an object is not relevant. A list contains values, while a string is its value.

    @Gaska said:

    And by one of Murphy's laws, if something stupid is possible, someone will do it - like interchangeably use empty list/string and null.

    And then they get an exception, like virtually every other method that accepts a list.


  • Banned

    @Salamander said:

    List itself being an object is not relevant. A list contains values, while a string is its value.

    It is relevant because nothing* prevents the caller of your function to pass null in place of a list.

    @Salamander said:

    And then they get an exception, like virtually every other method that accepts a list.

    Only at runtime.



  • @Gaska said:

    It is relevant because nothing* prevents the caller of your function to pass null in place of a list.

    Yes, and it's usually an error when they do. I've seen null instead of an empty list precisely once and that was exactly what was wrong: the calling method was broken.
    So I fixed it where the problem occurred instead of the methods it was calling.

    @Gaska said:

    Only at runtime.

    In an ideal world, you would be able to specify that passing null lists is a compile error. Unfortunately we're not there yet, so runtime is the best they get.



  • You can test someSlice == nil or you can test len(someSlice) == 0. The former is true if the slice is nil and the latter is true in both cases.


  • Banned

    @Salamander said:

    In an ideal world, you would be able to specify that passing null lists is a compile error. Unfortunately we're not there yet, so runtime is the best they get.

    Actually, we are there already. There are languages that make it possible to statically enforce the given variable will never ever be assigned null. They're not widespread, unfortunately, and legacy code will never be fixed, but still.



  • @Gaska said:

    It shouldn't be bool Dictionary<Key,Value>.TryGetValue(Key key, out Value value) to start with. It should be Optional<Value> Dictionary<Key,Value>.GetValue(Key key).

    What's the difference between returning Optional<Value> and Value. Either way you can be aware that the return may not have a value, just by looking at the documentation.

    But can't you do the same thing with an attribute on the method to indicate returned values may be null?

    @CoyneTheDup said:

    I imagine that would be legal, yes; I don't see how it would be prevented within the language.

    You'd have to make that prevention part of the language.

    As is, it's no different than reading the documentation for the method.

    So, in C# Optional<T> does nothing. It merely suggests that the internal value can be null, which is no different than ANY OTHER REFERENCE.

    For it to have any meaning, you'd have to follow a coding standard.

    Which is something you can do without Optional<T>.


    In the future, we can write a language that requires marking a reference as nullable, without fancy generic bullshit that just adds nuance.

    But that doesn't remove NULL from the language.

    And as such, the OP's OP (complaining about NULL) is total bullshit.


    In fact, the only ways I can imagine removing null from the language, is to make everything a list, with a list class that supports only 0 or 1 entries, or to make everything in the language a dynamic.



  • You should check out Rust, I was actually impressed by the way it handles stuff like this.



  • So basically using the same concept as smart pointers.

    You know, you can do that by creating an extension method on object.

    public static class ScrewingWithYou
    {
        public static IsNull(this object haha)
        {
            return haha == null;
        }
    }
    


  • Um, what? Did you respond to the wrong person? I don't understand how your post is related to Rust at all. I was talking about the Option type which is an enum. (Rust enums are of interest here)



  • You left me without context,
    So I started searching until I found something that seemed on topic.



  • I see.

    Yeah, I like that.

    It's no different than the New/OpenDialog way of handling results, except a little bit cleaner, in that you don't reference the value otherwise.

    You can adapt that pattern to C# too.

    I'm stuck on how to implement the "match" structure, but the Some(x) None is easy to just use inherited classes.


  • Banned

    @xaade said:

    What's the difference between returning Optional<Value> and Value.

    A very good question. Especially in context where one of the functions presented returns Optional<Value> and the other returns bool.

    @xaade said:

    Either way you can be aware that the return may not have a value, just by looking at the documentation.

    The point is not just to make sure the developer RTFM, but also to refuse to compile his code if he didn't.

    @xaade said:

    But can't you do the same thing with an attribute on the method to indicate returned values may be null?

    Depends on the specifics of the type system in a given language. In a language where any reference is nullable, even the ones explicitly marked as non-nullable, the whole discussion is pointless. In a language where references are non-nullable by default, this "might be null" attribute is exactly the optional type we're talking about.



  • @Gaska said:

    Especially in context where one of the functions presented returns Optional<Value> and the other returns bool.

    I like the bool part though. It lets you shortcut the inevitable "Is there a value" question.

    But, I may be more inclined to like void Dictionary<Key,Value> DoIfValue(Key key, Action<Value> action) for that purpose.

    No null, and no extra ifs.



  • @xaade said:

    So, in C# Optional does nothing.

    "Optional" isn't even a thing in C#.

    It has "Nullable<T>" which seems to be almost exactly the same thing, based on my reading of this discussion.

    And currently, the only difference between using Nullable and not is you get that handy .HasValue() method helper and you're signaling stuff like your JSON serializer or SQL library that, hey, it's ok if this thing's null, ok?

    The next C# version will (or is planned to) have non-nullable references, and then it'll be significantly more useful.

    (Psst: good thing we switched to this awesome Discourse parser and we don't have to write HTML entities for greater-than and less-than anymore! Such an improv-- oh wait.)


  • Banned

    @xaade said:

    I like the bool part though. It lets you shortcut the inevitable "Is there a value" question.

    This shortcutting is exactly what I'd want to prevent.

    @xaade said:

    But, I may be more inclined to like void Dictionary<Key,Value> DoIfValue(Key key, Action<Value> action) for that purpose.

    No null, and no extra ifs.


    It's an acceptable solution, but:

    1. It's arguably less clear what's going on in the code than if you used plain old if.
    2. It's less versatile than simple Get() method, so by necessity you'd have to have the latter too, and you end up with two ways of doing the same (and the original problem isn't gone either).

    @blakeyrat said:

    "Optional" isn't even a thing in C#.

    It has "Nullable<T>" which seems to be almost exactly the same thing, based on my reading of this discussion.


    Yeah, pretty much so. But it has the fatal flaw of allowing unchecked access to its inner value.

    @blakeyrat said:

    And currently, the only difference between using Nullable and not is you get that handy .HasValue() method helper and you're signaling stuff like your JSON serializer or SQL library that, hey, it's ok if this thing's null, ok?

    Also, Nullable is necessary if you want to have nullable primitives and structs. This is actually the reason why they even bothered with it.



  • @blakeyrat said:

    we don't have to write HTML entities for greater-than and less-than anymore!

    Use inline code blocks: Optional<T>


  • ♿ (Parody)

    @CoyneTheDup said:

    Keep on kicking that can.

    That's why you never rely on natural keys.



  • @Gaska said:

    Yeah, pretty much so. But it has the fatal flaw of allowing unchecked access to its inner value.

    Well, you're C#'s language designer. You have the choice of throwing an exception for this, or returning null (if the inner value is null.) You have no way of catching this at compile-time-- what do you do?

    C# chose one path, you prefer another. Is either superior to the other? ... meh.



  • C#'s Nullable<T> is intended to be used on value types, which can never be null. Side note: If you ever find yourself writing Nullable<int> instead of int? (C#) or Integer? (VB.NET), you're the WTF.

    As for Java's Optional<T>, it was introduced as part of Java 8's Stream API (aka LINQ-alike syntax without the query language). Hence why the typical usage for it is something like this:

    Optional<FileInputStream> fis =
             names.stream().filter(name -> !isProcessedYet(name))
                           .findFirst()
                           .map(name -> new FileInputStream(name));
    

    This uses a Collection<String>, two Stream<String>s, an Optional<String>, and an Optional<FileInputStream>.

    If Optional<T> didn't exist, those lambdas would need manual null checks in them. Yes, the final result is still returned as an Optional... Java doesn't know you've finished with the function chain.

    In fact... you could continue on with it, although it's not recommended as you really need that FileInputStream for a using try-with-resources block.


  • Banned

    @blakeyrat said:

    Well, you're C#'s language designer.

    Am I? OK, so I make all references non-nullable, create built-in optional type and add ifexists statement which works about the same way as if statement; it takes an optional value and checks if it contains something, and if it does, then inside this block, the value is treated as if it was regular non-nullable reference to the contained value. Pseudocode:

    var x = GetDataIfYouFeelLikeIt();
    ifexists (x) {
        x.Frobnicate();
    } else {
        ReportProblem();
    }
    

    @blakeyrat said:

    You have no way of catching this at compile-time-- what do you do?

    ...Oops. I wrongly assumed I can do what the fuck I want - I'm the designer after all. No, under your completely arbitrary constraints, I have no solution for the problem how to enforce null checks at compile time without making any compile-time checks.



  • @xaade said:

    In fact, the only ways I can imagine removing null from the language, is to make everything a list, with a list class that supports only 0 or 1 entries, or to make everything in the language a dynamic.

    As in Optional<T>? Because that's what it does. If it was used for every "optional" reference, you might get rid of null.@boomzilla said:

    That's why you never rely on natural keys.

    True enough. Except I'm not really talking about keys, I'm talking about composition of optional members.



  • Why not just if(x) like C++? Or does C# have if(y) reserved for some other use? (I don't know C#)


  • Banned

    @LB_ said:

    Why not just if(x) like C++?

    Because of the "value is treated as if it was regular non-nullable reference" part. It's good to have two separate language constructs for two different things.



  • Ok, after seeing how Rust does it I agree with your logic.



  • NULL is a value that is not a value. And that’s a problemAnd therein lies it's power.


  • Banned

    As any professional boxer will tell you, with great power comes great headache.


  • Java Dev

    @xaade said:

    I like the bool part though. It lets you shortcut the inevitable "Is there a value" question.

    Rust lets you do

    if let Some(value) = dict.getValue(key) {
       ...
    }
    

    which is more or less equivalent to

    if (dict.tryGetValue(key, value) {
        ....
    }
    


  • Apparently you wouldn't be allowed to call methods on a nullable outside the checked block.

    Which seems awfully pedantic to me. And let's say you have an object with a bunch of properties, and they can either all be null or all be not null. So what, you're going to wrap your code in twenty null checks?

    And five dollars say people would just get pissed off that the compiler doesn't let them write code, because as much as we've advanced the static analysis tools, they still can't read minds and infer that, say, the outside system's contract specifies that the value can only be null on Tuesdays, so if(GetDayOfWeek() == DaysOfWeek.Tuesday) is a null check.



  • Did you mean to reply to me? If so, I think you missed the context of what I was replying to.



  • In the current version of C#, you can do strange things like:

    if(thing?.TryGetValue(key, out string value))
      value.Something();


  • In the first sentence, yes.

    I got kind of sidetracked.


  • Banned

    @Maciejasjmj said:

    Apparently you wouldn't be allowed to call methods on a nullable outside the checked block.

    Which seems awfully pedantic to me.


    Well, that's the point. Also, Rust's Option type has a variety of convenience methods that let you do stuff without if let block, like map() which throws the contained value through a function but only if there is one, or and() which takes another Option (possibly of different type) as argument, and returns its argument if both are non-empty (returns None otherwise). So in practice, it isn't that bad.

    @Maciejasjmj said:

    And let's say you have an object with a bunch of properties, and they can either all be null or all be not null. So what, you're going to wrap your code in twenty null checks?

    All at once? Then they shouldn't be optional, but rather the whole object should. Each one separately? Then you probably want to know which of them are null anyway - if not, it's probably refactoring time.

    @Maciejasjmj said:

    And five dollars say people would just get pissed off that the compiler doesn't let them write code, because as much as we've advanced the static analysis tools, they still can't read minds and infer that, say, the outside system's contract specifies that the value can only be null on Tuesdays, so if(GetDayOfWeek() == DaysOfWeek.Tuesday) is a null check.

    You can always do .unwrap(). That's just nine characters, but I assure you it's worth it in the long time. I mean, assuming you want to write bulletproof software.


    Error 500 happened and I'm not sure if I'm posting duplicate or not.


  • Discourse touched me in a no-no place

    @Gaska said:

    Error 500 happened and I'm not sure if I'm posting duplicate or not.

    It's optionally duplicated…



  • @Gaska said:

    Well, that's the point. Also, Rust's Option type has a variety of convenience methods that let you do stuff without if let block, like map() which throws the contained value through a function but only if there is one, or and() which takes another Option (possibly of different type) as argument, and returns its argument if both are non-empty (returns None otherwise). So in practice, it isn't that bad.

    Sounds like the elvis operator in C#. thing?.GetScorpion()?.GetOverHere(that) will return the default value of the type returned by GetOverHere() (null, in the case of reference types) if thing or the result of GetScorpion() is null. It helps a lot.


  • Banned

    @Magus said:

    elvis operator

    I thought the limit operator is the worst name for an operator one can come up with... but elvis beats it by a league.



  • @Gaska said:

    Well, that's the point.

    What, being awfully pedantic? That only applies on this forum, you know.

    @Gaska said:

    All at once? Then they shouldn't be optional, but rather the whole object should. Each one separately? Then you probably want to know which of them are null anyway - if not, it's probably refactoring time.

    public class Person
    {
        //whole lotta properties
        public DateTime? BirthDate { get; set; }
        public int? Age { get { /*too lazy to look it up*/ } }
        public ZodiacSign? Sign { get { /*yeah, you get the drill*/ } }
        //...
    }
    

    If BirthDate is null, so are the others, but the compiler is rather unlikely to figure that out.

    @Gaska said:

    I mean, assuming you want to write bulletproof software.

    To do which you need a lot more than null checks. It's called validation logic, it's called unit testing, and if you want your software to be bulletproof the two are necessary anyway. You've managed to make your software impervious to nerf darts at best.

    @Gaska said:

    Error 500 happened and I'm not sure if I'm posting duplicate or not.

    Probably a null dereference 🚎



  • @Maciejasjmj said:

    If BirthDate is null, so are the others

    1. Why are those other fields stored in the first place?
    2. Assuming there's good reason to store those fields, you should break them off into a separate class, e.g. BirthDateDetails (and then make that single member optional)


  • The name was coined by the people testing roslyn, because ?. looks like eyes with elvis hair, apparently. Microsoft doesn't like the name. They call it Null Propagation.



  • @Gaska said:

    Well, that's the point. Also, Rust's Option type has a variety of convenience methods that let you do stuff without if let block, like map() which throws the contained value through a function but only if there is one, or and() which takes another Option (possibly of different type) as argument, and returns its argument if both are non-empty (returns None otherwise). So in practice, it isn't that bad.

    Is Option a language level construct, or some library level generic class? Asking because you mentioned

    @Gaska said:

    create built-in optional type
    before, and I was curious if that was something you picked up from Rust.


Log in to reply