3 ms·
It's unfortunate that we're learning all of these lessons so late... * things should be non-nullable by default * things should be immutable by default * thi
by kstenerud 2y ago
It's unfortunate that we're learning all of these lessons so late...
* things should be non-nullable by default
* things should be immutable by default
* things should be of the narrowest scope by default
So many design decisions for new things make the trade-off of immediate convenience instead of "falling towards the safe path" (which requires much more careful design and UX). And we have sooooo many footguns as a result in almost every language, platform, and technology thanks to this cowboy mentality.
Civil and electrical engineering have codes. We have lessons-learned, which we re-learn every 30 years or so with the next batch of languages and techs.
- TA293847923847 2y ago[flagged]
- kazinator 2y agoIt's unfortunate for Java to be learning these things so late. "We" and "Java" are not the same. Java is like a third world village learning about boiling water killing germs.
- soerxpso 2y agoThat's not true. The Java community in general has known about this for many years, and using Java's `Optional` type for anything nullable has been considered best practice. The reason the language itself has moved slowly is that making core changes to an existing language like this is hard; there are backwards compatibility concerns that are always going to be at odds with correctness concerns, and it's important to hash out the details and make sure that the eventual system they land on is the right one, since it intends to stick around for decades to come.
- mrkeen 2y agoOptionals weren't as well-received as you make them out to be. IntelliJ will issue you a warning for using an Optional either as a field, or a method parameter.
- shepherdjerred 2y agoThe purpose of Optional, IMO, is to avoid returning null, not to avoid receiving null. It is easy to validate incoming params for null or to check if an internal class field is null. It is much harder to know if some method can possibly return null. To put it another way, Optional as a param/field helps the _author_ of the class, Optional as a return helps the _user_ of the class. Taking an Optional as a field/method parameter just introduces a third state you have to handle: * The Optional is present * The Optional is absent * The Optional itself is null I've worked on codebases that abused this where there is different behavior for each of the three cases. On one hand whoever wrote that code should have thought about the contract of their method a bit more. On the other hand, respecting and looking into _why_ IntelliJ is warning about this behavior would help prevent such mistakes in the first place. But, if you really want it, you can configure IntelliJ not to warn on this inspection.
- tadfisher 2y agoThe authors of Optional intended it to only be used as a return type for library functions, to avoid well-known headaches around documenting the nullability of these functions [1]. To quote: > For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list. You should almost never use it as a field of something or a method parameter. [1]: https://stackoverflow.com/questions/26327957/should-java-8-getters-return-optional-type/26328555#26328555 https://stackoverflow.com/questions/26327957/should-java-8-g...
- shepherdjerred 2y agoI think we're in agreement. This is exactly how optional should be used.
- kstenerud 2y agoIt's not just Java. It's C, C++, Ruby, Python, Go, BASH, C#, Javascript, PHP, PERL... It's about making our systems human-tolerant. Humans are absolutely terrible when it comes to consistent (or even correct) behavior, so we must design our systems such that the path of lowest cognitive load is also the path of highest safety and least astonishment. For example, C++ has the concept of a const method. And that's great, because you can label which methods won't mutate an object's data. But it's actually backwards. It should be that mutator methods must be marked as such (because they're the ones with a higher likelihood of causing problems), whereas any non-marked method is assumed to be non-mutating. In Rust, you must specially mark mutable objects. In Kotlin, you must specially mark nullable things. Each of these newer languages is taking on some of the lessons learned, but nobody is taking a serious holistic look at human psychology and how it contributes to system failures - it's always just a few pieces here and there that the designers had learned along the way. And then someone comes along and points out a lesson they didn't implement and everyone goes "Oh. Oops." You don't get that in civil engineering because the lessons have been codified (and people who skimp out on them are liable). Psychology really needs to have more of a center focus when designing software systems, because we can't take the human fully out of the works.
- mrkeen 2y ago> And then someone comes along and points out a lesson they didn't implement and everyone goes "Oh. Oops." I don't think that's the case here. It's not "Oh. Oops". It's "Yes, we like it that way". I think that readers of Java source code have the right to see a BufferedReader, and think "That's a BufferedReader". Writers of Java source code have decided that that's too onerous. They would like the 'opposite' right - of taking a 0x0000, and declaring that to be a BufferedReader. That's really the core of it. The debates always involve adding extra types, annotations, IDEs or external tooling into the mix, as if nulls naturally arise in nature, and some genius-level engineering is required to mitigate against them. But people routinely include them in their source code. I don't think you can win the war on accidental nulls if you can't swing opinion on deliberate nulls.
- 12_throw_away 2y ago
- ecshafer 2y agoThat is not a fair description to Java or the team that has created it. Do you actually think that James Gosling, Guy Steele, Brian Goetz, Doug Lea, etc. are not aware of nullability? Java was an early 90s attempt to get C and C++ programmers to write safer code with the technology of the day. The design goal of the language was to get half way to LISP or ML for those C and C++ programmers. In an alternate universe where they had just made Common LISP, does it succeed? Perhaps not. Also consider that Java is a cross platform language, that must be backwards compatible, and work the same via a vm across architectures and operating systems, and basic things like just make variables non-nullable by default are not as simple.
- Sankozi 2y agoThere are very few languages that got "things" better than Java (if I understand kstenerud correctly): * Haskell * Rust * C# (barely) with other .NET languages Any others? If "Java is like a third world village learning about boiling water killing germs" then how do you call other main programming languages - C, C++, JS, Python?
- kaashif 2y agoC++ has many issues but it has actually supported non nullable references right from the start. Everything is riddled with foot guns and escape hatches but references can't be null.
- Sankozi 2y agoC++ is weakly typed language with undefined behaviours baked in. It definitely did not get "things" right. And also - you can get nullable references. The following compiles (and often runs) without a problem: int functionWithReference(int &ref) { return ref; } int main() { int* pointer = NULL; return functionWithReference(*pointer); }
- consteval 2y agoC++ is not weakly typed, it's just a low-level language. Meaning you can directly interact with memory if you so choose. The same is true in Rust, and YES you can break the type system with unsafe code. However, we understand that this is not really enough to make the language weakly typed. Java and C# ALSO have this problem. You can make everything Object if you want. It'll compile, it'll run, and C#'s ArrayList class worked like this. Also the above will not compile. Because compilers can actually detect if you set a pointer to nullptr and then use it. Here, you didn't use it so maybe the compiler won't complain. But in the general case yes it will complain. You can also get Null references in C# and Java in this same method. You call some unsafe code that directly interacts with memory. That's allowed, and yes it breaks the type invariants. Point being, if you truly want to argue C++ is weakly-typed then you'd also have to argue C# and Java are weakly-typed. Most people don't do that though, so it's just a matter of bias or familiarity.
- augusto-moura 2y agoThat is definitely wrong. Java is not the only language that does this. From the TIOBE index list[1] (pick any other list if you want): - Only 3 languages from top 20 (Rust, Swift and Kotlin) started with null safety type features, some others developed this over time (JS with TS, Python type hints) - Only 2 (Rust, and Kotlin) languages AFAIK are immmutable by default It is no coincidence that all of these languages are modern and created after the 2000s [1]: https://www.tiobe.com/tiobe-index/ https://www.tiobe.com/tiobe-index/
- Hamuko 2y agoHow do you define "immutable by default"? Swift for example has different syntax for mutable variables (`var x = y`) and immutable variables (`let x = y`).
- airstrike 2y agoSwift is technically "immutable by default" as you have to explicitly declare a variable to be mutable with `var`. F# also is immutable by default. Maybe it's not on that "top 20" but 20 is an arbitrary cutoff. There are many so many languages being used in production that it's hard to imagine "20" is a defensible sample. It's also hard to argue Python has any type safety with "type hints". The interpreter doesn't do anything with those hints. Linters and safety don't belong in the same sentence. All in all, that seems like a bad source.
- unscaled 2y agoTo be exact, all of these languages are statically typed and were created or at least started taking their final shape[1] after 2009, when Tony Hoare (who has the best claim for being the one who invented the null reference) coined the term "Billion Dollar Mistake" and made the final convincing argument as to why no serious typed language should have null. But it's probably more important than all of these languages have been heavily influenced by the ML/Haskell family of languages. Most ML-influenced languages forbid null references, discourage them or make nullability a part of the type signature. I think the ML-heritage is the key factor, together with Tony Hoare's influence. Languages released shortly after 2009 that have ignored the ML tradition like Go and Dart did not have null-safety. I believe ML-influenced language designers were more attuned to Tony Hoare's call for action and had a good idea about how to make null-safety work smoothly an industrial language. Fortunately for us, nowadays the language designer doesn't have to be a Functional Programming aficionado anymore: null-safety has proven itself as relatively easy to implement and too useful to ignore. --- [1] Rust is the odd one out here: Graydon has started working on Rust as a personal project back in 2006, but that language is bears little resemblence to what we call Rust today. Rust only became more than a personal project around 2009 and the first release (0.1) only came in 2012. Looking around, I find no reference for avoiding null reference in Rust before 2010.
- deleted 2y ago[deleted]
- lolinder 2y agoUnfortunately it seems like Java still hasn't learned the non-nullable-by-default rule—this proposal introduces two new types, with the default un-annotated type still answering :shrug: when asked if it's nullable.
- kaba0 2y agoIt’s almost like you can’t change the default without breaking 467482 million lines of code? As they clearly write at the end, they will think of additional proposals, like making non-nullable the default on a per-class/package level. But they don’t have the luxury for that. It’s like, possibly the best language team on earth did think of this tiny little obvious detail.