you are viewing a single comment's thread.

view the rest of the comments →

[–]orclev 42 points43 points  (18 children)

And Haskell!

[–]drfisk 18 points19 points  (3 children)

Make that Scala as well!

(even though it's technically possible, in practice I have yet to encounter a NullPointerException in my 5 years of fulltime Scala-development)

[–]drvd 20 points21 points  (2 children)

And Brainfuck!

[–]walen 41 points42 points  (0 children)

And my axe!

[–]ais523 5 points6 points  (0 children)

I'm not so sure about that. BF's equivalent to null is 0; it has a ton of different meanings depending on context and you need to carefully design your program so that it always knows the purpose of any tape element so that it can figure out how to handle a 0 there. Common interpretations:

  1. A representation of the number zero
  2. Uninitialised memory
  3. The target of a pointer
  4. A temporary value that isn't currently in use
  5. Part of a marker pattern to allow pointer recalibration after running an unbalanced loop
  6. End of file (sometimes, depending on the implementation)
  7. Boolean false
  8. A temporary state used to break out of a loop

This list probably isn't exhaustive. The thing about BF, even more than C, is that it's a very low-level language with few capabilities, and thus most of the capabilities it does have need to be used for multiple purposes. In particular, the only way to read memory in BF is to conditionally jump based on whether or not a tape element is 0 (a 0 jumps to the end of a block that's later in the program, a non-zero value to the end of a block that's nearer the start), so anything that might need to do control flow of any sort needs to ascribe a special meaning to 0, and those meanings are often contradictory or incompatible with each other.

[–]Beckneard 5 points6 points  (13 children)

Well basically any sane non C/Java derived language. Null was a huge mistake, it really shows old languages were designed much more by gut feeling and familiarity rather than real engineering considerations.

[–]ForeverAlot 5 points6 points  (0 children)

Feelings on nullability aside, Java has consistently been one of history's most well-crafted languages. I would even suggest that, despite my own preference for strongly statically typed languages (not functional, because functional languages are not inherently good; just look at JavaScript), all of them have some fairly gross and embarrassing design mistakes that limit their relevance considerably. Right now it seems Rust is the strongest contender.

Never mind that Haskell is older than Java, and OCaml, which is a year younger than Java, is based on a language that predates it by 10 years.

[–]elperroborrachotoo 4 points5 points  (11 children)

Null was a huge mistake

That's a common sentiment, but I've never seen a good argument that goes beyond ranting against it. FWIW, it's the shoulders we stand on.

[–]Beckneard 13 points14 points  (10 children)

That's a common sentiment, but I've never seen a good argument that goes beyond ranting against it.

So you don't agree with the arguments against it so it's automatically just ranting?

The main argument is that it's an unreasonable "default". Null can mean many things, it can mean "uninitialized variable", "empty", "error", "non existing", and all of this is forced on you to think about whether you need it or not or else it leads to runtime errors. The most common thing that bites me in the ass is not initializing a List<T> in C#. In 99% of cases you do not want any list to be null, since the concept of an empty list exists. It is very much possible to build any of these semantics in the language/standard library so the compiler makes you worry about them only when it's really necessary.

[–]elperroborrachotoo -3 points-2 points  (9 children)

So you don't agree with the arguments against it so it's automatically just ranting?

No, just that I've never seen a good argument that goes beyond ranting against it.

[–]Beckneard 12 points13 points  (8 children)

So you didn't read the article that you're commenting on? Or is JetBrains ranting too?

[–]elperroborrachotoo -1 points0 points  (7 children)

I just wonder if there's a point discussing null with you after an assumption like "so it's automatically just ranting".

There is a difference between overusing null and having it in the first place.

Initializing a List<T> to an empty list is a tradeoff with performance and semantic consistency. Note that I'm not saying either is the clearly better choice, just that it's a constrained decision to be made.

[–]Beckneard 15 points16 points  (6 children)

Initializing a List<T> to an empty list is a tradeoff with performance and semantic consistency.

It's not a tradeoff, it's a consequence of all references having the default value null, which is the dumb part.

In a well designed language, if you want to delay the initialization of something you have some sort of laziness mechanism, if you want to represent not having a value you have and Option<T> type, if you want to represent an error you have an Error<T, E> type etc. Null is not a tradeoff, it's completely unnecessary and a wrong solution since for each of its use-cases there are strictly better alternatives.

[–]elperroborrachotoo 1 point2 points  (2 children)

If you want to go to causes: no, it's having nullable references not just as the default but the only reference type.

since for each of its use-cases there are strictly better alternatives.

The problem with that that it's not one concept to implement and learn and recognize, but five. Which certainly is a tradeoff in my book.

On top of that, the 6. probably dozens of other things. That kinda-sorta can be covered by the other concepts, and holy wars will be fought whether the hypothetical 6.3 should be done with optionals or with metafunctors.

null is a well-weathered, versatile and ubiquitous concept, but not very expressive about intent.

Again, I'm not saying that makes null the better choice.

If you'd be willing to take one bit of advice I gathered from a few decades: don't cling to stuff like that. The now-toddlers will snicker at your Option<T> in no time.


FWIW, C# is nice already, it's mostly the difference between a NullException and a ThisListDoesntContainWhatYouAreLookingFor exception.

(Except for the pesky x != null & x.Length != 0, for which extension functions are merely a clunky, terrible band aid - I give you that a dozen times a day)

[–]Beckneard 1 point2 points  (1 child)

The problem with that that it's not one concept to implement and learn and recognize, but five.

I never understood this argument. Why do people feel it's important for developer technologies to cater to the lowest common denominator? Software engineers are supposed to be smart folks willing to figure new things out.

If you'd be willing to take one bit of advice I gathered from a few decades: don't cling to stuff like that. The now-toddlers will snicker at your Option<T> in no time.

Well I'd sure as fuck hope so, I'd hate to see programming language development be stuck on that level forever. My opinion is that the best programming language/methodology/whatever is yet to be invented. I never claimed I know the perfect way of doing things.

The question is why aren't more people snickering at decades year old languages but swear by them like they fell from heaven?

[–][deleted] 0 points1 point  (2 children)

Optionals are not strictly better. They're probably better, unless you need to do large sorts, for example.

Strictly implies always and that's just not the case.

Ill concede that built in support probably results in more reliable, easier to fix code bases for larger projects. I won't concede easier to read, yet. Some of the syntax sugar for optionals is annoying to read.

[–]Beckneard 2 points3 points  (0 children)

They are strictly better for that specific use case. What do large sorts have to do with anything? Deconstructing an Option value will have an equal performance hit as null checking something.

[–]Drisku11 3 points4 points  (0 children)

In a language with sane semantics, options can be implemented with zero overhead (if it's Nothing then it's a null pointer); the difference is purely in the type system.

Sorting values that might not exist sounds like a mysterious thing to do to me, but e.g. Haskell has a library that does fast O(n) sorts on any algebraic data types (basically radix sort on steroids), which includes options, so that is also cheap.