6 ms·
Doesn't an Optional basically cover this case
by randomopining 2y ago
Doesn't an Optional basically cover this case
- hedora 2y agoAn Optional is just a tri-valued null (null, None, and Some), so no. It'd be nice if Java had a concept of a never-null reference (like a C++ reference vs. a C++ pointer), but the @NotNull annotation wasn't enforced the last time I checked. Also, there's no way for an object to express that invariant because encapsulation is so weak. Given only this constructor (and no reflection): Foo() { foo.bar = new Bar(); /* foo.bar is final; Bar() does not throw */ } callers can still get an instance of Foo with bar set to null. Anyway, null handling in java somehow manages to be worse than C, where you can at least inline a struct into another, statically guaranteeing the instance of the inlined struct exists. I can't think of another statically typed language that screws this up so badly. It just keeps getting worse with stuff like Optional and @NotNull. (Disclaimer: I haven't followed java for 4-5 years; it's possible they finally fixed this stuff.)
- jflwyasdf 2y agoFortunately, Uber made tooling for languages with broken type systems * https://github.com/uber/NullAway https://github.com/uber/NullAway * https://github.com/uber-go/nilaway https://github.com/uber-go/nilaway
- erik_seaberg 2y agoLombok, Error Prone, and Kotlin also have their takes on the problem.
- durable_queue 2y agonull can be avoided with a good linter
- kbolino 2y agoNot avoided altogether. Static checkers cannot possibly follow all code paths, and they generally err on the side of false negatives rather than risking too many false positives causing people to disable them.
- dexwiz 2y agoI wasn’t aware they preferred type II errors. That makes sense, but I don’t really expect tools like that to work across modules.
- kbolino 2y agoIt depends on the specific tool and how it's configured. But that has been my experience with many tools configured with their recommended settings.
- kbolino 2y agoAssuming that was the only constructor you defined on class Foo, and you used this.bar instead of foo.bar (latter won't compile), then the caller can't possibly get a Foo with bar set to null (except by reflection, and there are ways to prevent that). Moreover, even if new Bar() did throw an (unchecked) exception, the invariant would still hold, since Foo would rethrow the exception. This has always been the case, as far as I know.
- hedora 2y agoDoing it requires two threads. Thread A sets a shared reference to a newly allocated and null initialized reference to Foo: shared = new Foo(); While that's running, thread B invokes a method on the reference that assumes bar is non-null: shared.useBar(); // null pointer exception Later, thread A runs the constructor for Foo.
- kbolino 2y agoI think you're right, if access to shared is not in any way synchronized. But the correct way to handle this, at least in this case, is to mark shared as volatile, which guarantees thread B will only ever read null or a fully constructed Foo from shared. This has been the case since Java 5, released 20 years ago, thanks to JSR-133.
- tsimionescu 2y agoBy that standard, C and C++ are much worse, since they offer no runtime encapsulation at all, and have much worse and more subtle multithreaded errors (e.g. Java at least guarantees that all native word sized reads/writes are atomic, if I recall correctly). C++ doesn't even guarantee that a reference can't be null, or worse, deallocated before it is dereferenced. They allow you to specify that a field is of some type and shouldn't be null, which is nice, but they don't enforce that in any way, they just call any code path that violates it UB. For example, this is code that any C or C++ compiler will happily run and do something: struct Bar { int b; }; struct Foo { struct Bar bar; } foo; strcpy((char*)(&foo), "ABC"); Or in relation to null C++ references: int& foo(int* p) { return *p; } int &r = foo(nullptr); //UB, but in practice will likely result in a null reference at runtime Similarly, accessing an object from multiple threads without synchronization means its value is not fully defined in Java. Unlike C or C++, it is at least known to be a Java type, not a memory corruption vulnerability.
- alkonaut 2y agoWait, javas Optional is a reference type so it can be null? Doesn’t that almost defeat the purpose of it?
- Defletter 2y agoYup. Your IDE will likely highlight it as an issue, but it's totally legal to return a null Optional. There's nothing special about it, it's just a wrapper class.
- alkonaut 2y agoDid the project to add value types to Java (I’m sure I heard of it a decade ago) never finish?
- Defletter 2y agoNot yet, that's Project Valhalla iirc. It's coming along but hasn't been merged yet. I don't believe it's even a preview feature within the JDK yet.
- steve_rambo 2y agohttps://openjdk.org/projects/valhalla https://openjdk.org/projects/valhalla
- michaelt 2y agoArguably yes, but that doesn't stop people using it. Basically Java had nulls from the start. A decade or so later some people who didn't like nulls introduced their own Optional type, as a third-party library. Enough people liked it that Optional was added to Java's standard library. But as it's just an object, it can be null. Some null avoidance enthusiasts also use third-party @Nullable and @NotNull annotations, which some automated code checking tools will attempt to verify during compile/test.
- paulddraper 2y agoKinda. Every non-primitive is nullable in Java. Adding Optional doesn't/can't change that. You can have a gentlemen's agreement to prefer None to null.
- simpsond 2y agoYeah, I wish the VM would prevent null assignment of optional and force to empty. There are probably side effects I can’t think of here and certainly would cause problems with legacy code misusing optionals.
- sedro 2y ago> I can't think of another statically typed language that screws this up so badly. It just keeps getting worse with stuff like Optional and @NotNull. Java might be the only language where a simple assignment `x = y` can throw a NullPointerException (due to auto-unboxing)