Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm not sure I understand this discussion. It sounds like most people are saying that null/nils cause a tonne of problems because if you don't check them everywhere, you end up with a crash.

I don't see how making types non-nullable solves the problem, doesn't it just create a new problem? When I load the string from somewhere outside of the program, if it is not present, I would either have to check for that condition otherwise I will crash, otherwise I would assign it some magic value and have to check everywhere "if not magic value".

otoh, if the strings are not external then there is little danger of things ever being null no?



> I don't see how making types non-nullable solves the problem, doesn't it just create a new problem? When I load the string from somewhere outside of the program, if it is not present, I would either have to check for that condition otherwise I will crash

If the type is non-nullable then the compiler will refuse the program if you have not dotted your is and crossed your ts. So you'd have to check your expectations at the edge, and if the expectation is "that is indeed optional" then it's optional internally and the compiler will ensure that is acknowledged at every place it's used.

> otoh, if the strings are not external then there is little danger of things ever being null no?

It depends. Lots of things are internally nullable. If I look an account by a key that's been provided externally, the account may or may not exist, that's an optional.

However it's true that most of the internal values will be non-nullable, and then the advantage of non-nullable types is that is checked and validated by the compiler, so it avoids misuses and misunderstandings.

When you only have nullable types, then the only thing you can do is assume, everywhere, and pray that you're right.


Non-nullable types allow functions to put the burden of checking for the existence of a value on callers. That means the check only has to happen in one place instead of everywhere a string is used.

But I sort of agree that excluding nulls is only part of the solution, because existing isn't the only requirement that values have to meet. I often need strings to be non-empty or have a minimum length.

Many modern type systems allow you to define new types that conform to an existing type's interface. But it's often a rather convoluted affair.


The type system forces you to deal with the case, instead of relying on the programmer to remember. You can still opt to crash explicitly if an option has nothing it it, but if you merely forget to check it won’t compile.


The advantage of having something like a non-nillable value is that it more strongly encourages (and/or forces, depending on the library) the programmer to move the handling of incorrect values to the edge, where they first came in. If you are parsing something, and you're trying to extract a string to pass it to an API that requires a non-nillable string, you are forced to handle not getting a string right on the spot, rather than passing it in to the API, where it may go who knows where.

This is a very important programming pattern that should be used at every available opportunity, and probably one of the biggest programming failures that is rarely talked about in programming. Dynamically-typed languages encourage this style more than statically-typed languages but it can be done in either one. You need to do as much of your validation as close as you can to the time that data enters your system. If you don't, instead of validation living at your edge, it gets smeared through the entire program, and it will be done incorrectly when that happens.

(If you have a deeper layer that has more restrictions on the validity, then the additional validation should be done on that deeper layer. This can be applied recursively within a program if it is big enough to have multiple domains. But you always want edge validation.)

Architectures that fail to do this inevitably become a mess on the inside. Functions develop that are passed "strings" but they don't know if they're validated strings, or decoded strings, or what. Where things get validated and decoded becomes incredibly complicated. Functions start growing options describing what's being passed, but then the functions calling those functions end up eventually being wrong themselves. This eventually metastasizes into the sort of code that nobody can change because every attempt to change something screws up some delicately balanced code path. The only solution to this is to start over and do this edge validation I'm talking about, so that the entire rest of the code base just stops having to worry about it.

This also goes hand-in-hand with the idea that you should decode data at the edge, and pass around data internally only in its natural format, and encode data only at the edge as it leaves. If you're in the "middle" of a program and suddenly there's code to URL decode a string, there's an architectural problem in that code. (This code is likely to become code in the future to conditionally decode the string, or much worse, guess at whether the string needs to be decoded, which is getting perilously close to a You've Already Lost situation.) If you come to a deep enough understanding of what it means you can start to see that validation and decoding into a canonical internal format, and the encoding on the way out from the canonical internal format, are the same thing.

I know this is a common question since I also had it myself at the beginning, but see the strong types not as the assertion that the world will never have a nil string in it, because that's obviously an impossible assertion, but as a statement that any calling code is going to have to deal with what happens when there's a nil string (or whatever other invalid input), because I, this strongly typed library, am not going to deal with it. This statement is also almost always correct, too, because the library lacks the context to know how to handle things it can't handle. You shouldn't ask libraries to handle things they don't know how to handle, because, well, they don't know how to handle them.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: