This comment is not about text blocks as such but the write up by the author. (Brian Goetz... If you are here, when do we see the next edition of the book, please?).
It is not simply 'here's a new language feature'. I find it quite informative regarding what, why, how and why not etc. His articles explain what went into the decision making. Something on the lines of discussions in Effective Java by Joshua Bloch.
This is a nice feature to have, no doubt, but won't make much difference for an IntelliJ user. What I am most eagerly waiting for is Loom, that will bring fibers to the JVM, and make the arguments in favour of server side JVM even more stronger.
I really like Kotlin, but text blocks were never the pain point for me in Java. The best thing Kotlin brings to the table is explicit nullability, which makes it so much easier to reason what can be null or not.
Loom and Kotlin coroutines are not the same though. Loom will bring real fibres to the JVM, which maybe Kotlin coroutines can use. Kotlin coroutines should also benefit from Loom.
So this is a long overdue QoL feature but the whole whitespace elision thing is unwelcome and unnecessary (IMHO). What's wrong with What You See Is What You Get? This is a perfect example of added complexity to solve a complete non-problem just based on probably the unsubstantiated aesthetic view of a handful of key people. Stop. Just... stop.
Even stripping trailing whitespace is... risky. Why is the language trying to decide what whitespace is significant? Or even trying to divine the mind of the developer at all?
I didn't realize there was a raw string proposal in Java 12 using backticks (bleh). By now I'm pretty used to languages that use double-quotes for interpreted strings (including escape sequences, at a minimum) and single-quotes for raw strings. This is an incredibly useful feature. Of course, Java uses single-quotes for character literals so that's out, otherwise I'd like to see """ for interpreted and ''' for raw.
Anyway, let me point out just one reason why this is terrible: source control. Consider:
It's only one line change but you have in fact changed what the previous lines do.
And of course (which the article mentions).... tabs!
I really want the option of pasting text into a block like this and knowing that's what I'll get. I don't want to process it usually (eg escaping characters).
> This is a perfect example of added complexity to solve a complete non-problem just based on probably the unsubstantiated aesthetic view of a handful of key people. Stop. Just... stop.
This type of remark is the height of arrogance. The whole process of designing text blocks was in the open. It was a preview feature for two releases (three if you count the raw string proposal in JDK 12) and thousands of people gave their feedback what they wanted to be changed. That your preferred version wasn't chosen is not the result of "the unsubstantiated aesthetic view of a handful of key people", but of this process.
Python has the textwrap[1] module in the standard library. Calling “textwrap.dedent()” on the docstring (multiline string) will strip white space to the least-indented line inside the text.
I’m personally a fan of having an easily-accessible method to call. That way you get indented text blocks and no “magic” formatting (at least, you explicitly opt-in to the magic formatting).
Agreed that the whitespace elision is overly complex and too prescriptive for a small issue. Either whitespace is important or not; if not it doesn't matter so there should be no special handling, and if it does - the special handling is very confusing.
Scala has stripMargin, integrated into IntelliJ to explicitly indicate how to dedent the text block. Kotlin has trimIndent.
Anything that takes this long to explain should not be a core language feature.
> To disentangle the incidental and essential indentation, we can imagine drawing the smallest possible rectangle around the XML snippet that contains the entire snippet, and treating the contents of this rectangle as a two-dimensional block of text. This "magic rectangle" is the contents of the text block, and reflects the relative indentation between the lines of the block but ignores any indentation that is an artifact of how the program is indented.
Well, I'll withhold judgement somewhat until I eventually use this feature for a little while, but based on the description this is simply too complex, which is disappointing. Who exactly was asking for the "magical rectangle" approach, anyway? Or incidental vs essential indentation? They did too much. And given how long people have been waiting for simple multi-line strings, and how many other languages already have them, I'm not sure how this got messed up.
> Avoid mixing spaces and tabs in the indentation of a text block
This has some implications. For example, I can imagine someone editing a text block and inadvertently using a different indentation type (tabs/spaces) from the other existing lines, which would then change their program in a non-obvious way. I'm myself an author of a programming language with a non-standard approach to whitespace (called Muon), so this is a topic I've thought about quite a bit. Interesting that the Java team considers this an acceptable tradeoff. I'm looking forward to seeing how this plays out in practice as a data point.
I wish that's how C# handled it! There are verbatim string literals that support newlines, but in practice, most of the time I see people stick to regular string concatenation because it ruins code indentation/alignment. That's how Rider chooses to refactor code when you insert a newline as well. Multi-line verbatim strings begin to get useful around the point where you should be probably loading your text from some resource instead of embedding it in the source.
There's plenty of contexts where the extra indentation doesn't matter, though. And C#'s verbatim strings, at least when it comes to multiple lines, have the benefit of being extremely predictable in what ends up in the string (everything, including whitespace). They also have other uses that Java doesn't even address, like not interpreting escape sequences inside the string.
I'm not sure you can really compare them. They're two different features with fairly different uses, it's just that one or two of those uses somewhat overlap.
They're comparable in the sense that I'm guessing C# is unlikely to get yet another string declaration syntax, so we're stuck with what we've got. Regarding predictability I definitely agree, but good syntax highlighting would help with that.
FWIW the Java snippet seems to be a syntax error instead, the JEP explicitly defines the opening delimiter as three double quotes, any amount of whitespace, and a line terminator.
The closing delimiter can, however, be on the same line as the final content (in order to suppress the trailing newline for instance).
> This is great, because it doesn't make leading whitespace significant on the lines which the text block spans.
I think you might want to go and reread the article, they are using "determining lines" to remove leading whitespace. I think I would find this approach much more readable than Cs
> I much prefer Cs solution to this problem; you can write multiple literals in sequence and they will be concatenated:
Python also allows that.
The semantics are completely different and not at all incompatible (even though Java doesn't support implicit concatenation of sibling literals), string blocks means you don't have to bother with explicit newlines and are way more convenient for long blocks of embedded text, especially when newlines are significant and frequent (e.g. wrapped paragraphs).
Java also seems to be getting a slightly more flexible version of Swift's processing, so it will automatically dedent based on the indentation of the line containing the trailing delimiter, or the least indented line of content within the block. Meaning you can write
text = """
hello
world"""
and get "hello\nworld". Though it is apparently forbidden to have non-whitespace content on the same line as the opening delimiter:
> The opening delimiter is a sequence of three double quote characters (""") followed by zero or more white spaces followed by a line terminator.
Read the article again. Java wouldn’t need to be aligned like your python example at all. You can align it up nice and neat with world aligned with hello.
About 25% of the way through the article they address this with an example of XML in a text block. You can have the text justified with the level of indentation where you declared it, and not have that indentation carry over into the string. Did you read that part?
Multiple string literals in sequence is the worst feature ever. If i had a penny for every time someone forgot a comma in a list of strings... ["foo", "bar" "buzz"]
It seems to be using a somewhat similar concept it calls "incidental white space", in order to limit the embedding of leading whitespace (unlike Python which just stores the entire triple-quoted string as-is), but is more permissive:
Text content can be indented less than the trailing delimiter, which I understand is an error in Swift
As the article says, they examined lots of languages, not just Kotlin (it would be arbitrary to confine their research to JVM languages..)
>> While Java could not adopt the Swift approach wholesale because of existing language constraints, the Java approach took as much inspiration from the good work that the Swift community did as we could -- and left room to take more in the future.
Looooong after the other languages have done it, Java comes around to doing it. Seriously, the best thing about Java is the JVM where you can choose a better language than Java to program with it and get all the benefits of the JVM.
That's like a compulsive hoarder seeing a guy buying a lawn chair and saying, oh, nice to see you finally catching up!
That the Java language is slow to evolve while the Java platform evolves quickly has been one of the central strategies of Java since inception. In fact, James Gosling wrote back in 1997 how Java should only adopt language features loooong after they've been tried in other languages. It's worked very, very well. There's obviously a portion of users (<10%) who prefer a faster-moving, feature-rich language, and they have good options on the Java platform, but the Java language philosophy has been more attractive to a much larger group of developers.
What is more interesting is not which features Java has chosen to adopt, but which ones it hasn't and won't: yes to lightweight threads but no to async/await; yes to pattern-matching but no to extension methods.
What you're saying is exactly what I'm saying, except we disagree what a "better language" is. I find the approach Java has taken causes people to fetishize complexity with it. It's not so much about "my language has more features than Java therefore it's better" (the hoarder reference) it's "my language is simpler than Java therefore it achieves what Java does with less in multiple dimensions." And I don't mean Scala, either. That's just piling on more of what Java is.
Nothing's wrong with that or with `String.format`. I just find it less ergonomic. Like I said, no complaints anywhere. You can just as well use `ExecutorService`s instead of async/await and all that.
Your use case doesn't have to be everyone else's.
As opposed to Kotlin or Scala, Java is a great choice for performance-sensitive applications because there's (almost) no syntactic sugar that produces throw-away objects and induces unnecessary memory pressure.
The thing I love about Java is that they continue to improve the language without:
A) Throwing the kitchen sink in and making mistakes.
B) Changing anything that already works.
There are very few languages that continue to improve and provide such long term stability. More often than not more feature full languages end up forcing me to re-test or rewrite sections of my old code base for forwards compatibility.
What about switch expressions in Java is better than Kotlin's when? I haven't personally used switch expressions in Java yet, but I've read the JEP and I don't see anything special or interesting.
The ecosystem of supporting libraries for Java is bigger than any other ecosystem. There's a mature library for every concept in existence. The Node ecosystem has a lot, but for server-side libs it still doesn't reach the coverage of Java.
Apache, for example, supports a ton of Java libraries for which there's little competition, certainly not well distributed across language ecosystems. PDFBox, Lucene, etc.
When you're in the nitty gritty of automating business processes, that sort of thing is invaluable. For CRUD-style web services, any language will do the trick.
(I say this as not a big fan of Java the language)
Python also has a similarly wide ecosystem, and does better specifically in some regions than any other language, like ML, but a different set of focus areas. It's probably the other top contender for business-process automation, but big enterprises prefer OOP/static typing for typical work.
C# probably comes close in many areas, but there's still a split between the .net core and not-core ecosystems for the long tail of libraries, and no open-source powerhouse quite like Apache in the mix.
(C/C++ might fall here somewhere too, but I don't know nearly enough about those language ecosystems to comment)
> There's a mature library for every concept in existence
If you'll forgive a light trolling: how about ahead-of-time compilation, allocating small objects on the stack, UTF-8, compile-time asserts, or SIMD support?
(Was going to include await/async, but then I remembered EA Async.)
I realise this is a little off topic, but the JVM isn't without limitations. (Or perhaps all my examples are wrong - disproof welcome!)
You can get AOT compilation with GraalVM today, allocating small objects on the stack is being worked on in Project Valhalla, compile time asserts can be implemented with annotations if you care (see @NotNull), utf-8 is available in the standard library in the StandardCharsets class.
For Async/await, I believe a much better approach is available with Quasar today or with Project Loom soon.
It's also long been possible with lesser-known proprietary solutions like Excelsior JET, so I suppose Java can claim to have a mature solution to that feature, just not a mature mainstream FOSS solution (not counting Graal).
The JVM world has Graal for AoT, FWIW. I would argue that await/async is really settling for the mediocre still. Many languages, even JVM languages offer more powerful abstractions and concepts for solving that problem. Clojure's implementation comes to mind.
I don't think you can compare V8 with the JVM. For starters, last time I checked, V8 is still single threaded, isn't it? Also it seems like future versions of JS are embracing things that make it look like they're envying Java, which seems like it's going in the wrong direction.
Compared to any language that has threads, workers are a usability nightmare and come with a million caveats.
(For example they have major limitations in Electron, which is one place where having threads would be very convenient. The current best practice is to spin up an entire new hidden browserwindow instead which is frankly insane.)
Well yeah, Microsoft developed TypeScript to resemble C#'s type system so naturally it will look a bit like Java? TS is far from being the de-facto standard though (maybe because it's centred around OOP?)
I'm not an expert on this subjectrobably the best thing the JVM has going for it is two things: many world class extremely tunable garbage collectors and acres of software written for it already. V8 has tons of software written for it but the focus is somewhat different (see Apache projects)
I'm not sure they meant any language. It sounds like they're advocating for using a non-Java language that compiles to bytecode to be run on the JVM. E.g. Kotlin, Scala, Clojure, Groovy, Jython, JRuby etc.
The goal of the JVM is "write once, run anywhere". v8 achieves the same, but for languages that compile to Javascript. E.g. Dart, Elm, Typescript, CoffeeScript, ClojureScript etc.
I think the real choice to be made is ecosystem. There are languages to suit every programming style in either camp. The availability and quality of packages in the Java ecosystem is higher IMO (use Spring and it just works).
Node has non-blocking I/O by default; it's possible to implement the same in Java, but you have to make a conscious decision to do so. Java has threads, but Node has workers. Java can have a longer startup time and is better suited for servers with high uptime, Node starts up quick and is easier to use in on demand situations etc.
I don't really know why you would, but there is RingoJS if you want to run Javascript on the JVM for some reason.
It has an unmatched combination of stability, productivity, performance, observability and ecosystem size. There are few if any platforms that offer. E.g. very few platforms, if any, offer the kind of low-overhead, always-on, in-production deep profiling that Java has [1], certainly not platforms with similar performance.
It seems strange to embed content in code in this way. You lose syntax formatting if it's structured content (HTML, JSON, etc) and also require recompiling if the content changes. I understand doing it if you're prototyping/hacking things together but it seems like a lot of effort was put into building this feature.
IntelliJ not only handles syntax formatting of code in string literals, but validates SQL against the db schema and performs identifier completion.
It's more convenient and safer to put SQL (or other text) inline next to the code that uses it rather than "some other file" that can fall out of sync.
If you use a good IDE like IntelliJ, you don't lose syntax formatting, and can edit the fragment even with autocompletion. IntelliJ is good enough to do this even right now without text blocks in Java, when let's say a HTML snippet is constructed using string concat.
It's extremely convenient to embed content which is not single line but which you'd be embedding either way e.g. text with some amont of formatting, or literal SQL queries.
It's also useful for small amounts of structured content e.g. if you don't yet need to rely on a full-blown templating system for your HTML, or to POST small amounts of static JSON or somesuch.
> You lose syntax formatting if it's structured content
Jetbrains's IDEs do content-sniffing and formatting and coloration of embedded content (though it breaks down somewhat quickly if you start doing string formatting within the block).
Records are still a preview feature in Java 14 (Apr 2020). Java 15 (Fall 2020) contains a second preview. They're usable, but you have to pass a flag to the compiler to enable them, and you run some small risk that the syntax will change (it's pretty simple, so I'd guess that won't happen).
I'm guessing that they'll land in Spring or Fall 2021, but that's just an outsider's guess. The really important cutoff is Spring 2022, when Java 18 is intended to be an LTS version.
You have to pass `--enable-preview` to BOTH compiler and runtime.
If you think about it - the feature may change significantly or be even removed - it makes sense to only support a preview features in one java version.
Providing backward compatibility for preview features is simply not intended.
Thanks for making me curious... Cool new developments, didn't touch Java in a while!
> Records are the impl of dataclasses
This is ofc backwards/reverse of any sane logic that would start with value types and after invent references (eg. in this case probably would've mean introducing a new composed-primitive type)... but then again, it's Java, at least they got the strings being immutable part right from the start.
interesting... so `inline class` would behave like `struct` in C#? Took them a while (and I'd imagine it's one reason why game engines like Unity, Godot etc. chose C#), but cool!
I don't hate Java. It was my 2nd or 3rd language, and the one I first used professionally. But O-M-G, this feature exists in most mainstream language and has for the past decade at least.
This is nuts to me how behind Java is. Is it only due to the backward compatibility? Or is there some crazy red tapping every time something is added?
Most evolution on the platform is in the VM and tooling rather than the language, and the language is conservative and slow-moving by design (it was part of the "charter" back when Java was created). This has worked very well.
OTOH, Java programmers look in astonishment at how far behind most other platforms are in GC, compilation, and observability.
It's a combination of things. Java is slow moving by the very nature of the contributors to the language and runtime favouring slow methodical advancement.
Additionally Java has a longer history than most of backwards compatible software that contributes to a higher burden of testing before making changes to the core language.
Finally there is the community itself which favours high performance and reliability and prefers where possible to make use of libraries rather than change the language or runtime itself.
That isn't to say Java isn't evolving or that the JVM itself is stagnant.
The introduction of the Java module system allowed the JRE itself to become a much lighter dependency. Things like Project Loom seek to bring Erlang-like fiber/green thread support to the JVM and will probably land in a release soon.
Also the release cadence has been changed so new releases are now landing much more frequently which is increasing the pace of development.
I'm thankful that Java hasn't become a mess like C++.
The virtual machine and stdlib continue to see innovation, while the ease of implementing JVM languages like Scala and Kotlin mean that Java can let these new languages innovate, and pick the best features when they're proven (with improved performance normally too).
You can see this with Lambdas, and now with Records and pattern matching
Java doesn't add features unless they're absolutely sure they want to support it for eternity and for something like text blocks why take the risk unless you're absolutely sure? Text blocks aren't something I see myself even using frequently.
I find these tools only work well for simple queries. For anything complicated, you spend N units of time figuring out how to make the query, then 4N units of time figuring out how to represent it in the metalanguage (often hacking around it with custom functions and operators).
They are especially bad with exotic operators like postgres' JSONB columns. I ended up ripping jooq out of an app over this.
There's an argument that they bring type safety to SQL, but Intellij actually validates your string literal SQL against the schema, so the benefit is marginal.
It is not simply 'here's a new language feature'. I find it quite informative regarding what, why, how and why not etc. His articles explain what went into the decision making. Something on the lines of discussions in Effective Java by Joshua Bloch.
His article on records: https://www.infoq.com/articles/java-14-feature-spotlight/