5 ms·
First, your parent comment misunderstood what the section they were critiquing is referring to. It's not about nullability (which is orthogonal) but about refer
by pron 4mo ago
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.
- nixon_why69 4mo agoValue 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.
- gf000 4mo agoYou 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).
- tsimionescu 4mo agoThis 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 4mo agoBut with null-restricted types, Integer! and int has no difference semantically and representation. They plan to introduce null-restricted types in future.
- pron 4mo agoI 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 4mo agoIn 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.
- zoogeny 4mo ago> More generally than just Java, nullability is often a property not of a type but of a variable. This is a tangent, but I'm not sure I follow this. Can you give an example to make this clear?
- pron 4mo agoYes, but it comes from Java having both runtime and compile-time types; it's harder to make the distinction in languages that don't have runtime types. In Java, you can ask, `x instanceof T` (and this is a runtime test), which means, is x one of the values in the set of values allowed by T. `null instanceof Integer` is false, even though a variable of type `Integer` can be assigned a null. So you can think of `Integer x` as being `Integer|null x`, i.e. x can hold a null, even though `null instancof Integer` is false.
- resonious 4mo agoThis 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...
- throwaway2037 4mo agoGUI frameworks have similar arguments around their design choices.
- pron 4mo agoWhat's funny is that the only languages in the same popularity league as Java are Python and JS/TS (and possibly C and C++ if you want to extend things to more domains) yet I rarely ever hear people saying Java should be more like these languages. It's because many of the people who dislike Java also don't like any of the most popular languages (even those who like, say, Python better don't think Java should be more like Python). These people may point out that languages become more or less successful not because of the things these people care about but because of other factors. And they're right, but then the question is, shouldn't a smart product team focus more on the things that actually matter more to more people? Programming languages are tools, and so their value is not intrinsic, but comes from the value of the software they're used to create. Now, some people claim that Java's success is largely the result of it being one of the most hyped languages of the late 90s and early 00s, alongside VB, Delphi, FoxPro, and C#. But this claim doesn't stand up to even the slightest scrutiny.
- ptx 4mo agoWhat'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 4mo agoRegarding "What's wrong with what .NET did with threads?", see https://cr.openjdk.org/~rpressler/loom/Loom-Proposal.html 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.
- Athari 4mo agoThe colorless functions approach has well-known disadvantages though, including providing less control and making interop a pain. It isn't like one approach is the correct one and another is a mistake.
- pron 4mo ago> including providing less control and making interop a pain This is true in some languages but not in Java. The limitations (and performance cost) are not from the nature of continuations/stackful coroutines/"colourless functions", but from their interaction with other constraints and existing designs in the language. E.g. in Java, virtual threads have zero impact on FFI. In general, the costs and limitations associated with a feature in language X don't extrapolate to language Y, because they often stem from interaction with existing constraints in language X. The design of FFI is a very common source of problems for various features. For example, if the FFI is designed such that you frequently pass pointers to to objects to C, that can have a big impact on other features. In Java, you nearly always only pass pointers to "off heap" memory, i.e. memory that's not managed directly by the JVM. While this has no performance cost, you could say that this, in itself, has some convenience cost, except Java programs need to rely on FFI much less than other languages, so the overall cost to convenience is low.
- mixolydianagain 4mo ago> All of the language differences between .NET and Java fall in this "non-consensus" zone Curious if you think fibers vs async/await is still in this zone (amongst experts). It seems fibers are objectively better. But I'm no expert*
- pron 4mo agoI think user-mode threads are better when the language already has threads. I'm not sure they would have been better for JS. But yeah, this one is probably less controversial than things like properties and extension members, which we also said "yeah, nah" to.
- sroussey 4mo agohttps://github.com/oven-sh/WebKit/pull/249 https://github.com/oven-sh/WebKit/pull/249
- aardvark179 4mo agoAlthough the work being done to enable multiple threads in JS is impressive I think it will be hard to make robust in many casss without locks, or fairly strict limits what operations can be performed on objects shared between threads. The property lookup and modification process in JS is complex enough as is, is not specified in an atomic kind of way, and has many opportunities for user code to be run as part of accessor properties. Enabling it in multithreaded implementations is tricky without opening up deadlocks when modifying property collections, and even with that could likely be broken by some suitably evil code. Ive worked on more than one implementation that offered some degree of multithreaded access and it’s generally only safe when limited to simple properties. Async / await avoids those issues because none of the places where user code can be executed allow async code, so there is no opportunity for the world to be changed under your feet during something like property access.
- sroussey 4mo agohttps://tc39.es/proposal-structs/ https://tc39.es/proposal-structs/ Structs, Shared Structs, and Synchronization Primitives There are a few things that would be required to make it all work, this would be one of them.
- jayd16 4mo agoThis is pretty funny... "All differences are opinions....except what .net did. Those are wrong!" I personally think Java continues to to waste a lot of time and come to a slightly more verbose and worse solution again and again. Structured concurrency is like c# async/await with less sugar. Streams are just LINQ but worse. It's probably exactly because of the "not like .NET! We must be different to explain being late" mentality.
- egeozcan 4mo agoAs a person with a lot of .NET experience but has been working on other tech since 6 years, the wow effect I had from using LINQ has never been repeated with anything else. It felt like magic, maybe too much magic, but so useful nevertheless.
- pjmlp 4mo agoLINQ comes from FP, and was introduced into C# via Haskell, and actually the first version (.NET 3.5) was quite similar to Smalltalk or Common Lisp collections.
- pron 4mo agoJava is getting that power in a different, more orthogonal way, IMO, through Project Babylon: https://openjdk.org/projects/babylon/ https://openjdk.org/projects/babylon/
- parampampam 4mo agoNothing funny there. They shared their opinion as an example. Yes it differs from others, that’s what they was talking about.
- gf000 4mo agoBoth languages/runtimes are decent, stable and good choices for running production systems. They have different philosophies though, C# is mostly "give the developer a complex toolkit so they can do whatever they want, but keep the runtime simple", while Java is more like "keep the language as simple as possible, and put new features mostly into the runtime making it more complex, but benefiting even old code". Async vs virtual threads is a clear example of that. The former makes the language much more complex, and has a huge surface area where it may clash with other features, so a developer has to remember all of these. But it's a simple machinery under the hood. Meanwhile virtual threads don't change the language at all, it's the same as it was with Threads, but under the hood it is a very complex feature. And in this particular instance I think it is quite clear cut that Java made the correct decision, for the most common use case of these languages having non-blocking IO "automatically" makes for significantly better user experience.