NULL: the worst mistake of computer science
-
Why does it matter?
I don't know.
I'm just showing that if you care so much about it, you can find out why in the same query.
NULL isn't the problem.
-
I'm just showing that if you care so much about it, you can find out why in the same query.
Ah! The spirit of doing it because you can. Carry on there…
-
C "NULL is a problem because I can't tell in an outer join what it means"
X Demonstrates that you can tell
X Therefore, it's not NULL that's the problem. You're creating the problem that you say there is no solution to.
-
Those more into strict relational algebra than I am would probably beg to differ. I'm nowhere near as dogmatic when it comes to SQL. I just want the DB schema to be at least somewhat sensible for both the data and the queries over that data…
-
That's not where it's annoying. Where it's annoying is:
bool x = some_external_value; int y; if( x ) { y = 42; } /* some code which does not touch x or y */ if( x ) { printf( "%d\n", y ); } ```</blockquote> At least Visual Studio does recognize that `y` may not be initialized in some cases and will warn you about it in the editor.
-
At least Visual Studio does recognize that
y
may not be initialized in some cases and will warn you about it in the editor.So will GCC on compile, which is my usual target. And I do prefer 'may be used uninitialized' over silently assuming it will be initialized, which you sometimes get when an uninitialized variable's address is passed to a function.
-
Is it just me, or does Dicksucks claim there's an exception every time this thread is loaded (before loading it anyway) for others too?
-
Discuss did that to me several hours ago when the pages loaded slowly. Now everything looks okay. Too okay.
-
-
> The reciprocal of Zero is a number that is not a number. And that's a problem
Filed under:
ftfy
However, it's also not not a number. Don't believe me?
And don't forget about the reciprocal of negative zero.
-
Remembering that discussion, I reckon that the actual worst mistake of computer science is teaching idiots who don't real the documentation (and so fail to understand what NULL and NaN mean) to program computers in the first place.
-
```
bool x = some_external_value;
int y;if( x )
{
y = 42;
}/* some code which does not touch x or y */
if( x )
{
printf( "%d\n", y );
}Code like this won't even compile in Java, and that's a language that everybody ridicules.
-
Good job Discourse, you fucked that up pretty good.
-
I think you need to add a newline into the quote. Why? Who the hell knows...
@another_sam said:@PleegWat said:
```
bool x = some_external_value;
int y;if( x )
{
y = 42;
}/* some code which does not touch x or y */
if( x )
{
printf( "%d\n", y );
}Code like this won't even compile in Java, and that's a language that everybody ridicules.</blockquote> Yep. DiscoMarkdownHTMLBBCodeParser bugs. Still haven't been fixed, but at least <a href="https://what.thedailywtf.com/t/what-favorite-ui-element-will-we-lose-next-hopefully-not-flags/6755/428?u=sloosecannon">logout functionality was removed</a> (then re-added) in the latest version. So... progress is being made?
-
So having the error show up at compile time rather than run time has no value?
But it doesn't show up always, that's the issue. If you're not required to use
Optional
, the [Java] compiler (as it is now) won't tell you that you might be missing anull
reference check somewhere.
And even then, you can still fail at checkingOptional
and attempt to use it anyway, which will result in a run-time error. (I think it's something likeNoSuchElementException
.)As I already said (and @Captain mentioned below your reply), the value it has is making the programmer aware of the possibility of null. If the language is designed like this from the start (I think Rust does this, and I see in this thread that Haskell likely does too.), then it is obviously helpful. In java/C# - not so much.
I'm not arguing that Optional/Maybe/... constructs are bad or useless, I'm just arguing that tacking them on as an afterthought doesn't help much, when there's no obligation to use them. Just creates further mess when some parts of the code use them and some don't.
And, returning to my original point - if you abolish
null
from a language and then add something likeOptional<T>
, that's just a different name for null/nothing.
-
I reckon that the actual worst mistake of computer science is teaching idiots who don't real the documentation (and so fail to understand what NULL and NaN mean) to program computers in the first place.
But anybody who wants to should be able to program. It must be so; Blakey said it.
-
> NULL is a value that is not a value. And that’s a problem.
Got as far as that and stopped reading /taking it seriously. Why?
Because you're an ignoramus?
Zero is a number that is not a number. And that's a problem
There we go!
-
Any entity that exists, from abstract concepts to useless bags of skin, by definition, has to have a value that can be described. Sometimes there is nothing other than
NULL
to provide an absolute and accurate description.By the way, are you aware that "zero" had to be invented in order to allow Math to be viable?
-
Any entity that exists, from abstract concepts to useless bags of skin, by definition, has to have a value that can be described. Sometimes there is nothing other than
NULL
to provide an absolute and accurate description.By the way, are you aware that "zero" had to be invented in order to allow Math to be viable?
I use
null
frequently in cases that aren't exceptional but cause the method to fail. An obvious choice would be a method that gets the config values for a program but does not need those values to continue (fall back to default, etc). Yes, you may throw aFileNotFoundException
, catch that, etc, but it is much simpler, in my mind, toreturn null
and run a null check before using the result.
null
only bites you in the butt if you're a poor programmer who allows thatnull
to escape its confined space into an area where it can cause problems. Using an IDE with static analysis (as discussed above) and@Nullable
and@NotNull
annotations are both immensely valuable tools in preventing these kinds of errors, and are usually readily available.
Granted usingnull
can lead to gotchas, but by being proactive, never assuming anything which isn't specified by the method contract, and being careful about program flow, you can ensure thatnull
problems never really occur.
-
Any entity that exists, from abstract concepts to useless bags of skin, by definition, has to have a value that can be described. Sometimes there is nothing other than NULL to provide an absolute and accurate description.
The difference here is a type that is explicitly and obviously nullable, to prod the programmer into thinking about the potential null value, and other types that cannot ever be null so the programmer knows he does not have to think about them.
By the way, are you aware that "zero" had to be invented in order to allow Math to be viable?
I am aware that zero was adopted as a better alternative to the null value when zero is what is actually meant. Zero wasn't invented to "allow Math to be viable", it was used as part of a place value system because the notation is really handy.
-
The difference here is a type that is explicitly and obviously nullable, to prod the programmer into thinking about the potential null value, and other types that cannot ever be null so the programmer knows he does not have to think about them.
What happens when I have to cast one to an
Object
? (As is frequently required in Java programs. Benefits/downfalls of this may be discussed elsewhere).Note: I don't necessarily disagree with your idea, but language constraints and other issues make it infeasible to me.
-
Yes, you may throw a FileNotFoundException, catch that, etc, but it is much simpler, in my mind, to return null and run a null check before using the result.
mightBeNull.getOrElse(default) mightBeNull.map(notNullValue => dontCallThisIfValueIsNull(notNullValue))
What happens when I have to cast one to an Object? (As is frequently required in Java programs. Benefits/downfalls of this may be discussed elsewhere).
Unfortunately the Java type system doesn't support not-nullable types. This also means Scala doesn't support them either, which sucks hard, because it includes a nice Option type. So if you cast to Object you're going to break stuff sometimes, which is what happens now anyway.
Note: I don't necessarily disagree with your idea, but language constraints and other issues make it infeasible to me.
For existing languages the biggest problems are the APIs you need to call, because they're already established with null as a valid return type. Retro-fitting such APIs with Optional would be great but it's going to take a long time and the effect will only be of benefit when programmers see Optional everywhere and a null looks strange to them.
-
Raw:
int x;
if (very_difficult_problem(constant_input))
{
x = 42;
}I dunno. Maybe it would work, but it would either require some insanely powerful static analysis tools, or the compiler to chew you off on missing cases that are impossible anyway.
Output:
WTF, DiscoBBHTMLMarkDownParser?
-
How about searching a database for a query result and turning it into an object? Or another case where there is no default value?
-
Preview:
Result:
Where's my newline? FUCKING HELL I'M FINDING BUGS WHILE REPORTING BUGS.
-
FUCKING HELL WHY DOES IT
DELETE TWO CHARACTERSINSERT 0 NEWLINES WHEN I PRESSEDBACKSPACEENTER ONCE?
-
The point I have been making is:
Null has to exist in order to describe something that does not exist. In the case of programming languages this is critical, otherwise you have the situation that "mathematicians* had before they invented the concept of zero - which is a very specific type of
NULL
. Resulting in a BSoD which helps nobody andnothingNULL.......1 + 1 = 2
1 - 1 = ????? :( :Wtf: "...run for the hills, it's the end of the world..."
-
Alternate punchline: FUCKING HELL WHY
DOES IT DELETE TWO CHARACTERSDO I GET TWO BUGS WHEN IPRESSED BACKSPACE ONCEONLY FOUND ONE
-
Alternate punchline: FUCKING HELL WHY DOES IT DELETE TWO CHARACTERSDO I GET TWO BUGS WHEN I PRESSED BACKSPACE ONCEONLY FOUND ONE
DiscourseDiscuss
-
How about searching a database for a query result and turning it into an object?
Return Option types in your record where those columns are nullable in the database.
Or another case where there is no default value?
None is an Option that has no value and is more-or-less equivalent to the literal null.
-
-
@another_sam said:
Option types
?
In Java, Optional, in Scala, Option. Some other languages have similar types.
-
Honestly, I personally think the "danger" of playing with null is one of the benefits too.
The NPE is a great way to ensure you don't try to run things on non-existent things - it's a very loud "No you idiot, this doesn't exist. Don't do that!" message. It prevents people from even attempting things based on something that doesn't exist.
ED:
For example, you have a method that frobnicates widgets. If you pass innull
, you either have to check fornull
(in which case you're actively coding a defense againstnull
, which means you're handling it), or you'll throw an NPE somewhere when you actually try to frobnicate thenull
(surely there's a there somewhere). Without anull
value, what's the alternative? Silently fail? Or blow up? Which essentially makes the alternative identical to the thing it's replacing...
-
@sloosecannon said:
@another_sam said:
Option types
?
In Java, Optional, in Scala, Option. Some other languages have similar types.
I see.
So....... what do you do when you call
.get()
on a value that isn't present? Without null, that's hard to do, yes?
-
The NPE is a great way to ensure you don't try to run things on non-existent things - it's a very loud "No you idiot, this doesn't exist. Don't do that!" message. It prevents people from even attempting things based on something that doesn't exist.
mightBeNull.get()
will explode if it has no value if that's what you really want. But you probably wantmightBeNull match { Some(x) => doSomethingWith(x) None => wtfDude() }
or any one of a number of better constructs.
So....... what do you do when you call .get() on a value that isn't present? Without null, that's hard to do, yes?
mightBeNull.get()
will explode if it has no value. Calling .get() is the explicit acknowledgement I was talking about before, that the programmer has considered the possible null value and decided it will always have a value. There are usually better ways to write it.
-
@sloosecannon said:
The NPE is a great way to ensure you don't try to run things on non-existent things - it's a very loud "No you idiot, this doesn't exist. Don't do that!" message. It prevents people from even attempting things based on something that doesn't exist.
mightBeNull.get()
will explode if it has no value if that's what you really want. But you probably wantmightBeNull match { Some(x) => doSomethingWith(x) None => wtfDude() }
or any one of a number of better constructs.
So....... what do you do when you call .get() on a value that isn't present? Without null, that's hard to do, yes?
mightBeNull.get()
will explode if it has no value. Calling .get() is the explicit acknowledgement I was talking about before, that the programmer has considered the possible null value and decided it will always have a value. There are usually better ways to write it.Well I think I understand the concept, but I don't really see the benefit.
I may be missing something but here's how I see it:
null
:
value is either an object or null.
null explodes the program if you attempt to operate on it
null may be compared to prevent explosions
Option types
contains a value
value can't be null, but can be None
Different methods can be run depending on if value is None or not (similar to a switch statement?)
Will explode the program ifget()
is run on something with None as its value.
So in essence:
They contain a value or no value
Can be tested to see if there is a value or not (in syntactically different ways)
Explode the program if you try to use a non-existent value.Is there something I'm missing?
In essence the differences (as I see them) are:
- Might explode earlier if the
get()
call is used before the value would be used - Syntactic sugar between
match
andif(x==null)
There are differences between the two, granted, but I don't really see a benefit to either option... Option types are essentially a wrapper over null?
- Might explode earlier if the
-
If you're not required to use Optional, the [Java] compiler (as it is now) won't tell you that you might be missing a null reference check somewhere.
My bad, I assumed you were using a sane programming language.
And, returning to my original point - if you abolish null from a language and then add something like Optional<T>, that's just a different name for null/nothing.
If you're going to do all that work, why not make
Optional
required?mightBeNull.map(notNullValue => dontCallThisIfValueIsNull(notNullValue))
fmap dontCallThisIfValueIsNull mightBeNull
-
@ashkante said:
If you're not required to use Optional, the [Java] compiler (as it is now) won't tell you that you might be missing a null reference check somewhere.
My bad, I assumed you were using a sane programming language.
Hehe, fortunately I don't really have to use it. I'm just a "programming-language-groupie" and like to learn about all programming languages (even the bad ones - from those I can learn how not to do things).
@ashkante said:
And, returning to my original point - if you abolish null from a language and then add something like Optional<T>, that's just a different name for null/nothing.
If you're going to do all that work, why not makeOptional
required?I expect Java people did it for backwards compatibility. I agree with you though, if I put that feature into a new language (or a revamp of an old one), I'd damn well make sure it's compiler-enforced.
-
Optional was introduced quite late in the game (Java 8, released last year), so basically nothing uses it.
Looking over how it works, it looks like it's intended to be used with Java 8's streams. The methods Java added for stream stuff seems to be heavily influenced by various extension methods in .NET. Kinda/sorta like Java's answer to LINQ, but without the query language itself (streams assume you already have a collection of objects).
-
Kinda/sorta like Java's answer to LINQ, but without the query language itself
The Java mindset is extremely against putting things like the LINQ syntax in Java. It makes it very stodgy, but also really cuts the amount of shenanigans you can expect to see when reading someone else's code: in Java, your initial reading of the code is virtually always the right one. (And then you wonder “so which class actually implements that stuff?”)
-
However, it's also not not a number. Don't believe me?
NaN doesn't incorporate positive or negative infinity, which are infact defined as numbers, but are not finitely quantifiable.
E.g.
isFinite(1/0) // false
-
Will explode the program if get() is run on something with None as its value.
And remember how I said you probably wanted something other than
.get()
? It's not called all that often, so it stands out as a potential bug when reading the code.Is there something I'm missing?
Perhaps only the obviousness aspect of an Option type compared with null. It doesn't do anything that null doesn't do, but it does make it easier to do the right thing, and a bit prettier if you use the syntaxtic sugar. It's not magic, just convenient.
-
By the way, are you aware that "zero" had to be invented in order to allow Math to be viable?
The thing that always interested me is that negative numbers and imaginary numbers were accepted at around the same time. In modern education the negative numbers are taught so much earlier, and seem like such a simple extension, that it's difficult to appreciate how much of a conceptual difficulty they presented at the time.
-
The thing that always interested me is that negative numbers and imaginary numbers were accepted at around the same time.
Well, I think they both originally came out of interest in general solutions for polynomial equations (originally Diophantine equations, but more generally). Negatives would have been accepted sooner; the concepts required for imaginary numbers don't even make sense until you've got negative numbers.
-
My bookkeeping teacher (a technician by education) wondered why bookkeepers wouldn't just use negative numbers instead of putting those numbers on the other side of the account/balance.
Taking into account that negative numbers were invented only centuries after double-entry bookkeeping, this is obvious.
Interesting fact: the usual mathematically sound definition of negative numbers as class of pairs of natural numbers is practically identical to the way double-entry bookkeeping denotes more money has been taken from an account than there was on it before.
-
It doesn't do anything that null doesn't do,
Really? Because I don't remember null having all these methods:
Method and Description static <T> Optional<T> empty() Returns an empty Optional instance. boolean equals(Object obj) Indicates whether some other object is "equal to" this Optional. Optional<T> filter(Predicate<? super T> predicate) If a value is present, and the value matches the given predicate, return an Optional describing the value, otherwise return an empty Optional. <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper) If a value is present, apply the provided Optional-bearing mapping function to it, return that result, otherwise return an empty Optional. T get() If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException. int hashCode() Returns the hash code value of the present value, if any, or 0 (zero) if no value is present. void ifPresent(Consumer<? super T> consumer) If a value is present, invoke the specified consumer with the value, otherwise do nothing. boolean isPresent() Return true if there is a value present, otherwise false. <U> Optional<U> map(Function<? super T,? extends U> mapper) If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result. static <T> Optional<T> of(T value) Returns an Optional with the specified present non-null value. static <T> Optional<T> ofNullable(T value) Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional. T orElse(T other) Return the value if present, otherwise return other. T orElseGet(Supplier<? extends T> other) Return the value if present, otherwise invoke other and return the result of that invocation. <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) Return the contained value, if present, otherwise throw an exception to be created by the provided supplier. String toString() Returns a non-empty string representation of this Optional suitable for debugging
-
// 'empty instance' SomeClass value = null; // equality comparison Object.equals(null, other); // predicate filter (convoluted just to illustrate that it can be done with a one-liner) var value = new[] { obj }.Where(x=> x != null).Where(predicate).FirstOrDefault(); // mapping var value = new[] { obj }.Where(x=> x != null).Select(mapper).FirstOrDefault(); // get value object value; if ( object == null) { throw NoSuchElementException; } value = object; // get hashcode int hashcode = obj != null ? obj.GetHashCode() : 0; // if present if ( obj != null ) { consumer( obj ); } // is present bool value = ( obj != null ); // or else object value = obj ?? new object(); // or else get object value = obj ?? other();
Trivial and all expressed using
null
in the internals. In other wordsOptional<T>
does indeed not do anything thatnull
doesn't do.
-
Trivial and all expressed using null in the internals. In other words Optional<T> does indeed not do anything that null doesn't do.
Curious that you use C# code as an example, as C# has Nullable<T>, the same type of concept behind Optional.
You can't assign aDateTime?
to aDateTime
without explicitly casting to the value, and doing so when it has no value throws an exception.DateTime?
can be compared with null, however it is never actually null itself.The issue is not of Null vs Optional, it's of compiler support and documentation. Whether or not something may exist versus definitely existing.
C# screwed it up by not using the?
syntax for reference types as well.
Java screwed it up by having no compiler support.
-
Actually you should say that C# screw it up by not having NonNullable<T> for reference type (adding nullability for reference type is just redundant and not adding actual value to the language itself) And reversing the meaning of ? for reference type makes sure you breaks almost all existing code.
So it's too late by the time nullable related operators are added into .NETv2. Btw, these are all just syntax sugars and I can live without these.
-
- just like for doesn't do anything you couldn't do with a goto
- you got a lot of statements there, though. Being free to call methods on your nullable type gives you a lot more freedom to choose the appropriate coding style for what you're trying to accomplish
- I personally don't like the c# designers' tendency toward syntax bloat. A class full of helper methods is the proper object oriented way to handle this, and given all of these operations can be done just as tersely—and twice as clearly—using optional, their decision to add a special new syntax just for boxing structs seems kind of pointless. Maybe they need to start at -200 from now on
- bottom line is: null doesn't actually do anything. It just is (or is not, depending on your philosophy).