15 ms·
Pet peeve warning. I'd like to propose a very simple JEP for JDK22: Let me omit the useless {} at the end of a record declaration. I get that records are tech
by xg15 4y ago
Pet peeve warning.
I'd like to propose a very simple JEP for JDK22: Let me omit the useless {} at the end of a record declaration.
I get that records are technically classes and that sometimes, you want to add helper methods, additional constructors, etc. But the canonical - and most common - usecase for records is a dumb immutable data structure, and for that you shouldn't need anything except the fields and generated methods. That's the whole idea behind them.
I always found it strange that Java has you write an awkward empty class block for the standard usecase here, while reserving the more natural syntax for exotic uses.
- krzyk 4y agoDo you really think they just forget about it? It has a purpose: https://mail.openjdk.org/pipermail/amber-dev/2020-April/005899.html https://mail.openjdk.org/pipermail/amber-dev/2020-April/0058...
- imoverclocked 4y agoThat’s the fun thing about backward compatibility. You can never clean up technically supported things that were never intended. It would be cool if we could have some kind of pragma or alternate syntax (file extension?) that gets rid of these unwanted ambiguities every decade or so. How to do that while avoiding the whole “Perl 6” can of worms might be the hard part though.
- KptMarchewa 4y agoRust editions? They work on per crate, rather than per file level though.
- pron 4y agoIn Java you set the language version per source file, and there are occasional and uncommon source incompatibilities, but it's still not worth it to introduce a common incompatibility (which isn't really the case here, anyway).
- KptMarchewa 4y agoThey still all compile to some set bytecode version, right?
- pron 4y agoThe target bytecode/standard library version can also be specified on a per-file basis (we have both -source and -target options). But while the VM can load a classfile of any version since the beginning of time, the javac compiler supports only a certain number of versions back in terms of source version and target version (e.g. you can't use a JDK 19 compiler to target JDK 7, but you can ask for the same language, API, and bytecode level as 15).
- nativecoinc 4y agoPerl 5 has that. Perl 5 seems to have all these annoying boilerplate lines that you need to add to every file in order to get “Perl The Good Parts”. But I think (I read) that they managed to boil it down to just one line.
- javier2 4y agoThese things are what I love the most about JEPs. Someone already discussed it.
- xg15 4y agoThanks for digging out that thread, that really gives some insight! I still disagree though. First, there is precedent with interfaces and abstract methods, which also leave out the method body and terminate with a semicolon. Second, the point here is that you almost always leave the body of a record empty, while you rarely do so for a class or method. They are worried that if you use arcane constructs like non-static initializers, the syntax might become confusing - but are fine if you have clutter in the common case. That seems backwards to me. Edit: You can construct the exact same confusing situation that the thread warns against already today, with abstract methods: public abstract void foo(); { System.out.print("I don't have anything to do with foo!"); } Somehow we still lived.
- pron 4y ago> You can construct the exact same confusing situation that the thread warns against already today, with abstract methods The email exchange didn't talk about that kind of confusion; in fact, it said `;` was an option. It just said that saving one or two keystrokes isn't worth it to break the rule that type declarations end in `}` while statements end in `;`. > there is precedent with interfaces and abstract methods, which also leave out the method body and terminate with a semicolon. Abstract methods aren't type declarations and they have no body. Also, they've been in Java since day one. It's conceivable that down the line, people will be so used to records that we'll allow `;` to terminate the definition. It's just that we've gone down from a page of code to one line, and adding another rule to save one character isn't worth it at this time.
- xg15 4y agoFirst of all, thanks a lot for the reply. I didn't expect to get an answer by the actual authors of the feature :) I think it's not really about the keystrokes (though { } is harder to type on my keyboard than ; ) but more that this technically opens a new class block, which gets treated as such by build tools, IDEs, etc. E.g. formatters want to put the braces on different lines by default and are generally tuned to put class blocks front and center - because with all the other occurrences of class blocks, that's the sensible thing to do. With records, it just undoes the neat "just one line" property. Yes, you can add custom formatting rules to stop that, but that's additional effort - you also have to ensure everyone uses the new formatting, etc. It's also more cognitive effort to parse the code: Imagine the GROUP BY clause were mandatory in SQL and if you didn't want to use grouping in your query, you'd have to write something like "GROUP BY 1". Certainly doable but makes queries harder to read. > type declarations end in `}` while statements end in `;`. That rule already has lots of exceptions, e.g. methods are not type declarations (like you said) and neither are initializers. Nevertheless, both use braces and leave out the ; at the end.
- adrianmsmith 4y agoThere is plenty of precedent for using ; instead of { } if the { } is empty, e.g. interface methods, or "while (foo());"
- DeathArrow 4y agoIn C# you can declare a record like a method body.
- deleted 4y ago[deleted]
- bcrosby95 4y ago> I'd like to propose a very simple JEP for JDK22: Let me omit the useless {} at the end of a record declaration. Meh. Pet peeve warning: I hate this. Sneaking in stuff like this that might save 1 or 2 characters every hundred or thousands of lines is just frustrating. If I'm regularly discovering cute one-off things like this in a language I work in then I'm gonna hate the language. And unsurprisingly, I hate most modern languages.
- capableweb 4y agoUnless your doing mostly lisp programming, it does sound like you hate most languages (which to be honest, is the position I'm in so wouldn't surprise me) To turn it around, what languages do you love?
- bcrosby95 4y agoClojure is my favorite. I also rather enjoy Elixir - it has elisions like this, but there tends to be deeper fundamental underpinnings as to why it works, why it was included, and it's more broadly applicable. So rather than memorizing minutia you can understand those underpinnings. Once I got past some of the weird syntax rules of Erlang, I really liked it. It was actually the first non-C-like language I "got". I also somewhat enjoy Golang. I don't think baking concurrency into the actual language was necessary to get the ergonomics it provides (repeating a mistake Java made), but overall it's better than most others. I think Java does an OK job of not being too susceptible to this. For people that want it there's always Kotlin, but I'm happier not using it. The evolution of Java seems to have a broader logic behind it, and they seem to be adding things with an eye towards the sum being greater than the individual parts. Of course, for work, I'll use whatever is necessary for the project. Which is currently C# because we're doing stuff with Unity.
- illiarian 4y agoMy pet peeve is that all properties could be in the class body, and then both classes and records could enjoy object initialisation a la C# if the committees that be ever wanted to add any useful ergonomics to the language. Alas.
- adrianmsmith 4y agoI don't understand the syntax for records at all. Pretty much every Java codebase is going to have "POJOs" already e.g. a class with a few fields and getFoo() methods, after all that's why they introduced records in the first place. If they'd had the attributes and the methods together inside {} like a normal class, and if they'd called the getters according to the naming convention which has established itself pretty much as a constant over the last 20 years, you could upgrade your old POJOs to records pretty much by just replacing "class" with "record". Come to think of it I don't really understand why they had getters at all. Just go with a .foo attribute syntax. I can't imagine if I define a record and start overriding the foo() getter to do something other than returning foo I'm going to have a good time come PR time ... I've certainly never seen code that does this.
- rovolo 4y agoThe difference between getters (or properties) and attributes (or fields) is that getters are a real function and attribute access does not use a function. The attribute access is less work because you don't have to do a method dispatch to get the value. (At least historically; the method dispatch may be optimized out now for basic getters.) Most of the time your getters will just return the attribute, but there are situations where you don't have an attribute backing your property: 1) You're renaming the field, and you can't update all uses at once. You can create a synthetic property with the old name which delegates to the new name. 2) You want to lazily compute the property only when requested. 3) You want to perform a side-effect every time the field is accessed