Imho, that's at least one option too many.
The first option is especially troubling, because we reward people who use side-effects with special, less verbose syntax, while we claim that the language nudges people toward a more value-driven style of programming.
The second option is pretty bad from a different perspective: Those who actually want to return a value, but have forgotten the equals sign fall into this trap. This comes up a lot. (We have at least a warning for that now.)
The third option is explicit and the style I think should be preferred in traits, too. (E.g. trait Foo { def foo: Unit } instead of trait Foo { def foo }, I think it's mind-boggling and invites errors that we even allow the second option.)
What about
Imho this would improve consistency of the language, remove confusing variations in style, reduce the amount of special-cases users have to learn and prevent a lot of beginner mistakes.
Better ideas, opinions, criticism?
Simon
--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
What about
- deprecating and removing option number one,
- adding a warning if a method's result type is inferred to be Unit for option number two and
- guiding users towards specifying the return type explicitly, like in option number three?
Imho this would improve consistency of the language, remove confusing variations in style, reduce the amount of special-cases users have to learn and prevent a lot of beginner mistakes.
Better ideas, opinions, criticism?
The exact opposite is annoyingly advocated by the "official" style guide
-jason
--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
— Or: Can we decide on one-true-procedure-style instead of three?
I have been focusing on beginner-level issues for the last few weeks and one large chunk of popular problems which comes up a lot is the different declaration style for procedures.
Scala has
- its own special syntax for procedures, def foo { println(1) }
- Unit-returning methods with inference, def foo = { println(1) }
- has explicit Unit-returning methods, def foo: Unit = { println(1) }
Imho, that's at least one option too many.
The first option is especially troubling, because we reward people who use side-effects with special, less verbose syntax
The second option is pretty bad from a different perspective: Those who actually want to return a value, but have forgotten the equals sign fall into this trap. This comes up a lot. (We have at least a warning for that now.)
The third option is explicit and the style I think should be preferred in traits, too. (E.g. trait Foo { def foo: Unit } instead of trait Foo { def foo }, I think it's mind-boggling and invites errors that we even allow the second option.)
What about
- deprecating and removing option number one,
- adding a warning if a method's result type is inferred to be Unit for option number two
- guiding users towards specifying the return type explicitly, like in option number three?
I think it would be good to get rid at some point of specialized procedure syntax. It goes with the general desire of making the language simpler. But I also agree we have to be careful not to create busywork for people. So, as a first step, it would be good to update the style guide and IntelliJ's syntax checking tool.
In a sense, I think the idea about recommending : Unit = is quite similar to the reason why we started to emit a warning for catching exceptions with case _: “If you really want that, please think about future readers of your code and be explicit about your intention.”.
That's pretty much the only thing Go managed to do right: They have go fix, which can rewrite existing code without user input.
--
"The Go language has always been defined by a spec, not an implementation. The Go team has written two different compilers that implement that spec: gc and gccgo. Having two different implementations helps ensure that the spec is complete and correct: when the compilers disagree, we fix the spec, and change one or both compilers accordingly."
I would give my left arm to see things prioritized in this fashion, instead of like this. https://groups.google.com/forum/?fromgroups=#!topic/scala-language/SMru3oz2gc4
The utility of procedural syntax is that Scala doesn't disallow side-effectiveness, and in my limited experience, ": Unit =" is too verbose unless it facilitates a one-liner. That would be one line of side effect.
Also, how did the wrong wrong wrong scaladoc style leak over to:I say "wrong" because the correct style is a way for the closing slash not to impinge typographically on the comment text.
http://docs.scala-lang.org/style/scaladoc.html
The utility of procedural syntax is that Scala doesn't disallow side-effectiveness, and in my limited experience, ": Unit =" is too verbose unless it facilitates a one-liner. That would be one line of side effect.
The only thing I can say is that it's not my experience, but that it is the experience I gained from having worked with "beginners", sitting down with them and asking them about their experience: the confusion about the difference between def-with-= vs. def-with-no-= is a _huge_ issue.
The question is, why are we causing this huge confusion for basically no tangible benefit? Imho, it would be a lot easier to explain and more consistent if one could say "every member implementation consists of an =, separating the signature to the left and the body to the right".
I am not sure how these beginners learned Scala, but I see this mistake very rarely in StackOverflow questions. I suspect that your sample is biased. (Mine may be also.)Questions around def f() vs def f come up way more often, as do questions about map(_ + 5) vs map((_ + 5)*2). A question which is basically "why don't we have tap and/or pipe" comes up every few months. Then there's the "what's f(x: Int)(y: Int) anyway" question, and the how-the-heck-do-you-use-Option question, and the I-don't-know-how-to-use-Try question, and so on. I have seen the f {} vs f = question a few times, but its way down the list, and unlike some of the others, I haven't seen people go, "Wha, huh, I still don't get it?!" or "Arrrrgh, my life would be so much easier if you would just make me type : Unit = every time" after a two-line explanation:
When you write def f { }, f will run the enclosed code and return () (i.e. nothing, Unit).When you write def f: X = expr, f will run the expr and produce X; omit the type X to have it inferred
For beginners to whom that explanation doesn't make sense, you need a few more words, of course (e.g. an intro to types and return values). But it's really simple.
If it really is a huge confusion, I'd reconsider. But I think it's a small confusion. And I don't know how you develop in Scala, but I would notice typing : Unit = a bunch of extra times. And it's really easy to pick out the side-effecting methods visually now (obligatory) because they have no return type. If you write everything with : Unit =, suddenly the visual difference goes way down
The point between all these examples you made and the procedure syntax is that there is a reasonable explanation for them. People benefit from knowing why things work this way.
That's just not the case for the procedure thing. It's just some random public-static-void-main bullshit we throw at them for absolutely no good reason.
Hi!I am not sure how these beginners learned Scala, but I see this mistake very rarely in StackOverflow questions. I suspect that your sample is biased. (Mine may be also.)
Questions around def f() vs def f come up way more often, as do questions about map(_ + 5) vs map((_ + 5)*2). A question which is basically "why don't we have tap and/or pipe" comes up every few months. Then there's the "what's f(x: Int)(y: Int) anyway" question, and the how-the-heck-do-you-use-Option question, and the I-don't-know-how-to-use-Try question, and so on. I have seen the f {} vs f = question a few times, but its way down the list, and unlike some of the others, I haven't seen people go, "Wha, huh, I still don't get it?!" or "Arrrrgh, my life would be so much easier if you would just make me type : Unit = every time" after a two-line explanation:
When you write def f { }, f will run the enclosed code and return () (i.e. nothing, Unit).When you write def f: X = expr, f will run the expr and produce X; omit the type X to have it inferred
For beginners to whom that explanation doesn't make sense, you need a few more words, of course (e.g. an intro to types and return values). But it's really simple.
The point between all these examples you made and the procedure syntax is that there is a reasonable explanation for them. People benefit from knowing why things work this way.
That's just not the case for the procedure thing.
It's just some random public-static-void-main bullshit we throw at them for absolutely no good reason. I want to reduce exactly that beginner-hostile non-sense, because I believe a person shouldn't need to become some "elite" coder who remembers all weird gotchas to leverage Scala for his/her projects.
If there would be an alternative which prevents people from mistakenly creating procedures instead of methods AND wouldn't introduce yet another syntactic inconsistency, I would love to hear about it.
A method-procedure doesn't return a value. So, don't write =.
A method-function does return a value. So, write =.
So we don't need to special-case procedures, we pretend they return a value we call () of type Unit, and fill it in if we convert a procedural method into a Function.
If there would be an alternative which prevents people from mistakenly creating procedures instead of methods AND wouldn't introduce yet another syntactic inconsistency, I would love to hear about it.
No, no, you're missing my point. In order to clarify what's side-effecting you WANT a syntactic inconsistency. This is exactly what tells you at a glance to be careful!
I suppose we could name UnitImSoSorryButIJustWantThisToWorkIKnowItsSideEffectingImNotABadPersonOkaywhich would also let you tell at a glance that something is going on.
Hi,A method-procedure doesn't return a value. So, don't write =.A method-function does return a value. So, write =.
I think that reasoning could be used in Java, but in Scala, where Unit actually has a value, it's blatantly wrong and misleading.
If there was a type, which should qualify to work without =, it's Nothing, but weirdly a method of type Nothing requires the =.
So we don't need to special-case procedures, we pretend they return a value we call () of type Unit, and fill it in if we convert a procedural method into a Function.
I think the thing above is not only a special-case, but it is one for which one can't find a decent explanation. Every point why Unit shouldn't require = applies even more to Nothing.
If there would be an alternative which prevents people from mistakenly creating procedures instead of methods AND wouldn't introduce yet another syntactic inconsistency, I would love to hear about it.
No, no, you're missing my point. In order to clarify what's side-effecting you WANT a syntactic inconsistency. This is exactly what tells you at a glance to be careful!
There are tons of people who DON't WANT to have a side-effect at all, but keep falling into the procedure-trap. If this wouldn't happen at the rate I'm seeing, I wouldn't care that much about procedures.
Get us off the JVM entirely and to something where this isn't the sensible encoding and fine, I'll accept "blatantly wrong and misleading". I know you'd _like_ to, but there really is no return value and there's no harm in reflecting that until the time when there actually is a return value under the hood. For now it reflects reality *better* than the fiction of Unit.
But sure. It's a bit ugly, I think it'd be fine to be able to declare Nothing instead of Unit, if you really wanted to. Does that come up much?
If they don't want to have side-effects and think it's not null, how do they get past the type system later on when they have Unit where they expect some other type? And I said long ago that I'm okay with f = println giving a warning.
P.S. If your IDE can color it for you, it can rewrite f { } into f: Unit = { } for you.
I suppose we could name UnitImSoSorryButIJustWantThisToWorkIKnowItsSideEffectingImNotABadPersonOkay
I say "wrong" because the correct style is a way for the closing slash not to impinge typographically on the comment text.Also, how did the wrong wrong wrong scaladoc style leak over to:
http://docs.scala-lang.org/style/scaladoc.html
Possibly, before the doc sprint, the code didn't include enough doc to set a precedent.(As a total noob/nuli, I adopted the first style as advocated by the style doc, which is mathematically (alignment on multiples of two columns) and rectilinearly cleaner. Neither style solves the problem of switching to non-scaladoc without a formatter. But the second style now looks to me like a flag planted atop the code. Happy Memorial Day.)
/** Foo is something useful.
* Too bad the PR is rejected because the
* Scaladoc comment is wrong wrong wrong.
*/
class Foo {
}
/** Bar is a refinement of Foo.
* In the Scala type system, refinement = improvement.
*/
class Bar extends Foo {
}
/***** .........
***** .........
***** .........
...............
...............
*
*
*/
By the way, shouldn't this be on scala-debate or something?
--
P.S. If your IDE can color it for you, it can rewrite f { } into f: Unit = { } for you.
Agree. I'll look into the refactoring code, so that the IDE can get rid of the special syntax without requiring user interaction.
--
You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
P.S. Regarding frustration, f(i: Int) { i + 1 } could be a gotcha also; maybe it would make sense to warn about that also (i.e. if the statement is an expression not returning unit).
Agree.
Is there consensus on the trait Foo { def foo } bit? If yes, I can create a pull request for it now.
I agree that trait Foo { def foo } is bad, but I think trait Foo { def foo: Unit } is equally bad. It should always be trait Foo { def foo() }. Then intentions are clear--foo has side-effects and doesn't return anything. I think that trait Foo { def foo(): Unit } adds nothing but clutter.
I agree that trait Foo { def foo } is bad, but I think trait Foo { def foo: Unit } is equally bad. It should always be trait Foo { def foo() }. Then intentions are clear--foo has side-effects and doesn't return anything. I think that trait Foo { def foo(): Unit } adds nothing but clutter.
The huge issue I have is with consistency, not with conciseness. I think it would be great to have ONE, consistent rule like "a method needs either a body to infer the result type or an explicit result type annotation".
It would be even more consistent to require explicit type annotations everywhere.
Clearly there are trade-offs between consistency and conciseness, and you would draw the line somewhere differently than I would. But I think if we change the rules now we are going to aggravate quite a number of people, myself among them.
For the record I also prefer def foo() { ... } for side-effecting methods over def foo(): Unit = { ... } for much the same reasons as Rex. It's clear, concise, and syntactically obvious that foo doesn't return anything.
--
Has no one suggested import scala.language.procedures?
The compiler could special-case the definition of main so that the first day of Scala class goes without a hitch.
I picture the opposing counsel jumping to his/her feet and barking, "I object!" The courtroom erupts! Pandemonium ensues!> I strongly oppose the idea that it is somehow defensible that we let _every_ beginner suffer through the method-vs.-procedure madnessI honestly love this sort of language, and I only I wish it were on scala-debate so you wouldn't have to hold back.
It does take me the umpteenth time to think of something to contribute: It's possible procedure syntax forces beginners to cope with the conceptual hump of everything evaluating to something, which is why they forget the equals sign. I remember that ": Unit" seemed strange to me because of that hump, and by conceptual hump I mean hurdle and not brain-f--k.
Without Simon's PR on "def g = 5" you get "warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses" which I'm sure is pretty confusing. With Simon's PR it moves to the line "def g" where you get "Procdure syntax is deprecated." Already that's a great improvement because the real source of the problem is highlighted.
Presumably the deprecation will morph into an error eventually.On Oct 25, 2013, at 11:12 AM, Rich Oliver <rzi...@gmail.com> wrote:Is it really OK that the following only gives 1 warning and no errors?
object MyApp extends App {
val x = new MyC1
val y = x.g
}
abstract class MyC {
def g
}
class MyC1 extends MyC {
def g = 5
}--You received this message because you are subscribed to the Google Groups "scala-internals" group.To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.
--
You received this message because you are subscribed to a topic in the Google Groups "scala-internals" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-internals/q1YX7NC1geM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to scala-interna...@googlegroups.com.
--