[HN Gopher] A compact overview of JDK 21's "frozen" feature list
       ___________________________________________________________________
        
       A compact overview of JDK 21's "frozen" feature list
        
       Author : mooreds
       Score  : 116 points
       Date   : 2023-06-11 15:07 UTC (7 hours ago)
        
 (HTM) web link (vived.io)
 (TXT) w3m dump (vived.io)
        
       | dexwiz wrote:
       | I'm impressed. One of the big hurdles of extendable types is
       | figuring out which subtype a parameter is. Overloaded methods are
       | a blunt tool that involves lots of indirection. Generics force
       | you to structure classes in a specific way. Pattern matching is
       | the cleanish solution to the problem of "what type so I have here
       | and what do I do with it?"
        
       | nikeee wrote:
       | Seeing Java getting these features is a breath of fresh air. I
       | wonder how this will impact Kotlin.
       | 
       | Being compatible with Java was one of the goals for Kotlin. We
       | soon have a lot of features in the JVM mother language that are
       | solved different in Kotlin. For example:
       | 
       | - Data Classes vs Java's Records - Nullability - String Templates
       | 
       | Not diverging from the core language is what made TypeScript
       | successful on a long term. This won't work for Kotlin. It will be
       | interesting to see whether the languages will diverge even more -
       | maybe to an extend where they will become incompatible - or the
       | interop will converge somehow.
        
       | ArturSkowronski wrote:
       | Hey, author there - HackerNews Effect killed our AWS hosted
       | WordPress ;(
       | 
       | You can find mirror on Substack:
       | https://vived.substack.com/p/the-compact-overview-of-jdk-21s...
       | 
       | EDIT: We did the redirection to the Substack mirror.
        
         | gabereiser wrote:
         | Your pop-over to join the newsletter and continue reading won't
         | allow someone to continue reading without signing up for your
         | newsletter. There's no way to close the pop-over modal. This is
         | user hostile behavior. When scrolling, it reappears over
         | content. Very anti-user behavior.
         | 
         | This is equivalent to forced purchase required to use the
         | restroom at a venue. Don't be like that. Compassion is good for
         | business.
        
           | ezfe wrote:
           | Substack popups have a Continue Reading button that dismisses
           | it...
        
           | capableweb wrote:
           | > There's no way to close the pop-over modal
           | 
           | There is, you click outside the modal. Or hit Escape key.
        
           | ArturSkowronski wrote:
           | It is default behaviour of Substack - to be honest I am not
           | sure if it is even possible to change.
           | 
           | However, you don't need to subscribe - you can close the
           | popup and carry on!
        
             | gabereiser wrote:
             | I know, not your fault, I'm just throwing a hail-mary in
             | case they see it. It's sooo frustrating. Once you leave and
             | come back it doesn't show. So obviously they are storing
             | state on it and pushing it in your face when the MarTech
             | gods deem it appropriate.
             | 
             | Good write up though and appreciate the KotH meme.
        
         | jaxrtech wrote:
         | "web scale"
        
           | ArturSkowronski wrote:
           | And we don't even use MongoDB!
           | 
           | https://www.youtube.com/watch?v=b2F-DItXtZs
        
       | neonate wrote:
       | http://web.archive.org/web/20230611150725/https://vived.io/a...
        
       | hamandcheese wrote:
       | I'm impressed with how Java is shaping up. With records, pattern
       | matching, destructuring, and virtual threads all arrived or
       | arriving, what advantages do Kotlin and Scala bring?
        
         | kernal wrote:
         | >what advantages do Kotlin bring?
         | 
         | Elvis operator. Drops mike.
        
         | AlexITC wrote:
         | I don't see much advantage from Kotlin unless you are stuck
         | with an old jdk (like the one from Android), still, the latest
         | jdk is still far away from current Scala.
        
         | social_ism wrote:
         | Feature soup is kind of meaningless. The open source community
         | has whatever it needs now.
         | 
         | Many "alot" of java programmers in the US cant code to JDK8
         | already. I love the JVM but these Java releases are not being
         | adopted on any real scale for a reason. They break things. And
         | syntax sugar is boring and unnecessary for a crew of software
         | engineers that have no real ethos surrounding records or any of
         | these features.
         | 
         | They are just being rolled out to appease devs from other
         | ecosystems. They will not form a new or better method for
         | building systems or improve performance.
        
           | Defletter wrote:
           | For me, the biggest pain point with Java is the lack of
           | optional chaining <https://developer.mozilla.org/en-
           | US/docs/Web/JavaScript/Refe...> and nullish coalescence
           | <https://developer.mozilla.org/en-
           | US/docs/Web/JavaScript/Refe...>. I've noticed so many
           | libraries and JDK APIs that try to solve this problem in such
           | a limited way. What is `Objects.toString(thing)` other than a
           | botched `thing?.toString() ?? "null"`? And that utility
           | method is only limited to `toString`, what if you want null-
           | safety for other methods? You have to write that yourself.
           | It's silly. Adding optional chaining and nullish coalescence
           | would be a wonderful QOL change. It'd reduce code complexity,
           | and it would flatten code (ie, hide less logic behind tiny
           | methods).
           | 
           | I do a lot of serialisation. You have no idea how much I'd
           | love to be able to just to `data.set("thing",
           | this.valueEnum?.name())` instead of having to do
           | `data.set("thing", this.valueEnum == null ? null :
           | this.valueEnum.name())`.
        
             | kaba0 wrote:
             | > I do a lot of serialisation. You have no idea how much
             | I'd love to be able to just to `data.set("thing",
             | this.valueEnum?.name())` instead of having to do
             | `data.set("thing", this.valueEnum == null ? null :
             | this.valueEnum.name())`.
             | 
             | You may be already familiar with this, but mapstruct is a
             | godsend package that easily beats any kind of optional
             | chaining.
        
         | jeroenhd wrote:
         | Until Java finally includes real nullability guarantees in its
         | language (and its standard library) I'll stick to Kotlin when I
         | can.
         | 
         | These improvements are still nice for when you're stuck dealing
         | with Java code, but in my experience getting projects to run on
         | the latest version of Java isn't very easy with various
         | dependencies all needing support first.
        
           | jdm2212 wrote:
           | FWIW, it is not difficult to set up NullAway:
           | https://github.com/uber/NullAway
        
         | mm007emko wrote:
         | Without Scala, Clojure or Kotlin this probably would have not
         | happened.
        
         | gavinray wrote:
         | I can give perspective as someone who enjoys modern Java,
         | writes Kotlin at their dayjob (and loves it), and also likes
         | Scala 3.
         | 
         | Here are the things that if Java had, I probably wouldn't see a
         | reason for other languages:
         | 
         | 1. Lack of first-class lambda syntax. In Kotlin/Scala you can
         | write something like:                  fun doSomething(handler:
         | (String, Int) -> Foo): Blah
         | 
         | In Java, all you have are the "Function<>" and related
         | interfaces, which are clunky to use.
         | 
         | 2. Opaque types (Scala 3). These have been one of the most
         | impactful programming features I've ever used, and I sorely
         | miss them in languages that lack them.                   object
         | Foo:             opaque type UserId = Int             opaque
         | type Email = String             def mkEmail(s: String): Email =
         | s             def findUserIdByEmail(email: Email): UserId = 42
         | import Foo.*         val email: Email = mkEmail("foo")
         | val valid: UserId = findUserIdByEmail(email)         val
         | invalid1: UserId = findUserIdByEmail("bar") // error: can't use
         | String as Email         val invalid2: UserId = 123 // error:
         | can't use Int as UserId
         | 
         | 3. Union types (Scala 3). You can emulate them in Java/Kotlin
         | with Sealed Types but it's much more verbose.
         | type JsonScalar = String | Int | Boolean         type Json =
         | JsonScalar | Map[String, JsonScalar] | List[JsonScalar]
         | // Makes writing functions that take multiple argument types
         | much easier:         def handle(it: String | Int | Boolean):
         | Unit = ...
         | 
         | 4. Context-oriented programming with "given/using" in Scala 3
         | and "context-receivers" in Kotlin.
         | 
         | This one is harder to explain succinctly but essentially it
         | allows you to decorate methods/classes with required
         | "contextual" args.
         | 
         | Instead of passing them as regular function arguments, you must
         | invoke the function inside of an "environment"/"context" where
         | the requirements are satisfied.
         | 
         | This makes threading dependencies through your code much
         | easier, and eliminates the need for dependency injection
         | frameworks in many cases.                   interface Logger {
         | fun log(message: String)         }              object
         | ConsoleLogger : Logger {             override fun log(message:
         | String) = println(message)         }              ctx(Logger)
         | fun doSomething(): Int {             log("Hello")
         | return 42         }              fun main() {             val
         | logger = ConsoleLogger             with (logger) {
         | doSomething()             }         }
         | 
         | 5. First-class support for asynchronous programming. With
         | "suspend" in Kotlin and a current prototype being done in Scala
         | 3:
         | 
         | - REPO: https://github.com/lampepfl/async | SLIDES:
         | https://github.com/lampepfl/async/blob/main/scalar-slides.pd...
         | | YOUTUBE TALK: https://www.youtube.com/watch?v=0Fm0y4K4YO8
         | 
         | 6. Passing arguments by name, rather than positionally.
         | fun doSomething(a: Int, b: Int, c: Int): Int = ...
         | doSomething(a = 1, b = 2, c = 3)
         | 
         | 7. Tuples (Scala). They're like anonymous data classes/records.
         | val t: (Int, String) = (1, "foo")         val (a, b) = t
        
           | lenkite wrote:
           | 1. Java already has succinct lambda expressions.
           | parameter               -> expression         (parameter1,
           | parameter2) -> expression         (parameter1, parameter2) ->
           | { code block }
           | 
           | and function signatures like the below might be "clunky" from
           | your point of view, but IMHO are more clear since they
           | document explicit types. (and you can navigate to their
           | javadoc)                   Blah
           | doSomething(BiFunction<String, Integer, Foo> fn)
           | 
           | 2. Conceded. There are some JEP's around this but they all
           | got rejected.
           | 
           | 3. Already covered in existing discussion. Verbosity level is
           | fine.
           | 
           | 4. Context oriented programming can easily be achieved using
           | AOP in java. But frankly is readability and maintainability
           | nightmare in any large project. I have seen
           | projects/apps/libs that used this paradigm (in several
           | languages) be re-written to explicitly designate all
           | contexts.
           | 
           | 5. Java with virtual threads now has _far better_ support for
           | async programming than Kotlin or Scala. It is now competitive
           | with Golang in async ease-of-use.
           | https://blog.rockthejvm.com/ultimate-guide-to-java-
           | virtual-t...
           | 
           | 6. _shrug_. Many popular languages have explicitly rejected
           | function named parameters. Use a struct /record if you want
           | named arguments is the usual answer.
        
             | kllrnohj wrote:
             | > Java with virtual threads now has far better support for
             | async programming than Kotlin or Scala. It is now
             | competitive with Golang in async ease-of-use.
             | 
             | Only if your problem set matches one of using threads.
             | There are other async problems that don't fit cleanly into
             | a "force it to be a blocking thread instead" model. In
             | particular those in front ends where being on a specific
             | thread at specific times is important.
             | 
             | Green threads work great for server-style async, which is
             | where go is seeing success. Then again servers are probably
             | the last major usage of OpenJDK, so copying Go's tradeoffs
             | here probably makes sense for it. But it's not
             | unambiguously "the best way to do async"
        
             | soulbadguy wrote:
             | > 5. Java with virtual threads now has far better support
             | for async programming than Kotlin or Scala. It is now
             | competitive with Golang in async ease-of-use
             | 
             | green thread/stackfull coroutine such as in go/java and
             | stackfless coroutine as in kotlin are well know solutions
             | for introducing async programming in a way that feel
             | natural to dev. They both have strength and limitation, i
             | don't think one offer "far better support for async
             | programming", and even more importantly they are not
             | mutually exclusive and can be used together depending on
             | one needs (see https://www.youtube.com/watch?v=zluKcazgkV4)
        
             | gavinray wrote:
             | > and function signatures like the below might be "clunky"
             | from your point of view, but IMHO are more clear since they
             | document explicit types. (and you can navigate to their
             | javadoc)                   Blah
             | doSomething(BiFunction<String, Integer, Foo> fn)
             | 
             | What happens when you want to pass a function of arity 3,
             | 4, 5 or 6?
             | 
             | Also, it's nice to be able to give identifiers to the
             | arguments:                   // In Kotlin (absurd example,
             | just to prove a point)         fun withHandler(
             | handler: (name: String, age: Int, isAdult: Boolean,
             | callback: (Int, Int, Int) -> Unit) -> Unit         ) {
             | handler("John", 25, true) { println(it, it, it) }         }
             | // In Java:         interface Handler {             void
             | handle(String name, int age, boolean isAdult, Callback
             | callback);         }              interface Callback {
             | void call(int a, int b, int c);         }
             | class JavaClass {             public static void
             | withHandler(Handler handler) {
             | handler.handle("John", 25, true, (a, b, c) -> {
             | System.out.println("a: " + a + ", b: " + b + ", c: " + c);
             | });             }         }
        
               | lenkite wrote:
               | It is possible to create custom functional interfaces in
               | Java. One is not restricted to what is provided in the
               | stdlib.                   @FunctionalInterface
               | public interface VargsFunction<T,R> {           R
               | apply(T...  t);         }
               | @FunctionalInterface         public interface
               | QuadFunction<T, U, V, W, R> {           public R apply(T
               | t, U u, V v, W w);         }
               | 
               | Of-course Java is nowhere as flexible as C++ in this
               | regard which has variadic templates, template parameter
               | packs and template-template parameters. Well, you can do
               | this with currying if one is feeling lazy, but obviously
               | not recommended:                  Function<One,
               | Function<Two, Function<Three, Function<Four,
               | Function<Five, Six>>>>> func = a -> b -> c -> d -> e ->
               | 'z';
               | 
               | The second point (named parameters) is one that several
               | language designer greybeards (not just Java) have taken a
               | deliberate design decision against for varying reasons.
               | Use builders/records/structs is the usual advice given
               | here anytime you ask them this question.
        
           | hamandcheese wrote:
           | Isn't point (5) kind of moot with virtual threads?
           | 
           | I think golang shows that a synchronous, imperative paradigm
           | wins the masses.
           | 
           | I'm not too brushed up with Kotlin suspend, but does it
           | suffer from the classic "function coloring" problem that
           | plagues other solutions? I've dabbled in functional effect
           | systems in Scala, for example. I really enjoy them, but my
           | coworkers sure don't when they realize that to perform some
           | IO in a new place they will have to update a huge stack of
           | type signatures to be wrapped in an IO monad. Async/await in
           | javascript has the same issue, though the syntax is a bit
           | friendlier.
           | 
           | My great hope for virtual threads in Java is that we can
           | bring great IO performance and scalability, on par with
           | golang, without retraining devs.
        
             | gavinray wrote:
             | Yeah, Kotlin does have the colored-function problem, in the
             | same way that Node/JS has.
             | 
             | Loom and Virtual Threads are one area I'm not as familiar
             | with.
             | 
             | What I do know is that you can configure virtual threads as
             | the coroutine dispatcher for Kotlin coroutines, and in a
             | recent video Roman Elizarov talked about how the default
             | "Dispatchers.IO" could theoretically leverage VT's in some
             | future JDK.
             | 
             | https://youtu.be/zluKcazgkV4?t=2518
        
             | soulbadguy wrote:
             | > I think golang shows that a synchronous, imperative
             | paradigm wins the masses.
             | 
             | I am not sure go shows that... Attributed the "poplarity"of
             | go solely to its async model is kind of a leap.
             | 
             | > I'm not too brushed up with Kotlin suspend, but does it
             | suffer from the classic "function coloring" problem
             | 
             | I never quite understand why function coloring is referred
             | to as a problem. Including the async/non-async nature of a
             | function in its signature is as natural as using any other
             | monadic types as a return, such as Optional for example.
             | 
             | > My great hope for virtual threads in Java is that we can
             | bring great IO performance and scalability, on par with
             | golang, without retraining devs.
             | 
             | I think that's sometime a conflation that happens : virtual
             | thread usually ease scalability at the the cost of
             | performance.
        
           | tejinderss wrote:
           | How about typescript? It supports union types, lambda
           | functions and type aliases. Would you consider it on par with
           | Kotlin?
        
             | gavinray wrote:
             | I adore TypeScript -- JS/TS has been my primary language
             | for most of my career.
             | 
             | Kotlin has a few things that TS doesn't have but overall,
             | I'd rate it very similarly. I probably enjoy writing TS a
             | bit more than Kotlin.
             | 
             | EDIT: TS also has Opaque Types, sort of. They call them
             | "brand types" or other names, it looks like this:
             | declare const opaque: unique symbol         declare type
             | Opaque<T, K extends string> = T & { readonly [opaque]: K }
             | type Email = Opaque<string, 'Email'>              function
             | mkEmail(email: string): Email { return email as Email }
             | function takesEmail(email: Email) { console.log(email) }
             | const email = mkEmail('foo@bar.com');
             | takesEmail(email);         takesEmail('wrong'); // error
        
               | tejinderss wrote:
               | Yeah i think extension functions and operator overloading
               | are biggest things in kotlin that are missing in
               | typescript. Its very easy to add functions to existing
               | types and chain the method calls in kotlin.
               | 
               | Edit: didnt know about the brand types in typescript,
               | TIL, thanks for the example.
        
         | mhfu wrote:
         | Don't know anything about Scala. Kotlin has null safety and a
         | bit cleaner syntax, but other than that, I don't see too much
         | advantage over Java for backend. In Android, Java is still
         | lagging behind a lot. Also, Jetpack Compose, a declarative UI
         | framework is Kotlin only. Kotlin is also working on wasm (so is
         | Java I think, but Kotlin has working examples with wasm GC) and
         | Jetpack Compose is going multiplatform, including wasm. This
         | video has some examples in description
         | https://youtu.be/oIbX7nrSTPQ
        
           | kaba0 wrote:
           | There is teavm and cheerpj which can already execute java (or
           | any jvm class file) in js or wasm.
        
         | matsemann wrote:
         | The stdlib of kotlin with immutable types, lots of good
         | extension functions on for instance lists etc is hard to beat.
         | Especially with the nice lambda syntax it makes it a joy to
         | write functional code compared to streams and having to call
         | separate functions by wrapping instead of chaining.
         | 
         | Operator overloading can be misused, but for certain things it
         | makes stuff much prettier as well.
        
           | AlexITC wrote:
           | Scala stdlib is considerably better than the one from Kotlin,
           | one detail I dislike about Kotlin collections is that `map`
           | invocations always result in a List.
        
           | jbellis wrote:
           | Did kotlin ever add an equivalent of parallel streams?
        
         | eeperson wrote:
         | The major things from Scala that I find useful are:
         | 
         | - higher kinded types
         | 
         | - null in types
         | 
         | - for comprehensions
         | 
         | - macros
         | 
         | - opaque types
         | 
         | - implicits/type classes
         | 
         | - persistent immutable collections
         | 
         | - EDIT named & default params
        
         | re-thc wrote:
         | > what advantages do Kotlin and Scala bring
         | 
         | That it's not Java. It's a huge thing with some developers not
         | wanting to touch Java for <insert reason> but would be fine
         | with Kotlin or Scala.
        
           | pjmlp wrote:
           | Then better go elsewhere, rather than work on Java Virtual
           | Machine.
           | 
           | It is like using UNIX and not wanting to understand, touch,
           | C.
        
         | jdm2212 wrote:
         | They're really great for making sure Java devs will absolutely
         | never contribute to your project.
         | 
         | (I say this as a Java dev who occasionally gets tempted to try
         | to help out in repos that are Kotlin/Scala, and gives up very
         | quickly.)
        
           | the_overseer wrote:
           | Is this supposed to be a good thing or a bad thing?
        
             | hamandcheese wrote:
             | Double edged sword. Spring devs: stay far, far away from
             | me.
        
             | jdm2212 wrote:
             | Mostly a bad thing, at companies with lots and lots of Java
             | devs.
        
           | soulbadguy wrote:
           | Isn't that true for any other language as well ?
        
             | jdm2212 wrote:
             | I'm happy to take a crack at Go and C++, but coming from
             | Java it is totally impossible to decipher wtf is going on
             | in Scala. Kotlin is better, but still pretty awful.
             | 
             | Also, devs who use Go and C++ usually have a good reason
             | (embedded systems and such), but Kotlin and Scala use seems
             | to be motivated mostly by vaguely hipster-y annoyance with
             | Java 8. And, like, sure, if you are annoyed by Java 8 and
             | then use a language designed to have nothing in common with
             | Java 8 except that it can import Java libraries and run in
             | the JVM... well, it's gonna be a pain in the butt for your
             | colleagues who do Java all day. And some of them aren't
             | going to make the effort to work with it.
        
         | piokoch wrote:
         | Kotlin provides modern features in the Android development Java
         | land stuck on the ancient Java 6.
         | 
         | Scala was an academic experiment on how to match nicely object
         | oriented world with functional programing paradigm that got
         | some hype because Java development was crawling like a snail. I
         | am not sure if this experiment was successful after all,
         | though.
        
           | wasyl wrote:
           | > Kotlin provides modern features in the Android development
           | Java land stuck on the ancient Java 6.
           | 
           | These days you can use Java 8 features with no issues, and
           | Kotlin isn't really solving the fundamental problem of
           | runtime version on target devices -- it's just spitting out
           | Java 8 bytecode by default. Android build system already
           | _desugars_ newer Java language features for older runtimes,
           | and they could do the same thing for all the new fancy
           | features. I guess they choose not to because Kotlin is
           | already there.
           | 
           | That said, I do believe Kotlin is still more concise, has
           | better nullability handling, and upcoming exciting features
           | of its own like compiler plugins
        
           | kllrnohj wrote:
           | Android isn't stuck on Java 6 and many of the changes are in
           | the compiler not the runtime anyway.
        
           | spockz wrote:
           | With Scala 3 a lot of the idiosyncrasies of scala 1/2 got
           | fixed. (If you can get over some naming.) What is mostly
           | brings for me is showing that composition beats inheritance
           | and that classic OO trying to shove the real world in an
           | inheritance tree is not the way to go.
           | 
           | Also, it got Java to move up development, together with the
           | move to cloudnative.
           | 
           | From a language enthousiast point of view I'm still curious
           | why Kotlin and now these features in Java get so much
           | traction while most have been available for 20 years in
           | Scala. Was it marketing? Was it people? Was it symbol soup?
           | Who knows?
        
             | vbezhenar wrote:
             | As a Java developer for 15 years and as a language
             | enthusiast myself I'm curious as well. Because I definitely
             | don't see many places where I would use pattern matching in
             | my code or even records. Recently I wrote like 10k LoC and
             | I used record once: in test code to return pair of values.
             | 
             | May be I'll replace some `if`-s with pattern matching, just
             | like I use `instanceof` pattern matching today, but that's
             | absolutely minor thing which is hardly worth mentioning.
             | 
             | I would even dare to say that lambdas and `var`-s for me
             | are questionable features.
             | 
             | Actually as I grow older, I appreciate ascetic nature of Go
             | and sometimes I think that using Java 1.4 might actually be
             | preferable for many codebases.
             | 
             | I understand that for code which manipulates trees like
             | compilers with their ASTs, pattern matching might be god
             | send. The thing is... 99.99% of developers don't write this
             | code, so optimizing language for it is strange goal.
             | 
             | Sometimes I think that some language features are driven by
             | hype, even with Java.
             | 
             | I always happy about runtime improvements, though. And Java
             | delivers in that front, so I can tolerate pattern matching
             | and streams if I can get virtual threads and struct values.
        
               | soulbadguy wrote:
               | > Because I definitely don't see many places where I
               | would use pattern matching in my code or even records.
               | Recently I wrote like 10k LoC and I used record once: in
               | test code to return pair of values.
               | 
               | Without knowing your application domain or seeing the
               | code, it's hard to guess why. But one reason is that
               | pattern matching and union/algebraic type tend to go
               | hands to hands. So depending on how your data domain was
               | modeled, it is normal that you don't find yourself not
               | needing to pattern match as much.
               | 
               | In general,it's normal to find one self "not needing" a
               | feature that one is not used to, professional are very
               | good at structuring things is a way that work best with
               | the current toolings.
               | 
               | > I understand that for code which manipulates trees like
               | compilers with their ASTs, pattern matching might be god
               | send
               | 
               | Very true, but i can assure you , pattern matching
               | (combined with record and ADT) are very useful tools in
               | general computation as well.
        
             | zdragnar wrote:
             | As someone who is only tangentially familiar with jvm
             | functional languages and hasn't written java in years,
             | "symbol soup" almost certainly has a lot of the blame.
             | 
             | Java is simple. There were few operators, and really only
             | one way to call a function. All function calls require
             | parentheses. Conventions are available for pretty much any
             | problem you can think of.
             | 
             | In functional land, you don't need to bother with calling a
             | function a factory, or adapter, or whatever overwrought GoF
             | pattern was maladapted. Despite being verbose and
             | convoluted, Java was all basically the same things- classes
             | and methods and a few annotations, and easy to Google
             | concepts.
             | 
             | Enter symbol soup. Now, your conventions aren't named, you
             | have to recognize them from experience. That creates
             | writer's anxiety- even if I understand what I am reading,
             | if I need to start from scratch I don't know that I'm
             | organizing things right. There are multiple symbols that
             | apply, combine or call functions, googling symbols is hard,
             | asking questions is hard in meat space without a screen to
             | show the unfamiliar syntax, and that's all table stakes
             | before you get into understanding performance implications,
             | code organization, maintainability, etc.
             | 
             | If I, hypothetical developer, don't know these things and
             | don't have someone to hold my hand, but I DO know java,
             | what's the point of learning the functional language?
             | 
             | This is the same problem F# had. Over time, C# kept getting
             | all the good bits from F# without the baggage. Java has
             | taken the longer road to get there, but today, if I were to
             | pick one, the value proposition of the functional language
             | appears to be on a trajectory of disappearing.
        
               | macintux wrote:
               | The problem I always have with OO (or imperative)
               | languages picking up functional features is that the
               | _constraints_ of functional languages are, to me, among
               | the biggest wins.
               | 
               | When I know that any library I invoke is literally
               | incapable of changing the data I pass to it, that's
               | tremendously freeing.
        
           | pjmlp wrote:
           | Google has been forced to update to Java 11 LTS and Android
           | 14 brings Android 17 LTS.
           | 
           | It turns out that Kotlin being able to consume Java libraries
           | is worthless if Android can only use jurassic libraries.
        
         | pjmlp wrote:
         | I rather focus on the disadvantages of additional layers to
         | debug, with their own set of libraries, and on Kotlin's case, a
         | way to sell InteliJ licences.
         | 
         | Meanwhile using Java, means using JDK out of the box with no
         | extra sugar. Pretty healthy.
        
       | soulbadguy wrote:
       | I am sure they are very good reasons for it, but even after
       | reading part of the latest valhala design document i still don't
       | quite understand by nullability and/or identity are used as key
       | differential between value types and "regular" class type. It
       | seems to make the design and integration of value object very
       | convoluted and is basically representational flatness as a mere
       | consequences instead of being the central defining factor of a
       | value object.
        
         | kaba0 wrote:
         | > basically representational flatness as a mere consequences
         | 
         | And that's exactly what they are going for, AFAIK.
         | 
         | You as a programmer should first and foremost care about the
         | semantics that you want to express in your programs. In many
         | cases it means that an object you use has and need an identity.
         | But you may find so that it doesn't make sense in a given case,
         | like a date, or a coordinate -- so you can express that it
         | doesn't have identity, allowing for more freedom on the
         | compilers part.
         | 
         | Finally, you may even say that an implicitly zeroed object
         | makes sense as a default for your class, and when this
         | particular case happens and your object can't be null, the
         | compiler can even completely inline/flatten your data. But the
         | performance improvements are generally not the goal themselves,
         | they are neat advantages you may get by restricting your
         | semantics.
        
           | soulbadguy wrote:
           | > You as a programmer should first and foremost care about
           | the semantics that you want to express in your programs.
           | 
           | I think what is semantics vs implementation details depends
           | on the task at hands. From my understanding, the need for
           | value types mainly originate from the need for precise
           | control of memory layout, In which case the representation is
           | part of the important semantic. C#/.Net seems to have a
           | simpler approach by just providing representation flatness as
           | a tool and let the developer chose what they want to do/focus
           | on.
           | 
           | > In many cases it means that an object you use has and need
           | an identity. But you may find so that it doesn't make sense
           | in a given case, like a date, or a coordinate -- so you can
           | express that it doesn't have identity, allowing for more
           | freedom on the compilers part.
           | 
           | If this is confusing it to me, the need to identity seems to
           | be a property of a specific object instance, not really a
           | property of a class/type.
           | 
           | > But the performance improvements are generally not the goal
           | themselves
           | 
           | I am not sure how true this is, the design document itself
           | reference numeral code performance as one of motivating
           | factor.
           | 
           | > when this particular case happens and your object can't be
           | null, the compiler can even completely inline/flatten your
           | data
           | 
           | As someone who have "worked" on quite of bit of
           | runtime/compilers, "compiler can" always turns out to be
           | "compiler doesn't". This idea of a compiler to auto-magically
           | deciding and optimizing data layout sound great in theory,
           | but in practice is very very hard to achieve in most
           | meaningful ways.
        
             | kaba0 wrote:
             | C# and Java have very different philosophies here - the
             | former prefers exposing the primitives to the developers at
             | the price of a simpler runtime but a more complex language,
             | while java does the opposite.
             | 
             | Of course performance is a goal, but they asked the
             | fundamental questions around the topic, and managed to boil
             | it down to something that will also solve another painpoint
             | of the language at the same time, and help heal the rift
             | between primitives and objects.
             | 
             | And your last paragraph is true in general, but the
             | explicit goal of all this is to _restrict_ the possible
             | semantics of code to enable optimizations - so in the end a
             | compiler-enforced nullable, primitive class _will_ be
             | reliably flattened.
        
       | arein3 wrote:
       | Is it too much to ask for null safety in the type system?
        
         | gavinray wrote:
         | Nope not at all, here you go:
         | 
         | https://openjdk.org/jeps/401
         | 
         | It's part of Valhalla, as a pre-requirement for heap-
         | flattening.
         | 
         | Ctrl+F for "Null-restricted type". The strawman proposal syntax
         | is "Foo!".                 When inlined, a null-restricted
         | class type should have a heap storage footprint and execution
         | time (when fully optimized) comparable to the primitive types.
         | For example, a Point!, given the class declaration above, can
         | be expected to directly occupy 128 bits in fields and array
         | components, and to avoid any allocation in stack computations.
         | A field access simply references the first or second 64 bits.
         | There are no additional pointers.
         | 
         | For a summary of current status and what it means for you as a
         | developer, I recommend the linked email here and the author's
         | comments in the thread:
         | 
         | https://www.reddit.com/r/java/comments/13xtog3/valhallas_lat...
        
           | arein3 wrote:
           | Thanks, hopefully it will be live sooner rather than later.
        
         | ArturSkowronski wrote:
         | In recent publication Brian Goetz explains why it is so complex
         | to introduce one:
         | 
         | https://mail.openjdk.org/pipermail/valhalla-spec-experts/202...
         | 
         | Great read.
         | 
         | TLDR: It is hard to decide what the defaults should looks like,
         | so they plan to add special markers (! and ?) to allow
         | programmers to pass that detail to objects with "undefined
         | nullability" (without ! or ?).
        
       | syngrog66 wrote:
       | I refuse to believe Java has gone through 20 major revisions
       | since 1.0
       | 
       | I remember when 1.5 came out and Sun's marketing folks insisted
       | it be called Java 5. I think thats when they jumped the shark,
       | and haven't corrected course back since, versioning-wise
       | 
       | And I wonder if someone keeps track of what the proper
       | traditional Java major version should be now. I'd guess its on
       | 2.x or 3.x at best
        
         | avgcorrection wrote:
         | There is no universal standard for "major revision" so this is
         | fine.
         | 
         | The only seeming standard is that big integers are bad. ;) But
         | don't tell Chrome that.
        
         | emodendroket wrote:
         | Is there some kind of objective standard for version numbers
         | I'm not aware of? Maybe you could call only LTS versions "major
         | versions" if you wanted.
        
         | joaonmatos wrote:
         | If you keep to the standard edition platform and never used
         | internal APIs, you could argue Java never broke backwards
         | compatibility, effectively having a 1. before every version
         | number.
         | 
         | In practice, you could say that Java had only one major version
         | bump: from 8 to 9, when it closed down internal APIs with
         | Jigsaw and gave away Java EE to become Jakarta.
        
         | too_damn_fast wrote:
         | Well, they were going with 1.5, 1.8 because the 5 and 8 are
         | minor version numbers as it's all backwards compatible.
        
         | kernal wrote:
         | >I refuse to believe Java has gone through 20 major revisions
         | since 1.0
         | 
         | What's your take on Chrome and Firefox?
        
         | thfuran wrote:
         | >And I wonder if someone keeps track of what the proper
         | traditional Java major version should be now. I'd guess its on
         | 2.x or 3.x at best
         | 
         | What does that even mean?
        
           | vbezhenar wrote:
           | Before Java 5, Java used 1.x scheme for its major releases
           | (Java 1.0, 1.1, 1.2, 1.3, 1.4). Java 5 was both Java 1.5 and
           | Java 5 and was marketed as Java 5. Since then Java switched
           | to new versioning scheme. Some people apparently are salty
           | about that. I'm salty as well, I'd prefer semver, but Google
           | Chrome 114 probably made it too seductive for marketing to
           | use this crazy scheme, so here we are, with releases like
           | Java 20 which add nothing new.
        
             | gavinray wrote:
             | JDK 20 introduced the Scoped Values JEP as a preview, and
             | also had significant changes to the Panama Foreign Function
             | & Memory (FFM) preview API:
             | 
             | - Scoped Values: https://openjdk.org/jeps/429
             | 
             | - Panama FFM 2nd: https://openjdk.org/jeps/434
             | 
             | The changes in the Panama API were so drastic between 19
             | and 20 that any code you had written would no longer work.
             | Which is the point of interim releases like these.
             | 
             | I happen to have a lot of experimental Panama code that has
             | been continually evolving with these non-LTS releases since
             | the initial release.
        
               | vbezhenar wrote:
               | I think that preview features are not something that any
               | sizeable chunk of developers will use. So while
               | technically you're correct, I still consider Java 20 to
               | be pretty minor release.
        
               | gavinray wrote:
               | That's fair, and I'm inclined to agree.
               | 
               | Just wanted to point out there wasn't _really_ nothing
               | new, even if it might have been somewhat pedantic.
        
         | dexwiz wrote:
         | It's fine. If your biggest gripe with something made by a
         | corporation is its name then you will always be unhappy.
        
         | vbezhenar wrote:
         | After 8.0 then started to release very quickly. I'd say, we're
         | now with Java 10u30 by old standards (or 1.10u30 by even older
         | standards)
        
         | faangsticle wrote:
         | Sure, that's easy. The answer is 21. You don't get to write
         | versioning rules for other projects and there is no golden
         | standard.
        
       | jayd16 wrote:
       | I'm curious to see how structured concurrency feels in
       | production. I'm still leaning towards C#'s async and TPL syntax.
       | Manual context, fork and unwrap syntax might feel cumbersome. I
       | enjoy the await sugar and implicit context handling but the
       | explicit scopes solves the bugs you see in C# where the default
       | thread pool is abused.
        
         | pjmlp wrote:
         | David Fowler has tweeter threads about researching how Java and
         | Go do it, including an experimental runtime.
         | 
         | By the way, .NET already has structured concurrency via
         | Dataflow.
        
       | gavinray wrote:
       | I wrote about how Record Patterns along with Pattern Matching for
       | Switch can be used to write things like Tree-Rewrite rules in AST
       | analyzers/program optimizers efficiently if anyone is curious:
       | 
       | This is how Spark's optimizer Catalyst works in Scala
       | 
       | https://gavinray97.github.io/blog/what-good-are-record-patte...
       | 
       | Kind of wild to believe this is valid modern Java:
       | return switch (expr) {                 // x + 0 = x
       | case Add(Var(var name), Const(var value)) when value == 0 -> new
       | Var(name);
       | 
       | These two are my favorite new JDK features by miles, along with
       | Sealed Types.
        
         | speed_spread wrote:
         | It's just too bad they could not come up with an extended enum-
         | as-tagged-union syntax. Using sealed classes for that pattern
         | works but is still messy to write. It feels like writing enums
         | with classes back in JDK 1.4 days.
        
           | gavinray wrote:
           | I think "sealed interface" with implementations used by
           | "records" gets you pretty close though right? This is usually
           | what I do, something like:                   sealed interface
           | Tree {             record Leaf(int value) implements Tree {}
           | record Node(Tree left, Tree right) implements Tree {}
           | }              var tree = new Tree.Node(new Tree.Leaf(1), new
           | Tree.Leaf(2));
        
         | derefr wrote:
         | Do you know if these are just Java features, or if they're
         | backed by new JVM bytecode intrinsics to ensure that these
         | destructuring matches are able to be performed efficiently?
         | (Think e.g. Erlang's recent "fused checks", where it can figure
         | out whether something is an integer _and_ whether it 's non-
         | negative using a single abstract-machine instruction.)
         | 
         | That is, for languages that already have features like this
         | (e.g. Scala), will those languages be getting any benefits as a
         | byproduct of Java getting these features?
        
           | fweimer wrote:
           | The implementation uses invokedynamic (which has been
           | available for ages) and dispatches to
           | java.lang.runtime.SwitchBootstraps#typeSwitch(...):
           | 
           | https://docs.oracle.com/en/java/javase/20/docs/api/java.base.
           | .....)
           | 
           | The concrete implementation in doTypeSwitch currently says
           | "Dumbest possible strategy":
           | 
           | https://github.com/openjdk/jdk/blob/master/src/java.base/sha.
           | ..
           | 
           | There is no @IntrinsicCandidate, so I don't expect Hotspot to
           | special-case any of this yet. The machinery described so far
           | merely computes an array index, and there is a subsequent
           | lookupswitch opcode that selects the appropriate case body to
           | run.
           | 
           | I'd be somewhat surprised if Hotspot could unroll the
           | checking loop and eliminate the subsequent switch. So the
           | Java implementation looks rather bad from a performance point
           | of view (but it's obviously designed for compact bytecode and
           | future optimization). Scala could certainly do the same (the
           | magic of invokedynamic is that it's not magic), and probably
           | much better in many cases, even on current Hotspot.
        
             | gavinray wrote:
             | FWIW, there's an open PR and discussion around the code for
             | this:
             | 
             | https://github.com/openjdk/jdk/pull/9779
        
               | fweimer wrote:
               | Haha, it's already merged. I should have run "git pull"
               | before writing my comment. The "Dumbest possible
               | strategy" comment is already gone, and appropriately so.
               | 
               | This is one reason why invokedynamic is so interesting:
               | it is possible to switch implementations without
               | recompiling everything.
        
           | gavinray wrote:
           | If you want a deep-dive into the bytecode, there's a great
           | article at:
           | 
           | https://medium.com/@nataliiadziubenko/java-20-pattern-
           | matchi...
           | 
           | The tl;dr = no new intrinsics (for now), it uses table-
           | switches and invokedynamic
        
           | PhilipRoman wrote:
           | I don't think you need any byte code intrinsics for pattern
           | matching. Special cases aside, there is no generic efficient
           | way to describe them. Java byte code is badly designed anyway
           | so it's up to the VM compiler to do the heavy lifting.
        
             | whartung wrote:
             | This is actually a core concept of the Java runtime. The
             | compilers and what not "know" about idiomatic Java. The
             | trivial example is things like the getter/setter pattern so
             | prevalent in Java.
             | 
             | But the compiler doesn't treat them as anything special,
             | it's just a method. But the runtime is well aware of this
             | pattern, and what the resulting, straightforward byte code
             | looks like, and can make optimization decisions from there.
             | 
             | So where, perhaps, you may want try and write "clever" code
             | to bend the compiler to your will, Java promotes "just
             | write Java, no reason for the code to be tricky, let the
             | compiler and VM implementations be tricky".
        
               | avgcorrection wrote:
               | I think getters/setters are more tricky than just reading
               | and writing the fields.
               | 
               | But all sorts of libraries except get/set so we often end
               | up generating them.
        
             | barrkel wrote:
             | I don't think it's that badly designed. JVM bytecode is not
             | much more than AST serialization, a post-order traversal of
             | expression trees. It's designed for verification - every
             | control flow needs the same typed stack - rather than speed
             | of interpretation, though it's easy to write an
             | interpreter. It's zipped, so it doesn't need to be
             | optimized for space.
             | 
             | I didn't like how it did exceptions, that seemed a bit too
             | much like its own little mini VM. JSR/RET etc, return
             | addresses on the operand stack. But that's gone now.
        
       | mooreds wrote:
       | I think the site is currently experiencing the hug of death, but
       | doesn't have an archive.is link :( .
        
         | idlewords wrote:
         | It amazes me how many people still can't configure a webserver
         | in 2023 to not fall down under a few queries/second load
         | serving up a textfile.
        
           | hn_go_brrrrr wrote:
           | Is the HN hug of death truly only single digit QPS?
        
             | idlewords wrote:
             | That's been my experience. But even the tiniest pizzabox
             | server should have no trouble at 40+ qps.
        
             | mooreds wrote:
             | I've had posts on the front page of HN (#1 or #2). That
             | generated about 20k visits.
             | 
             | Assuming:
             | 
             | * 1 page/visit, which is the modal value based on my
             | analytics
             | 
             | * the period where it is on the front page is 6 hours (I
             | don't know this, but I could if I could be bothered to go
             | back and look; I don't have granularity down to the minute,
             | though)
             | 
             | That is 20000 requests/(6 _60_ 60), which rounds to 1
             | request/second.
             | 
             | Of course, there are all the other assets (JS, images, etc)
             | that you need to account for as well. And it might spike to
             | higher.
        
               | MBCook wrote:
               | That assumes the hits are evenly distributed.
               | 
               | I think it's more likely that there's a big flood at
               | first and then it drops off towards a low number.
        
               | iudqnolq wrote:
               | I think that's completely useless? The whole point of qps
               | is that it gives insight into spikes.
        
               | fweimer wrote:
               | If the entire page is 50 KB, it think within five
               | minutes, it can be served 20,000 times over typical
               | commercial broadband (assuming 30 Mbps net capacity)?
               | 20,000 requests can't really form a huge spike. Most
               | personal-ish sites won't be hosted on commercial
               | broadband, so they should have more bandwidth than that.
        
           | sapiogram wrote:
           | Genuine question, what is it causes websites to keel over in
           | a mild breeze like that? Surely not raw CPU, memory, or
           | network bandwidth on the machine? Is it just some arbitrary
           | limit imposed on whatever VM they are running?
        
             | re-thc wrote:
             | > Surely not raw CPU, memory, or network bandwidth on the
             | machine?
             | 
             | Why not? It gets worse and worse as we aim for more
             | abstractions and layers of tooling.
             | 
             | Where the latest hype is server rendering React in NodeJs
             | for what instead code by a static site...
        
       | xyst wrote:
       | Less than 30 minutes after a post on HN and it's not accessible.
       | Lol
        
         | mooreds wrote:
         | I had an article on the front page of HN, it melted my server
         | and I ended up using a CDN.
         | 
         | Useful lesson, but until you have massive traffic happen once,
         | it's overengineering :) .
        
           | sapiogram wrote:
           | Melt in what way? Just didn't have enough network bandwidth,
           | or something else?
        
           | ZephyrBlu wrote:
           | Setting up a CDN is free, quick and easy. It should be the
           | default if you're deploying a static site. Definitely not
           | overengineering.
        
             | mooreds wrote:
             | I didn't find it to be free, quick or easy, but then again,
             | I used Cloudfront and had Wordpress on the backend. This
             | was also a few years ago; wrote about it briefly here:
             | https://www.mooreds.com/wordpress/archives/2565
        
               | vbezhenar wrote:
               | Today I configured setup for my website (which is empty,
               | I'm more interested with configuring things than writing
               | actual stuff). All I did: set up github pages (few clicks
               | in repository settings) and set up cloudflare DNS with
               | "proxied" setting (which is default one). So now my empty
               | website vbezhenar.com is protected by mighty cloudflare
               | and it took very low effort and zero dollars to do so.
               | You might want to check it out.
        
               | mooreds wrote:
               | That's great. I have over 1000 posts on my WP blog, so
               | moving it is a bit more involved. But if you're starting
               | out today, what you suggested seems great!
        
             | hamandcheese wrote:
             | I respectfully disagree, depending on a closed source, for
             | profit megacorp should not be the default, certainly not
             | for a hobby-scale project.
        
               | ZephyrBlu wrote:
               | I'm curious why you think that.
               | 
               | From my perspective, you should do what is best for
               | yourself and your users. I think you should _definitely_
               | be leveraging things like CDNs that are low effort and
               | high impact to save yourself time and help your users.
               | 
               | Not using things that are closed source and from
               | megacorps feels like a luxury that a lot of people cannot
               | afford. Not monetarily, but in terms of time and effort.
               | When I'm working on a side project I want to remove all
               | the friction I possibly can so I stay motivated and keep
               | working on the project.
        
             | faangsticle wrote:
             | If you consider sharing the browsing habits of all of your
             | visitors with Cloudflare to be free, then yes.
        
               | ZephyrBlu wrote:
               | Use Cloudflare? I would never!
               | 
               | My blog uses a custom CDN I wrote in Assembly for maximum
               | performance.
               | 
               | I also wrote a custom browser (Guess what language) so my
               | visitors browsing habits weren't shared with Google via
               | Chrome.
               | 
               | I will go to the ends of the Earth to protect my users'
               | browsing habits.
        
               | faangsticle wrote:
               | [flagged]
        
             | avgcorrection wrote:
             | Well, all I know is that there must be a long tail of
             | websites that will never need it.
        
               | ZephyrBlu wrote:
               | Sure, but in the scenario discussed (Post hitting top of
               | HN) a CDN is like insurance.
        
         | ArturSkowronski wrote:
         | As the author, I assure you that we will be conducting a post-
         | mortem analysis for sure!
         | 
         | We experienced an astounding increase in traffic, nearly 100
         | times our usual volume
         | 
         | You can find mirror on Substack:
         | https://vived.substack.com/p/the-compact-overview-of-jdk-21s...
        
       ___________________________________________________________________
       (page generated 2023-06-11 23:00 UTC)