and it's way more readable than their given rewrite.
Then again, for-yield might be too magical and "can confuse programmers less familiar with Scala," which seems to be a reason for a lot of the stylistic decisions.
My favorite syntax sugar in Scala. Especially in future composition.
Is there a good theoretical (not technical) reason why we can't mix types in a for-yield structure? There is an implicit conversion from Option to Seq added, so I can mix lists and options, but is there a fundamental issue preventing mixing other types? e.g. in the basic math of it?
All for comprehension is syntactic sugar for repeated calls to flatMap.
So
for {
a <- someOption
b <- someOtherOPtion
} yield a + b //returns Option[Int]
ends up being
someOption.flatMap(a => someOtherOption.map(b => a+b) )
and remember, all flatMap does is 'map', (so you'd get Option[Option[Int]), then "flatten" it so you end up with just Option[Int]. So if you have 4 'nestings', you only get one level of Option and not 4.
The signature for all flatMaps is ...
class Something[A] {
def flatMap[B](f: A => Something[B]): Something[B]
}
So, you could have that for Option, for Future, for NonEmptyList, Stream, etc.
But they can't mix and match cause you don't necessarily know how to 'flatten' a List into a future. List[Future[A]] is something very different than say just a List[A]. (One is a concurrent computation).
So, yes, you can do implicit conversions to alleviate this, or you can do what is known as a 'monad transformer' which sounds SUPER scary but I go over them in some slides and they're really easy to use.
I agree with your point in general. However, in this particular case, what you wrote isn't equivalent.
The explicit use of flatMap(Option.apply) in the first example is to deal with the case of address existing, but being a null string. Your code doesn't handle that.
Also it seems like a bit of a strawman to use such a pathological example (null values stored in a map are frowned upon even in Java-land) to motivate the entire styleguide section about monadic chaining. They say it's contrived but still -.-
Can people really not decouple the words "for" and "yield" from other languages and just understand how a scala for-yield is desugared? Writing Scala and avoiding for-yield for the reason of it being superficially confusing to someone from another language doesn't really make sense to me.
Imagine if we also changed "while," "return" (which btw scala did), or "if" and made it do something different or similar. Would you still feel that way?
Part of the reasons people can learn new langagues "easily" is that there are universal concepts. When you don't change words but change the meaning then that creates unnecessary difficulty.
In my opinion if you want to introduce a new concept, also introduce a new vocabulary to address it.
We should strive for programming to be easier and more user friendly, and things like this do the opposite. Especially for people like me who switch between multiple languages in a day, it can be mentally taxing to make that context switch.
I've never understood ppl on HN defending things being optionally harder. Such is the CS mindset.
Completely agree w/ you here in terms of language design.
OTOH what's done is done and I don't think one needs to eschew an idiomatic concept just because the people who designed it suck at naming.
Another example is 'case class', because of its heritage I have colleagues who insist it should only be used for pattern matching purposes. I strongly suspect that if the designers were to do things over again that what we know as 'case class' would just be called 'class'
I haven't heard about "it should only be used for pattern matching." Is there a performance reason or something more stylistic?
I use them all the time because of all the convienence associated with them. I'm not really aware of the downsides except for the ~22 parameter limit (I hit it when deserializing JSON that represents many possible Option(al) keys... And named parameters are awesome).
Thanks -- internally we are having a lot of debate about for comprehension. In particular, the use of it might simplify certain use cases (especially async with futures). That said, it also often leads to very high-entropy, dense code and thus hard to reason about.
We will include more guidelines on this in future iterations of the guide.
Isn't is better to use async/await over for comprehension, since its more clear and easy to understand.
Edit: My bad just did my scala assignment, overlooked the details and thought it was a Future :)
This style guide discourages multiple parameter lists, but it doesn't mention that they are useful for helping the compiler with type inference, as mentioned here: http://docs.scala-lang.org/style/declarations.html (granted, this is a bit of Scala ugliness, but it merits discussion).
I agree with several of their recommendations, but I strongly disagree with their general philosophy of "[feature] can confuse programmers less familiar with Scala". It's one thing for [feature] to be genuinely confusing, and an entirely different thing for it to be "confusing to novices / Java programmers". In the latter case, the right course of action is to educate them; otherwise we'd be stuck programming in Java++.
So far it's the best style guide I've seen for Scala. Much more pragmatic, and actually very close to the way I naturally write Scala. I love the instruction to avoid symbolic methods unless they are really using symbols that everyone use (+ - / * etc...) I really hate all the ~> <|-|> <:< madness, it gives Scala a really bad name.
I like it how they prefer JAVA_STYLE_CONSTANTS over ScalaStyleConstants and same thing for annotations.
The instruction on Implicits is really making sense. use it if you build a DSL or use it internally, keep the principle of least astonishment.
Great style guide. I'm adopting it. It's strict on one way, but let's you escape if you have a reason.
The only caveat is what others have mentioned regarding monadic chaining. I prefer to use for-yield when it's clear that I'm working with collection transformations, nested futures, and even nested options. only when it's too cumbersome to read I break it down to the desugared form.
> So far it's the best style guide I've seen for Scala. Much more pragmatic, and actually very close to the way I naturally write Scala. I love the instruction to avoid symbolic methods unless they are really using symbols that everyone use (+ - / * etc...) I really hate all the ~> <|-|> <:< madness, it gives Scala a really bad name.
Do any of you know if there is an equivalent of gofmt for scala, e.g scalafmt?
If such a thing existed some portion of this long list of sensible conventions wouldn't have to be memorized and/or constantly referenced and manually enforced.
Such a tool would empower scala programmers to focus more on that that which is most important- the functionality and logic, rather than manually applied aesthetics.
Lots of good sense, but a few things make the code clunkier than scala needs to be IMO.
try foo catch {...}
is readable and consistent; the idea that {} just makes a block is really useful, making try/catch, if/then and even method definitions a lot less "magic", a lot less cluttered by ceremony.
Infix method calls can likewise read much more clearly:
string contains "foo"
Try is bad, but \/ makes a better alternative to throwing an exception for exactly the same reasons that Option is better than returning null.
This style guide is great. I employ almost all of this at Empirical (my company) and I even learned a thing or two. Very well written, and great examples!
This style guide is depressing... The author's complete oversight of for-comprehensions, the convention of using apply, the insistence on using API-leaking side effects for error handling (read: throwing exceptions), makes me weep. Spark is a Java project maintained by a company filled with Java engineers.
Then again, for-yield might be too magical and "can confuse programmers less familiar with Scala," which seems to be a reason for a lot of the stylistic decisions.