is going to be dropped in Scala 3, where you will need to write the following instead:
def f() = { ... }
def f(): Unit = { ... }
The goal is that Scala 2.13 and 2.14 users will be able to run a Scalafix rewrite to remove procedure syntax from their codebases automatically.
This proposal is going to be discussed in the following SIP meeting. If you feel you have something to share with us with regards to this change, feel free to comment .
I am sad with this change. I love how Scala is succinct and this will make a language bit worse (from my PoV), unnecessarily verbose heavily used syntax. I was never āconfusedā with it when I was learning Scala and I donāt see anything bad about clearly signalling with missing equality sign that the function/method doesnāt return anything.
If you feel that there is no need for 2 variants of nothing returning functions, I would prefer removal of def f(): Unit = { ... } version.
The verbosity will be felt in particular contexts; for example in scala-swing (where syntax is now already mostly rewritten) the added : Unit = may feel annoying at first. Years ago, I was in favour of procedure syntax, but now I find the benefit of more regular syntax higher.
I work a lot with STM based libraries, so naturally here you have this signature in many many methods:
def something(arg: Int)(implicit tx: Txn): Unit = ...
This is similar to plain mutable style as in Swing. Howeverā¦ I think here the implicit functions may amortise the verbosity cost of dropping procedure syntax, as you can imagine the above to become something like
def something(arg: Int): TxnU = ...
So this is just a comment not an objection against the removal of procedure syntax.
I have for a long time disliked the change, so for reference: I still dislike it.
In more detail, I find that
def foo() {
stuff_that_returns_unit()
}
provides visual clarity that the method is entirely side-effecting far better than : Unit = does; and I find the danger of def foo = { ... } actually only having side effects rather worrying. The existing way is compact and precise and unambiguous; the alternatives are at least a little worse in all regards (to varying degrees, depending on which alternative).
For me, the feature has paid for itself many times over; Iād rather drop for-comprehensions than procedure syntax.
But I understand that the syntax is more regular if everything has a return value. (People do occasionally stumble over it when learning, but Iāve seen way more stumbling over the shorthand _ in closures, and over the distinction between closures, methods, and functions. These are things we could fix, basically by dropping āconfusingā shorthand. But I donāt think we want to, because shorthand is helpful.)
For me, the scalafix side of things is basically irrelevant. Fixing my code isnāt the hard part. Reading it afterwards is.
For the record, I vehemently oppose this change. Itās a purely gratuitous change that is going to cause all kinds of migration hell for no very good reason. Itās simply too late in the evolution of the language to make this kind of change. Iām all for radical change, and for fixing past design flaws, if the upside is compelling enough. This is squarely not in that camp. Deprecate procedure syntax if you insist, but continue to support it for the foreseeable future.
This would have probably been the less contentious change if I had guessed, but thatās clearly not the case! Thereās nothing much I can add, but in my experience newcomers to Scala have felt quite confused about this syntax and about two ways of doing the same thing. Honestly, I think removing procedure syntax eases readability because people need to have less things in mind when parsing the code visually. Maybe they get used at the end, but itās a price all developers, not only the seasoned ones but the beginners too, need to pay.
You can argue for or against it, but objectively speaking this wonāt cause any migration hell. People will have rewrites at their disposal to migrate not only this but other changes too, so this will be automatically fixed for them.
Itās perhaps just because only the one against are talking now
Iām totally for that change. In my experience (long with scala, thatās more than one decade of it), the cognitive weight of having several syntax for almost the same thing but not exactly is very high, higher than ascetic. Moreover, itās refactoring unfriendly, and forbid some lāinter rules (āalways add return type for pub methodā, for example).
So YES PLEASE, remove it and be done with one less language quirk.
Iām kind of mystified by the vehemence. I mean, this is the smallest of all the proposed changes, and the most purely mechanical ā itās the one I expect can be 100% covered by Scalafix, with no manual effort required and no obvious edge cases. Itās likely the easiest of all the changes to migrate.
And itās not gratuitous ā Iāve dealt with a fair number of folks, especially newer ones, who have wound up with wildly mysterious bugs because they forgot the = as a pure typo, and lost hours confused because they didnāt realize that their function was actually a procedure and was returning Unit. If we didnāt have type inference, I might regard this as a minor detail, but as it is, if you use inference heavily (and many people do), procedure syntax is a pretty nasty accidental trap you can fall into.
Iām strongly in favor of this one. Side-effecting functions should be obvious, and an explicit : Unit ascription is much clearer than a quietly missing =. Itās time to make this change, IMOā¦
Itās perhaps just because only the one against are talking now
@jvican, @fanf has got a point here. Is it possible that in addition to this thread, scala center will release a short survey for the SIP batch, so developers can vote for/against/indifferent of the change?
May I ask how exactly is it refactoring unfriendly? Isnāt this just an issue with IDEs not supporting it properly?
Again, why? The linter rule should be fine, if a method doesnāt return anything then it canāt have a type and passes the rule. What problem is with that?
Voting is out of scope here, weāre most interested in the points in favor or against Weāll take into account the inherent bias of people commenting on the tickets, for sure
Honestly, I donāt see that as likely to have real value. Unless it was conducted very carefully, the respondents would be quite self-selecting, so youād basically get the noisiest people on both sides voting, but probably not any sort of realistic cross-section of the developer community.
(Itās easy to conduct surveys. Itās hard to conduct surveys that actually tell you anything meaningful.)
I, personally, have no issues with migrating, IDEA can do it already. I worry about the unnecessary increase of verboseness (e.g. when writing a game in Scala, most [70%?] of my methods are purely for side-effects). I donāt find argument āit is easy to migrate so we should change the languageā convincing. For example, if we would have a Scala-To-Java migration tool, is this a reason to migrate all our code to Java? I donāt believe so, I chose Scala because how expressive and terse it is, not because I want to read epic cotton-stuffed tales like in Java.
Never happened to me in described magnitude, even when I was just trying out Scala. If types donāt align, I either use an IDE to show me the types (IDEA does this in many instances on its own) or start adding types. I usually find the issue under a minuteā¦ Shouldnāt be rather recommended to beginners to annotate everything with types until they are certain how they are inferred, instead of pushing it out of language because of beginners? Or canāt be improved compiler, to show better error messages with tips mentioning possible issues like returning Unit and working with the value?
Note that thereās no need to use Unit returning functions to do side effects, and that weāre talking about adding a = between the curly brace and the result type (or parameter list) of the method. I donāt think it is a big deal.
Did you get a sense for why they had such trouble with this, as opposed to, say, forgetting yield on a for-comprehension? I have trouble imagining that people who spend hours being confused about this wonāt also spend hours being confused about all sorts of other type errors. This is one of the simplest to fix, even if you donāt use an IDE, isnāt it?
Why do you think that? Every method that returns some non-Unit value has the same form def thing(): Stuff = { ... }. You have to actually read Stuff to know that itās Stuff and not Long or Unit or whatever. You can do the other without even reading anything, purely based on local shape. = is pretty distinctive. You have to find the = anyway in order to read Stuff. If you donāt find it, you already know what you need to.
Now, I think thereās an aesthetic advantage in the regularity of all methods having a return value. After all, if you can foo _ and get something, what sense does it make to say that foo has āno return valueā?
And I suppose those who almost never write purely side-effecting code donāt even consider that the = might be missing, so they donāt train themselves to look for it.
So I grant that some may find it clearer with the change. But you also should, I think, take me at my word that : Unit = is vastly harder for me to pick out quickly than ) {. If it wasnāt actually important to me, I wouldnāt say anything. Iāve had plenty of time to notice the difference.
Please donāt ask for that. This makes side-effecting code really hard to pick out, and itās incredibly important to know when something is side-effecting. Itās hard enough to keep side-effects straight even when itās trivial to pick out visually which things are purely side-effecting.
def foo() { .. }
to
def foo(): Unit = { ... }
is okayāyou can still tell whatās going on.
def foo () = { ... }
is just asking for confusion.
Letās be honest here: weāre asking for eight characters with this change, not two. Maybe eight characters isnāt too much to ask, but if we want it, letās ask for the actual impact (when maintaining roughly comparable clarity).
I would agree with you, and I wouldnāt have suggested this, if he had not said he was working on a game with lots of side effects. If ā70%ā of his code is side-effects, there isnāt much benefit to annotating every function with Unit as a return typeā¦
Knowing which is the 70% and which is the 30% can be really important. For instance if bippy builds a new object as opposed to changing the existing one, you want to be really clear on which is which.