Remix.run Logo
rf15 9 hours ago

I appreciate the hard work that went into the things that did make it into Valhalla eventually, but:

> The model was powerful, but also mentally heavy

No it isn't! it is this interpretation that kills off the null-safety debate entirely. Saying you have a variable that cannot be null is not a mentally taxing distinction, especially since everything is labelled thoroughly.

> The team, faithful to the lesson “simplify the model for the user, even at the cost of the performance ceiling,” ultimately dismantled this dualism.

but it would have simplified it for the user.

The whole attitude and process around this and the other topics gives me very little faith that Java can be steered in a sensible direction here. The type system of a programming language is supposed to give convenient guarantees to the developer on a CPU that can only do numbers. There is no reason to reduce the optional(!) safety guarantees you can offer with the excuse of "too mentally taxing".

Hell, they even get there half way by recognising:

> the language model and the JVM model don’t have to overlap one hundred percent

andyjohnson0 8 hours ago | parent | next [-]

> The whole attitude and process around this and the other topics gives me very little faith that Java can be steered in a sensible direction here.

I agree. The stewardship of Java seems rather lacking - particularly when compared to that of .net, where MS etc. mostly seemed to make the correct decisions from the start.

Does Java even have any value or mindshare at Oracle nowadays? The company seems to be a datacentre/compute business at this point, with appendiges for its legacy activities and a vast overhang of debt.

I sometimes wonder if the only parts of Oracle that are still profitable are the Legal and Lawnmower divisions.

pron 6 hours ago | parent | next [-]

First, your parent comment misunderstood what the section they were critiquing is referring to. It's not about nullability (which is orthogonal) but about reference/value projections.

Now, as a member of the Java team (although I'm not directly involved in Valhalla), I'm obviously biased so let me just say that both designers and fans of programming language features would do well to remember two things:

1. Opinions about features are almost never universal, even among experts, and almost each of them is about a tradeoff where different people prefer different sides. It is rare that some scientific study settles the issue.

2. These preferences are often not evenly split. Even when both sides are equally confident that their preference is the right one, sometimes 80% or 90% of programmers share a preference. The people with the strongest opinions are more often than not in the minority, because most programmers don't think so much about the programming language (nor, I would say, should they).

All of the language differences between .NET and Java fall in this "non-consensus" zone, and at least in one area I was deeply involved with, virtual thread, I can say that we thought that whatever we do we mustn't do what .NET did and that what they chose didn't work out well for them at all.

resonious 4 hours ago | parent | next [-]

This is great advice and it applies to a lot more than just language features. Different architecture, deployment setups, QA approaches are all like this. It's always "approach A is no good", "but company X uses approach A and they're doing very well", "yeah but look at all of these problems they have". Maybe a fair argument but the approach B people also have their fair share of problems...

ptx 44 minutes ago | parent | prev | next [-]

What's wrong with what .NET did with threads? Having async tasks sharing the GUI thread seems like a nice feature. Will we be able to use virtual threads and structured concurrency with Swing, e.g. to wait for a background task in an event listener?

revetkn 29 minutes ago | parent [-]

Regarding "What's wrong with what .NET did with threads?", see https://cr.openjdk.org/~rpressler/loom/Loom-Proposal.html (relevant part below):

  An alternative solution to that of fibers to concurrency's simplicity vs. performance issue is known as async/await, and has been adopted by C# and Node.js, and will likely be adopted by standard JavaScript. Continuations and fibers dominate async/await in the sense that async/await is easily implemented with continuations (in fact, it can be implemented with a weak form of delimited continuations known as stackless continuations, that don't capture an entire call-stack but only the local context of a single subroutine), but not vice-versa.

  While implementing async/await is easier than full-blown continuations and fibers, that solution falls far too short of addressing the problem. While async/await makes code simpler and gives it the appearance of normal, sequential code, like asynchronous code it still requires significant changes to existing code, explicit support in libraries, and does not interoperate well with synchronous code. In other words, it does not solve what's known as the "colored function" problem.
Regarding Swing, virtual threads are "just" threads so no reason they (and structured concurrency) can't be used.
nixon_why69 4 hours ago | parent | prev [-]

Value types kind of definitively don't have null, right? You can have a zero int but not a null int. So nullability is not entirely orthogonal to value types, its an advantage for value types where they are practical.

pron 3 hours ago | parent | next [-]

I didn't say nullability is orthogonal to value types; I said it was orthogonal to the two-projections world, which is what that text in the article was about rather than nullability.

As to value types and null, I'm not sure about the current picture, but the general idea is that you declare what semantic properties you want - identity or not, nullable or not, tearable or not - and then the compiler picks the best technical in-memory representation for each use. For example, the compiler could choose not to flatten variables that could be null in the heap but to flatten them in the stack. That's the general idea, but I'm not sure about the details, some of which may yet change.

More generally than just Java, nullability is often a property not of a type but of a variable. For example, in C, an int may not be null, but a pointer to an int may be. Now, in C, `int` and `int*` are two different types, but that's exactly a distinction that the original projection-spit design made and we wanted to avoid. But you could still end up with a variable that could hold either an integer or a null and another that may hold an integer but not a null, only this is separate from the reference/value projection, which combines both identity and nullability (in C, `int*` is not only nullable, but also has identity).

ScoobleDoodle 2 hours ago | parent [-]

In case you want to edit it back in: in the 3rd paragraph second sentence, the star in your int* got gobble up by formatting to italics.

tsimionescu 3 hours ago | parent | prev | next [-]

This won't be true in Java, though - in Java, you will have null Integers at least. It seems that int will remain a different thing entirely from Integer, and will remain a JVM-only concept.

joe_mwangi 19 minutes ago | parent [-]

But with null-restricted types, Integer! and int has no difference semantically and representation. They plan to introduce null-restricted types in future.

gf000 4 hours ago | parent | prev [-]

You can have a null int, it's called Integer.

What was taken away is the other, identity-having functionality of Integer and similar (e.g. no synchronization).

PaulHoule 4 hours ago | parent | prev | next [-]

.NET made different decisions.

I was at a conference on scientific programming in Java very early on that Geoff Fox put on up at Syracuse and we had a list of requests from Sun that they didn't give us but Microsoft gave many of them right away.

On the other hand I really like Java's all-virtual approach to inheritance because the .NET model gives programmers more ways to screw up and get confused.

Both languages slipped in generics after 1.0. Java used type erasure in a way that made it so a List<String> is really a List so generics could be retrofitted easily to existing code. .NET's implementation of generics let you do more but caused a rift in the ecosystem between generic and non-generic collections.

I'd say long term Oracle's stewardship of Java has been very good. JDK 8 puts lambdas on your fingertips with a very fluent syntax that belies the idea that Java is terribly verbose. Since then Java has gotten steadily better release after release while maintaining great compatibility.

I work with people who are conservative about updates because they are worried about breaking things but for the last few LTS releases I've said "it ought to be really easy, let's give it a try" and it is really easy and we get performance improvements we can feel.

rjrjrjrj an hour ago | parent [-]

Java stagnated for quite a while. Seemed like everyone was stuck on Java 6 for about a decade. But JDK8 was a huge step forward. Lambdas, streams, and a date/time API that is the best I've seen.

gf000 8 hours ago | parent | prev | next [-]

> The stewardship of Java seems rather lacking

In what way? If anything Java's main developers (employed by Oracle for the most part, working on the completely open source and free OpenJDK) are extremely knowledgeable and are responsible a big jump in how fast the platform evolves. They have added proper algebraic data types to the language, delivered virtual threads and garbage collectors that decouple pause times from heap size. Like if anything, Java is at the best place it has ever been.

lmm 8 hours ago | parent [-]

> They have added proper algebraic data types to the language

No they haven't. E.g. they added a class that superficially looks like Option but subtly breaks the rules that Option is meant to follow, ensuring that no-one can ever manage to migrate existing codebases away from using `null`.

gf000 8 hours ago | parent | next [-]

Sealed classes/interfaces and records are proper sum and product types.

The stdlib's Option type predates this language update by a long shot, so it doesn't use sealed classes, but it is now possible to have the usual FP "Maybe" type in Java:

``` sealed class Maybe<T> permits Some, None { record Some<T>(T obj) {} record None() {} } ```

(You will probably have to write Maybe.Some and I might have messed up the generic syntax as I wrote it on my phone, but that's mostly how it looks)

tsimionescu 3 hours ago | parent | next [-]

Except this is completely wrong.

First, a record can't extend anything, it's not even valid syntax, so a sealed class can't permit record subclasses. So no, it's not possible to create a Maybe<T> class in Java that can only represent a Some<T> or a None<T> record. You could do it with regular classes, or if it's ok for Maybe<T> to be an interface.

Secondly, regardless of the sealing, nothing in any current or near future of Java prevents you from assigning `null` to any class of any kind you might create. So you can always have `Maybe<T> x = null`, or even `Some<T> x = null`.

None of this will change with the adoption of value classes either. So no, there is absolutely no way in Java to create a real Optional/Maybe type that would guarantee that a variable is either an object of a given type or None. There is probably some way to do it for your specific project using annotation processors, of course, but that is very different from having built-in support.

munksbeer 37 minutes ago | parent [-]

It's probably a typo. He meant sealed interface. I think that should be quite obvious.

ahoka 6 hours ago | parent | prev [-]

Or just do as Kotlin and embrace null, but in a type aafe way.

an hour ago | parent | prev | next [-]
[deleted]
_kidlike 8 hours ago | parent | prev [-]

optional is not how algebraic data types are implemented in Java. Basically it's the combination of sealed types and records.

pjmlp 4 hours ago | parent | prev | next [-]

Given the mess of some .NET frameworks currently, and how bad it has taken for non nullable references to be widely adopted, I don't see those correct decisions on the last releases.

It is all about having AI on the framework, Aspire, multiple Web and Desktop frameworks all over the landscape.

Those interceptors and inline arrays via attributes instead of proper language grammar aren't that great either.

rf15 8 hours ago | parent | prev | next [-]

How .net got so many things right where java did not is a mystery to me, but appreciated (it has its own flaws, of course). Java, in my understanding, is still of core relevance to Oracle, and tied into a lot of contracts that require very little effort from them to maintain. But you are correct in observing that they want to be a datacentre/compute business more and more these days; they may have in fact overcomitted to this due to the AI craze, since shareholders are already complaining.

Someone 6 hours ago | parent | next [-]

> How .net got so many things right where java did not is a mystery to me

Part of the reason for that is that Java is older. https://en.wikipedia.org/wiki/C_Sharp_(programming_language)...:

“In interviews and technical papers, he has stated that flaws in most major programming languages (e.g. C++, Java, Delphi, and Smalltalk) drove the fundamentals of the Common Language Runtime (CLR), which, in turn, drove the design of the C# language.”

Also, some of Java’s design warts may be there because Java was initially envisioned for much smaller devices.

toyg 5 hours ago | parent [-]

This. C# was basically always meant to be "Java but done right". It came several years later, after Microsoft was legally barred from "EEE"-ing Java and required a direct competitor.

newsoftheday 2 hours ago | parent | next [-]

> It came several years later, after Microsoft was legally barred

That is an eloquent way of re-writing the history of Microsoft stealing Java and not being allowed to get away with it.

cm2187 5 hours ago | parent | prev | next [-]

But what I don’t get reading the original article is that they present how to insert struct in an object oriented language as an intractable problem, whereas a good implementation with .net (as far as I can tell) has been out there for nearly 30 years. And C# was shameless about stealing from other languages.

pjmlp 4 hours ago | parent | prev [-]

Ironically, they still do need Java for Azure, https://devblogs.microsoft.com/java

jbellis 7 hours ago | parent | prev | next [-]

It's no mystery. https://en.wikipedia.org/wiki/Anders_Hejlsberg

pjmlp 4 hours ago | parent [-]

Which recently decided that Go was a better option than C# for the Typescript rewrite, exactly because not all decisions were done correctly to make C# a better fit for the problem.

Rohansi 2 hours ago | parent [-]

Go was chosen mainly because it aligned more with how the existing compiler is designed. They did not want to redesign the compiler which eliminated C# as a choice. So Go is apparently just a better fit for quickly porting JavaScript code to.

6 hours ago | parent | prev | next [-]
[deleted]
amitport 7 hours ago | parent | prev [-]

The mystery of why .NET got so many things right is simply that C# was built several years later by the exact same Microsoft engineers who had previously worked on extending Java, giving them a perfect blank slate to fix the architectural flaws they had already encountered

Second mover advantage.

ah1508 2 hours ago | parent | next [-]

virtual thread instead of async/await is a counter example.

Java is more used than C#, they can wait before delivering a new feature (given their leader position) but cannot deliver a flawed implementation that would stay in the language forever. Glad to have virtual threads and the backward compatibility that comes with it instead a Async version of sync methods + async and await keywords all over the code and Task as a return type in my interfaces methods to allow implementations to do non blocking I/O calls if they need.

I use Java and C# and appreciate them both.

amitport 37 minutes ago | parent [-]

C# did not ship with async/await, and Java didn't have virtual threads back then. I am specifically referring to the initial choices made in C#'s foundation.

lyu07282 8 minutes ago | parent | prev [-]

> giving them a perfect blank slate to fix the architectural flaws they had already encountered

and then they make everything nullable by default in c#...

drzaiusx11 3 hours ago | parent | prev | next [-]

I'm honestly happy with java lang's stewardship over the past decade, this particular JEP notwithstanding (it's fine, but the good parts come later.) They're conservative in adopting new features whereas I see every other language bolting on everything under the sun with reckless abandon. I prefer the "let's see what shakes out" and adopt "the good parts" which seems to be Java's approach. Sugar like "var" from kotlin, project loom event loop like nodes, etc.

Zardoz84 3 hours ago | parent [-]

Type inference was on DLang far before that Kotlin even existed. The only difference it's that reuses "auto" keyword.

gf000 2 hours ago | parent [-]

I mean, type inference goes decades before Dlang.

dingi 38 minutes ago | parent | prev | next [-]

As someone who works with Java on a daily basis alongside a dozen other technology stacks, let me go out on a limb and say that I believe Oracle has been a stellar steward of the language. Java has been evolving quite nicely and at a reasonable pace, all without breaking the ecosystem or causing fragmentation. It certainly has its drawbacks, but doesn't everything?

pfannl 4 hours ago | parent | prev | next [-]

C# often feels like Java with hindsight; Java feels like Java with 30 years of backward compatibility debt.

pjmlp 4 hours ago | parent [-]

Hence why so many .NET projects keep being .NET Framework instead having migrated to modern .NET.

watwut 8 hours ago | parent | prev [-]

> particularly when compared to that of .net, where MS etc. mostly seemed to make the correct decisions from the start.

Wut? I did worked on .net projects and all it achieved was making me like java a lot more then previously.

andai 6 hours ago | parent | next [-]

I had the opposite experience, spent a year with each language, first Java then C#, and to me C# felt like "Java done right". (Which appeared to be the original design goal behind the language!) So I'm curious about your experience.

To me it felt a bit less like a religion and more like a language. It didn't force me to do things a particular way, quite as much. (Still more than I would have liked, though! After all, it's called that[0] for a reason :)

[0] https://www.reddit.com/r/ProgrammerHumor/comments/ddc4b0/mic...

ivolimmen 4 hours ago | parent | prev | next [-]

Same for me. I have worked with Java since 1.2.2 and used .NET for something like 10 years (don't remember the versions). Most important differences are:

  -Java always has an API, .NET is about extending an existing application (Servlet API vs IIS)
  -Java has a nicer IO as .NET has bidirectional streams (You can't wrap streams in .NET).
  -Linq is nice but has a huge caveat: if a Linq provider does not implement it fully to falls back to the .NET collections. So trying to 'Skip' and 'Take' on a ActiveDirectory will fall back to collections in memory and cause a crash on a huge AD in production (Yes had the pleasure).
  -Java's Eco-system is way bigger.
jaen 3 hours ago | parent | next [-]

> -Linq is nice but has a huge caveat: if a Linq provider does not implement it fully to falls back to the .NET collections. So trying to 'Skip' and 'Take' on a ActiveDirectory will fall back to collections in memory and cause a crash on a huge AD in production (Yes had the pleasure).

How do you expect this to work then? If the provider is bad, blaming LINQ for it makes no sense...

You either have a high level of abstraction and possible performance pitfalls - or a low level of abstraction, and also performance pitfalls since the code is less modular, more coupled and harder to read.

LINQ can in many cases improve performance significantly in large applications when used properly, since it avoids N+1 query problems due to implementation hiding/modularity, and allows composing parts of queries across different vertical subsystems of the application (vs. each subsystem doing its own query and then joining them with more boilerplate).

Nothing in Java compares to this. jOOQ and Hibernate (and the rest in the ORM ecosystem) are pale shadows, exactly due to lacking language features (such as reified expression trees), and even then, they only work with databases.

Rohansi an hour ago | parent | prev [-]

> .NET is about extending an existing application (Servlet API vs IIS)

I don't think this is true anymore since ASP.NET Core. While you can still run under IIS but it's a more typical reverse proxy setup instead of running inside IIS.

> You can't wrap streams in .NET

You've always been able to wrap streams in .NET so I'm not sure what you mean by this

peterashford 3 hours ago | parent | prev | next [-]

Yeah, me too. Java always seemed to consider design a lot more than C# which seems to have taken more of a kitchen sink approach to language design. That stuff piles up over time (see c++)

newsoftheday 2 hours ago | parent | prev | next [-]

Agreed. I jumped on the .NET bandwagon in 2000 and was on it for several years but ended up going back to Java by 2005.

bazoom42 5 hours ago | parent | prev [-]

What do you like about Java compared to C#?

watwut 5 hours ago | parent [-]

First, huge open source ecosystem and culture. Mature open source projects, culture of writing blogs and tutorials (that one will die due to changes in search engines, but it was super nice while it lasted).

Second, working in C# felt clunky, as if every other thing was done to check the checkbox "done" and the author called it the day once it sorta kinda worked. There was some additional syntactic sugar in that language that was nice, but it did not made that much difference in practice and I don't miss it after coming back to java.

Third, I found the obsession with bashing java by people who have no idea how java projects look like and which problems they have annoying.

_kidlike 7 hours ago | parent | prev | next [-]

so your complaint is about the blogger, not the Java language?

also, null markers are coming too: https://openjdk.org/jeps/8303099

Its just that they have to deliver things incrementally. This PR that introduces value classes/objects is already 200k lines long.

rf15 3 hours ago | parent [-]

I agree, but I have seen the previous proposals/jeps and the discourse around them is rather discouraging. I hope this one can find it's way out of Draft, but I'll only believe it when I see it.

21asdffdsa12 7 hours ago | parent | prev | next [-]

Nullable is just a different loadout state in Railway Orientated Programming. So, no reason to put different flavours of state into the language directly, when its a solved thing since (checks slides) 2012. There is just rails - going to A or going to B, depending on the trains loadout.

If you have language-wars about a concept going in and out of existence, that is a hint that there is demand and the language does not properly handle the demand or when it handles it, it creates mental overload.

> Value

> Errorstates

  > Null

  > IoExceptions

  > WeirdOsStatesNeededToHandleUpstairs
https://fsharpforfunandprofit.com/rop/

As the pythons said: Get on with it!

drzaiusx11 3 hours ago | parent | prev | next [-]

They just decided to tackle non-nullable value types in a follow-on JEP. I don't think they're saying it's untenable. You don't eat the elephant in one bite and all that.

That said, we've been gnawing on this limb for a while...

arein3 3 hours ago | parent [-]

Ill be old when null safety will finally arrive

This takes longer than game of thrones books

pron 6 hours ago | parent | prev | next [-]

> it is this interpretation that kills off the null-safety debate entirely. Saying you have a variable that cannot be null is not a mentally taxing distinction, especially since everything is labelled thoroughly.

I think you've missed what this is referring to. It isn't about null safety (which is orthogonal) but about having reference/value projections analogous to Integer/int.

What the Valhalla team ended up doing is, instead of having two projections for each type, one with identity and one without, value types never have identity and so Integer and int are synonymous, and the memory layout is determined automatically based on context and optimisation decisions. This is why the semantics of == for the primitive wrappers (like Integer) were changed, as they now don't depend on whether the "reference projection" or the "value projection" is used.

> There is no reason to reduce the optional(!) safety guarantees you can offer with the excuse of "too mentally taxing".

This is not what happened here.

tsimionescu 3 hours ago | parent [-]

> and so Integer and int are synonymous

Except they're not, as I can do Integer x = null, but not int x = null. So an Integer is forced to occupy more memory, for very very unclear reasons. And this is also deeply weird - there is no other (mainstream?) language that allows null value types.

pron 3 hours ago | parent | next [-]

That's not quite how it works in Valhalla. Because Integer and int already exists, your declarations above will be interpreted with those meanings, but (assuming some TBD nullability annotation), they will be equivalent to `int? x` and `Integer! x` respectively. In other words, the nullability of a variable is a separate concern from the data type, and other than the different defaults on variable declarations (as these types already exist), Integer and int become the same type.

tsimionescu 2 hours ago | parent | next [-]

This may be true, hopefully, in a future version of Java, if the article isn't wrong. In JDK 28 with the Preview feature enabled, int is not nullable and Integer is nullable, and they are thus different types under the hood. Which also means that on most CPU architectures, Long[] will be just as inefficient compared to long[] as it was in any previous version of Java.

pron an hour ago | parent [-]

> int is not nullable and Integer is nullable, and they are thus different types under the hood

Yes and no, because in Java we have runtime types and compile-time types. The frontend compiler will treat these types as having different defaults on nullability, but they'll compile down to the same representation (when appropriate). I.e. if the compiler sees that some Integer variable is never null, it will compile down to the same thing it would if it were declared an int.

You're right, however, that on the heap, until the language adds nullability information, the compiler cannot generally know that an Integer will never be null (unless it's a final field), so it's likely that, unlike on the stack, you'll get a different representation.

2 hours ago | parent | prev [-]
[deleted]
mike_hearn 3 hours ago | parent | prev [-]

It's not that weird. The goal is to enable existing types to be turned into value types without porting the users, so stdlibs and other libraries can mark types as value types without an API break.

That goal is an ideal and can't be reached perfectly. Converting a type to a value type will break clients that synchronize on them, or rely on identity for some reason. But such cases are rare, and can be weighed up on an individual basis when making the decision about whether to do it. Storing things in a nullable variable on the other hand is very common and changing the rules to prevent it would make every such change a source incompatible breaking change.

theptip 26 minutes ago | parent | prev | next [-]

> a single type would have two projections: a value variant (flat, never null, behaving like a primitive) and a reference variant (a box that allows null). Across various iterations this was written as Point.val/Point.ref, and later they experimented with the Point! and Point? syntax.

This seems heavier? Having two representations and manually having to refer to .val or .ref?

You can argue that the extra flexibility lets you write safer (non-nullable) code but naively it seems more complex at the language level.

rzmmm 8 hours ago | parent | prev | next [-]

This is mainly for performance and memory layouts, it would not have improved safety guarantees of java.

rf15 8 hours ago | parent [-]

It would have implicitly brought some null-safety to java with primitive-like classes that can not be null.

groundzeros2015 3 hours ago | parent | prev | next [-]

> very little faith that Java can be steered in a sensible direction here.

What? It’s been getting better with each release. Valhalla brings features that address key problems, and they didn’t rush to it either.

jmyeet 4 hours ago | parent | prev | next [-]

Java made several mistakes. It also made some questionable (yet often defensible) decisions. It's understandable. Type erasure was one I believe was a mistake. It's talked about in the article. Yes, you kept binary compatibility but you that created so many other problems such as not being able to use value types in generics. Notably, C# looked at that and said "nope". Type erasure is also hurting Valhalla here and the issue of value classes in generics is the second phase so is being pushed far into the future.

But a huge mistake (IMHO) was not having nullability part of the type system. You can still do this with type erasure.

Anyway, I read your comment as "nullability isn't complex" (paraphrased) but that's not the author's point. What's complex is having a value class and a regular class of every class and you don't necessary know which one you're dealing with at the language level.

C++ is a great example of this. You can create an object ont he stack or the heap and that's really what we're talking about with that proposal. And that's a nightmare. Combined with pointers it meant you never knew if you could free something or not and that ownership had to be passed around with vague comments like "// retains ownership".

Anyway, the whole article is a great tale of how difficult it is to retrofit things later and how difficult it can be to fix mistakes later (eg java.util.Date).

inigyou 4 hours ago | parent [-]

How would a non-nullable class field work in Java when it can be initiqlized by arbitrary imperative code that can read it while it's being initialized?

tsimionescu 3 hours ago | parent | next [-]

Look at how Go did it. Any value type has a defined 0 value, and any variable of field of that type is initialized to 0 by default. So any un-initialized non-null able value type field could have the corresponding 0 value.

inigyou 2 hours ago | parent [-]

That's worse than null. Now every object has an invalid state. It works for Go because Go is trying to keep language complexity low. It has no good design principles behind it other than that. Also the zero value of a reference is null so you still haven't answered how a non-nullable reference field would work.

tsimionescu 2 hours ago | parent [-]

Sorry, I misinterpreted your question to be about non-nullable value classes, not non-nullable classes more generally. For reference variables, it seems that the a priori best approach would have been to generate a compiler error if the field was read before it was written; since this ship has long since sailed with final fields, it seems that the same approach would have to be taken - the "not null able" guarantee only applies after the class is fully initialized, and you can observe it as null during initialization. This is probably not a huge problem, given that initialization code always has to deal with a class breaking its invariants, since they are only established at the end of initialization.

Regarding the 0 value choice in Go, I don't agree that this is worse than null. It simply applies a design constraint that is not usually very hard to satisfy - that the 0 value of your type must have well defined semantics.

wiseowise 3 hours ago | parent | prev | next [-]

How can Kotlin do it?

inigyou 2 hours ago | parent | next [-]

Probably with hacks. Did you know a final field in Java can change its value? And I'm not talking about his reflection to make it non-final. With ordinary code only, you can read a final field before it's been initialized, so it still holds its default zero value. For example "final int x = calcX();" and have calcX print the value of x, it will be zero.

There's a whole bunch of specification language describing how constants aren't actually constant in specific situations.

I don't know Kotlin but I assume it does the same thing: until the non-nullable field gets initialized, it holds null and violates the type system.

wiseowise an hour ago | parent [-]

Nothing stops me from sticking my dick into a blender either, yet it works fine for most of the things (the blender). Both Java’s notion of final and Kotlin’s nullability work great for 99.999 use cases and you really need to go out of your way to break them.

mike_hearn 3 hours ago | parent | prev [-]

A lot of the language rules are required to make its approach to nullability work. Hence odd keywords like "lateinit var".

jmyeet 4 hours ago | parent | prev [-]

The type erasure version of this would look a lot like Hack [1]. So generic arguments would simply have a ? if they allow nulls eg List<?Point>. The list itself couldn't be null unless it was ?List<?Point>.

Now, one can argue that this is just smoke and mirrors with type erasure and it is but you can already put a Date into a List<Point> if you're so inclined because the JVM doesn't know the difference, hence type erasure. So this is no different.

I'm no JVM expert but from reading the article it seems like the chosen solution for value classes is to treat them all as a single L-type in the JVM where each primitive type is its own L-type. If I read the correctly, it means that if you have a Point value class then on the JVM level you'll be able to stuff any value class into there if you're so incline, just like with List<Point>.

Obviously we need to be concerned with fuzzing (moreso in C++) but here really we're just trying to have sensible defaults that aren't guaranteed because we can't design the language how we want from the ground up without making a new language.

Oh and there is a prosopal for this [2]. Personally, I prefer the Hack version.

[1]: https://docs.hhvm.com/hack/types/nullable-types/

[2]: https://openjdk.org/jeps/8303099

inigyou 3 hours ago | parent [-]

you seem to have ignored the question and answered a completely different one

lowbloodsugar 39 minutes ago | parent | prev | next [-]

Like yeah, every field is final but omg non-null is a bridge to far! Wtf?

imtringued 5 hours ago | parent | prev [-]

Yes, in this respect Java is 100% doomed. They've made a terrible decision and they're sticking with it for the sake of "consistency".

groundzeros2015 3 hours ago | parent [-]

I think “Doomed” is slightly dramatic for preserving some decades old null ability conventions?