Isn't there an inherent need in programming to express an explicit "nothing" value? Coming from Python and JS, I never found None/null to be much of a problem. I in fact like the distinction of null and undefined in JS. Using null allows you to distinguish from the accidental undefined.
Even in dynamic languages, it's generally bad practice to have functions that return multiple possible types, and you are often better served by returning a more proper "null object" that accepts the same messages/methods as what would normally be returned. But for the most part, the problem people have with null is related to compile time checks and it not being opt in, which is unrelated to dynamic languages where…
NULL: The worst mistake of computer science? (2015)
371–377 of 377 posts
Re: NULL: The worst mistake of computer science? (2015)
#372Earlier quoted context omitted.
C allows defining new types though, so it can be done.
Could you provide an example? Either source code or a link. I want to see how you might define a type for "guaranteed to not be null pointer to char".
struct char_nonnull_t { char *ptr; };
char *char_nonnull_as_pointer(struct char_nonnull_t cp) { return cp.ptr; }
With the required extra accessor functions. Of course in C, we don't have generics, data hiding or other nice features, so we have to build a wall of conventions around our types instead. Types with invariants are totally possible in C. We just don't have a way to automatically enforce them. It's C, after all.Re: NULL: The worst mistake of computer science? (2015)
#373Earlier quoted context omitted.
This is incorrect. The type system of both languages makes sure that T does not include null, so the case where you "accidentally" handle the null of T is impossible. More generally, with unions you always have this behavior but I've never seen this be a problem. If your function accepts T | U and you pass (T | U) | U it simplifies to T | U and in my experience the code that handles U is always the correct thing to d…
> The type system of both languages makes sure that T does not include null, so the case where you "accidentally" handle the null of T is impossible. So does that mean you can't call generic methods with ? types? Because there's an excluded middle here: either something like String? is a first-class type, in which case you can invoke a T ... method with T=String? and then any T?s inside that method have the potential…
If a generic function f accepts a covariant Dog and Animal is a supertype of Animal you cannot call f with Animal because it requires a Dog. if f accepts a covariant Animal you can call it with a Dog because Dog is a subtype of Animal.
Now replace Dog with T and Animal with T? and you can see it is perfectly fine.
Re: NULL: The worst mistake of computer science? (2015)
#374Earlier quoted context omitted.
> The type system of both languages makes sure that T does not include null, so the case where you "accidentally" handle the null of T is impossible. So does that mean you can't call generic methods with ? types? Because there's an excluded middle here: either something like String? is a first-class type, in which case you can invoke a T ... method with T=String? and then any T?s inside that method have the potential…
What? No. T is a subtype of T?, so I don't get where you are going. If a generic function f accepts a covariant Dog and Animal is a supertype of Animal you cannot call f with Animal because it requires a Dog. if f accepts a covariant Animal you can call it with a Dog because Dog is a subtype of Animal. Now replace Dog with T and Animal with T? and you can see it is perfectly fine.
Can I have a Map ? If no, then Dog? isn't a first-class type. If yes, we have all sorts of nasty surprises, because code written in terms of Map will assume that if map.get(someKey) is null then that means someKey isn't in the map, and this code will work fine until someone uses a ? type for T and then break horribly.
Re: NULL: The worst mistake of computer science? (2015)
#375Earlier quoted context omitted.
> In fact I don't think I ever treat it as anything other than that in code either. > Was the purpose of null ever to mean anything other than I have not been defined/set? Different people understand null differently (it might mean "error", "value not in map", "invalid user input", ...) and there's never been a clear consensus. If "null" only ever has one meaning anywhere in your codebase, and any third-party librari…
> Different people understand null differently (it might mean "error", "value not in map", "invalid user input", ...) Null only has one meaning, null. That's the point. As soon as you start applying more to it than that you get problems. > and there's never been a clear consensus. This is simply not true. Null is null. That is all. Period. End of story. It has never been more than that. If you have libraries, functio…
The language designers didn't give any single clear meaning to null. They just put it in the language, and so different library authors (entirely understandably) used it for different things, and it's now impossible to standardise on any one universal meaning.
> I feel like you're missing my point. If you need to handle more meaning than null == notset/unset/absent then you need to resort to a new data type. Null only has one meaning, null. You can't get two meanings out of one.
Indeed, because null is a language-level special case. (Whereas using Option you wouldn't have any problem: Option is just another normal user-defined type in the language, so Option> works no differently from any other Option).
> You, as the consumer of the cache must then decide on how to represent or encode further meaning. Either using the Some pattern or an empty string or something like that.
So you have a bunch of awkward complexity in precisely the case where you least want extra trouble. You don't know how many places the cache might assume that null values have its particular meaning, and you have no way to know whether you've got them all. The most dangerous pitfalls in programming are things that usually work.
> It's two functions set sets the thing. Get gets it. If it's not there it returns null. That is the whole contract. Why do people try to over complicate the base contract? It's just crazy over engineering.
There's nothing complicated about using option. Set sets the thing. Get gives you an option that's either some if the thing was set, none if it wasn't. Perfectly normal datatype like you'd write yourself, no special cases anywhere.
> I can use null to represent that my cache does not have a value for that key because that is the design I chose that
Only if you write all you own code and never use anyone else's libraries. And even then, you have to remember all the things you used it to mean in all the places you used it. There's only one null and there's no way to define a user-defined thing that works like null, so it begs to be abused (I'd argue to use it at all is to abuse it, given that it has no particular meaning defined in the language).
Re: NULL: The worst mistake of computer science? (2015)
#376Earlier quoted context omitted.
> the number 0 in 0℃ is a number If we're going to get pedantic ... 0 in this case is an offset . The number is what's behind it: The point at which water freezes (aka 273 °K). In this case 0 indicates the absence of any offset .
I wonder why this gets downvoted - seems pretty reasonable to me...
As a mathematical entity it doesn't represent the absence of anything. It is just a symbol that has certain properties associated with it. There isn't a hole in the real number line where 0 should be: there is a number there.
It isn't pedantic to insist that 0 isn't a number, it is equivocal to do so. In most contexts it does not need to be treated like a special value. Temperature measured in degrees is an example where you don't need to treat 0 specially, at least not more than other values...
Re: NULL: The worst mistake of computer science? (2015)
#377Earlier quoted context omitted.
What? No. T is a subtype of T?, so I don't get where you are going. If a generic function f accepts a covariant Dog and Animal is a supertype of Animal you cannot call f with Animal because it requires a Dog. if f accepts a covariant Animal you can call it with a Dog because Dog is a subtype of Animal. Now replace Dog with T and Animal with T? and you can see it is perfectly fine.
We're talking about generics. and the like. I can have a Map , I can have a Map , and these are different things but they both work fine because both Dog and Animal are first-class types. Can I have a Map ? If no, then Dog? isn't a first-class type. If yes, we have all sorts of nasty surprises, because code written in terms of Map will assume that if map.get(someKey) is null then that means someKey isn't in the map,…
yes
> because code written in terms of Map will assume that if map.get(someKey) is null that means someKey isn't in the map
And it can safely assume that. Map isn't a subtype of Map, so passing Map to a place requiring Map will not compile.
T is a subtype of T?, not the other way around. Map is defined as Map, meaning V is covariant.
So you can pass a Map where a Map is required, but not a Map where a Map is required.