4 ms·
This JEP draft touches on an interesting tension in language design (and perhaps many other kinds of design) between a desire for rules that aren't unnecessaril
by pron 4y ago
This JEP draft touches on an interesting tension in language design (and perhaps many other kinds of design) between a desire for rules that aren't unnecessarily restrictive and a desire for rules that are easy to communicate to the user. I.e. there's value in accepting more correct programs but there's also value in easily communicating why a program is rejected, and sometimes there can be tension between the two.
- paddy_m 4y agoCan you expand on this. does this change make it easy to communicate why a program was rejected?
- lmm 4y agoThis change means that some programs won't be rejected when previously they would be.
- rustyminnow 4y agoI think this change would make it harder to explain why a program was rejected, even though it would allow a programmer more flexibility. It's easier to just say "this() must ALWAYS be called first in constructor" and everybody understands... than to try and say "you can call this() after other statements, but not in a try block and not if those statements reference the instance under construction" which will certainly allow you to do more interesting things, but also be more confusing.
- mjevans 4y agothis() and super() MUST be called during the Initialization Block, which MAY include guard / error tests and variable assignments (a list of permitted actions and types of actions is more complex).
- TylerE 4y agoThey aren’t mandatory, no? Thus must, or especially “MUST” is misleading.
- josephcsible 4y agoThis is the slightly confusing part: a call to another constructor is mandatory, but if you don't call any other constructors yourself, super() automatically gets called before your code, without you having to write it.
- mjevans 4y agoYeah, that's the confusing part. Historically that segment of code, much like version of other languages that require variable declaration only at the start of a new scope, is just implicitly at the start. There isn't a linguistic structure that separates it from more normal code that does other tasks; previously it was a compiler error.
- tsimionescu 4y agoThey may be ellided entirely if there is a superclass constructor without any parameters. In all other cases, either super(...) or this(...) MUST be called exactly once. Additionally, you can't catch Exceptions thrown by a call to super(...) or this(...) (so you can't call them inside a try{} block). Finally, you can't reference any non-static members of the "this" object except to write to write to a field. So yes, the rule is significantly more complex.
- nayuki 4y ago"this() must always be called first in the constructor" is not true! Consider the following example: Foo(long x) { ... } Foo(double y) { this(Math.round(y)); } In the second constructor, the first call is Math.round(), followed by Foo(int). I am talking about evaluation order, not lexical order. I found myself needing to work around the limitation recently: https://github.com/nayuki/PNG-library/blob/b92cedc23b1fc32d51bbc528797b9b55eba6bc17/src/io/nayuki/png/chunk/Gama.java#L36-L49 https://github.com/nayuki/PNG-library/blob/b92cedc23b1fc32d5...
- jfoutz 4y agoBuffalo buffalo buffalo Buffalo buffalo, is hard to parse because English is very expressive. And you kinda have to know words have different meaning in different context. If I explain buffalo is another word for bison, and also buffalo means coerce, I can rephrase this Bison from Buffalo coerce other Bison from Buffalo. Generally, making a language more expressive makes it harder to parse. You have to know a lot more stuff. Computer languages often have a formal spec. I think java does, but I don't think perl does. Regardless, you just have to remember that footnote on page 26 of the manual that the construct X is an option. I haven't touched java in a while, but I do remember some difficulty with parent class constructors calling methods implemented in the children, that relied on member variables that hadn't been initialized yet. I wish I could point at a concrete example, but I think it was something deep in the heart of swing (part of the jre so not changeable). I can't imagine a way this makes it easier to parse in my head as I'm reading through code, or communicate failure. but there probably are libraries that become more usable with this new syntax. It sucks because you're guaranteed super is called, the parent class can implement stuff that _has_ to happen. there's no way for me to force a subclass to call, something like pleaseInitializeAfterSuper(). and there's no way for me to do anything before super, right now. Regardless, there's no easy way out. Making the language more expressive is a damn big hammer to use though. you'd think you could use a builder to guarantee initialization, But sometimes you can't. To answer your question, no. I don't think this makes it easy to communicate why a program was rejected. it makes more programs possible though. At the cost of having to remember that footnote on page 26.
- justeleblanc 4y agoYour example isn't about expressiveness, it's about ambiguity. I don't get the relevance, to be honest.
- 8note 4y agoIs there actually a tension there? What's pushing for more possible correct programs?
- sbergot 4y agoThe tension is the following: - super() must be called first: the rule is simple but restrictive - non herited elements can be used before calling super(): the rule is more complex but less restrictive. This can lead to more complex error messages, etc
- disruptiveink 4y agoWhen the rule was made, it would not be uncommon to write Java in, say, Emacs. Nowadays it's practically guaranteed everyone writing Java will be using a fully fledged IDE (or if you did stick with Emacs, there are now packages to basically turn it into a Java IDE for all intents and purposes), so needing to remember the exact rule as you type is far less of a concern, as you get instant feedback vs feedback 10 minutes down the line when you try to compile your code.