On Scala
dehora.net
dehora.net
I've been working steadily in Scala since and currently do so professionally. I'm a fan, especially with the Akka actor framework.
Lately I've been playing with Play, Akka and ReactiveMongo. For-comprehensions offer a terrific abstraction for dealing with asynchronous code. My current side project is "Street View for Flights" implemented in the above stack. Lots of calls to third-party REST APIs after checking if data has already been retrieved and inserted into Mongo. Code like the following allows for controllers to be asynchronous while staying readable:
def byCode(airlineCode: String) = Action {
Async {
for {
airline <- Airline.findByICAO(airlineCode) // returns Future[Option[Airline]]
} yield airline map { a =>
views.html.airline(a)
} getOrElse NotFound
}
}
The advantage for me is that those futures could be redeemed either by finding the requested object in Mongo and on failure retrieving it from a third-party API while not blocking and keeping the code readable. Either way, the controller just gets a Future without blocking.Other parts of this project make heavy use of Akka actors to feed server-sent events (sort of a compromise between Comet and WebSockets). Development has been great fun because Scala really allows me to write code at a higher level. Asynchronous, typesafe, nullsafe code with the compiler as my safety net.
What's the point of having a powerful type system like Scala's and then throw it out of the window just so I can use a distributed framework?
https://github.com/scalaz/scalaz/tree/scalaz-seven/concurren...
https://github.com/scalaz/scalaz-stream
Like everything with Scalaz, the tools are great but almost completely undocumented.
Exactly. I will start considering scalaz once its authors grow up and realize that the lack of documentation is not a sign of quality.
They could just have kept the code proprietary.
The macro feature introduced in Scala 2.10 makes this possible.
http://doc.akka.io/docs/akka/2.2.0-RC1/scala/typed-channels....
[1] http://stackoverflow.com/questions/5547947/why-are-messages-...
findAirline: AirlineCode => Future[Option[Airline]]
getFlightsForToday: Airline => Future[Seq[Flight]]
findAvailable: Seq[Flight] => Constraints => Future[Option[Flight]
compose them so that I get: findFlight: AirlineCode => Constraints => Future[Flight]
I don't want `Future[Option[Flight]]` since Future has own error handling (using Try). No cheating by using scalaz monad transformer. def getOrThrow[T](x: Option[T]): T = x.getOrElse(throw new AirlineError)
def findFlight(code: AirlineCode, constraints: Constraints) = for {
airline <- findAirline(code).map(getOrThrow)
flights <- getFlightsForToday(airline)
available <- findAvailable(flights, constraints).map(getOrThrow)
} yield (available)
No idea why you consider using scalaz to be cheating. for
a <- forA
b <- forB
c <- forC(a)
it does not do a and b in parallel and then c, or does it? for {
a <- forA
b <- forB
} yield a + b
This runs them in parallel: val fa: Future[Int] = forA
val fb: Future[Int] = forB
for {
a <- fa
b <- fb
} yield a + b
(I dropped forC from your example as it has a dependency on the result for forA, and thus can't run in parallel.)I can't see the difference between your examples and so am confused why 1.) is serial 2.) is parallel.
You know that a for comprehension expands into calls to flatMap and map? So
for {
a <- forA
b <- forB
} yield a + b
expands to forA flatMap { a => forB map { b => a + b } }
Remember that forB creates and returns a future. Only when this future has been created will it start running.It should be apparent that forB is not evaluated till forA's future delivers a value, and thus the future returned by forB will run in serial with the future returned by forA.
In the other example the futures are created outside of the for comprehension, and thus start running in parallel.
Another feature that got my attention was the ability to have a SQL framework that handled things similar to LINQ. I haven't tried it much yet, but Squeryl[1] has looked promising for being a Scala equivalent. I may have to look into Akka more though as that will easily take care of async SQLite calls as well[2].
[1] http://squeryl.org/introduction.html
[2] http://www.gamlor.info/wordpress/2012/05/async-sql-and-akka/
I'm also looking forward to async SQL calls.
I've been building some Akka-based projects for a client and both they and I have been thrilled with the results. They're a startup that's gaining traction and they brought me in to help with scalability. I won't go so far as to say that Akka is a magic bullet but it makes reasoning about scalability far easier, though in our case we're mostly dancing around the IO bottleneck.
http://www.scala-lang.org/gsoc2013
http://www.google-melange.com/gsoc/projects/list/google/gsoc... (type "scala team" in "Organization" box
class Foo(var x: Int, var y: Int, var name: String)
(Thats equivalent to 6 method definitions and a constructor in Java. Also, the possibility that you forget to initialize one of the fields in your constructor [which happens from time to time in most Java code] is removed)It's not just about having to write less boilerplate, it's also about having to read less code and expressing ideas using functional concepts where it makes sense.
Critics like to complain that having many features makes the language complex. In practice Scala code is fairly straightforward, the extra features just mean that library designers have to power to implement some pretty amazing interfaces for you using these features. Most Scala code is pretty sensible, and it's nice to know that the extra expressive power is there when you need it.
This may sound like heresy but I find myself being more productive in Scala than in Ruby. Part of that comes for the self-documenting nature of static typing and clear interfaces (No more "what methods and fields does this Foo object that is being passed in to this obscure method have?"). This is a very useful property to have when reading other peoples' code. The tooling is surprisingly mature (IntelliJ).
In hindsight picking Scala as a better Java should have been a no-brainer.
http://talesfromannoyance.blogspot.com/2012/05/why-im-lookin...
If you want reuse, you need to look at taking those parts and wrapping them up in SOA.
Don't get me wrong, I like Scala. You just really have to watch its dual paradigm behavior when dealing with Java code
Monad m => Int -> m Bool
not nominal subtyping in action? Any type you create a Monad instance for will be accepted, so subtyping. You have to actually make it an instance of Monad, it can't just have the structure of a monad, so nominal.Haskell actually has whole program type inference (unlike Scala, which only does local inference), so fold/map will always return the right type as well, but you also get to not have to put types anywhere if you don't want to (including function signatures).
Scala's main advantage over Haskell is being able to call into Java.
+ a superior module system + better type classes (no global namespace)
But yes, if running on the JVM is no option, Haskell is a serious contender
Could you expand on that a bit?
It starts from this [1]. Then there's case classes, _, optional everything (forgetting = in a function def can make it mean something else), the currying syntax [2] (sometimes it needs an arbitrary _ to break ambiguity), the imports (especially renaming), arbitrary rules on whether construction needs "new" or not, etc.
The fact that [3] is possible even though Scala is not an almost-no-syntax language (like Lisps and Haskell) concerns me. And it even has macros, but all of its very many language features aren't implemented as macros :(
1. http://en.wikipedia.org/wiki/Scala_(programming_language)#Sy... 2. http://brenocon.com/scalacheat/ 3. http://blog.fogus.me/2009/03/26/baysick-a-scala-dsl-implemen...
optional = in function definitions is legacy that will hopefully go away at some point. Optional brackets and braces are something most languages have (bwim you can usually bracket or unbracket an expression without changing it), so it doesn't bother me that scala has them in slightly more places.
Using _ for partial application of an object method is simpler than you make it sound; you always need it. That page misunderstands. I dislike the complexity but it allows UAP to work which is awesome; are there languages with a similar UAP and functions-as-values without requiring disambiguation?
Agreed that relative imports and renaming imports are evil bad and wrong.
Construction requires new; I think this is largely there because it's a major difference at the JVM level and some people care about knowing when it's happening. Personally I agree we'd be better off without it.
Macros are new and experimental. I suspect that if/when they gain acceptance we'll see core language features implemented using them where this simplifies (e.g. there's no reason for comprehensions and case classes couldn't be macros).
It is usable now even for production although the compiler is not yet optimized and the language is still evolving.
- case classes: I love them.
- _: The underscore has one meaning, “there is something, but I don't care about the name”. Super simple.
- forgetting = in a function def can make it mean something else: I agree, it is very error-prone. As far as I know, there are some proposals to get completely rid of procedure syntax.
- currying syntax: PinS has a pretty good explanation why it works that way. It is certainly not perfect, but less error-prone than alternatives.
- the imports (especially renaming): Many languages have this feature and I have not seen any issues with it.
- arbitrary rules on whether construction needs "new" or not: No. The rule is that you always need new to construct an instance.
-[3]: You can do crazy stuff in every language. Have a look at functional code written in Java.
- And it even has macros, but all of its very many language features aren't implemented as macros: No. In a sense, ALL features are implemented via macros, because the compiler API and the reflection API (macros) are pretty much the same underneath.
- case classes are great because they're a Algebraic Data Types. I dislike their syntax
- the underscore is sometimes necessary for disambiguation, that's the only thing that bothers me
- I don't mind the fact that renaming imports is possible, I think that's great. I just dislike the particularly unusual syntax, since = is already there for symbol binding
- since there isn't a de-sugared version of every language construct, I doubt macros are indeed that equivalent. Again, I think macros are great, but it worries me when a language's syntax is already so complex through "hard-coded" methods (as opposed to the more programmatic macros)
If one is not careful and adhering to a formal style guide, it would easy to end up with an unreadable mess of inconsistent code. Anyone with some grounding in programming already at a professional level shouldn't have a problem, but someone that's relatively new to development might want to look into another language. For example, all of these are valid ways to create a class with some parameters/properties:
https://gist.github.com/yareally/5811498
After having to use Java on Android for the past three years, such freedom is both liberating and shocking at the same time. I use C#, JavaScript and Python pretty frequent as well, but it's just I'd say Scala is even more liberal than any of those feature wise. It's more like Perl (not quite, but close), but not quite in the area of a Lisp variant. Scala is definitely written from the viewpoint of the developer and not the intended users though. It's also nice to have access to features that are standard in languages like Python, Ruby, C# and functional languages. Seeing 13 lines of Java become 1 line of Scala[1] is a great feeling.
I'd say if you have experience with Java, C#, Python, Ruby or any functional language you'll pick up on Scala pretty quick. If Java is your only language experience, it might be a bit rough at first, because of the expressiveness and freedom of the language, but don't let it detour you. If needed, you can mostly stick to the imperative side of Scala and slowly work in more functional features as well as some of the useful syntactical sugar stuff (like operator overloading) that Scala provides.
I'd say that's a bad idea.
People keep saying that Scala is not an opinionated language and that you have to make choices and stuff. That's not true and in fact, Scala is a very opinionated language that makes imperative code painful. That's why some beginners get so frustrated when they pick it up. Because they come with certain wrong assumptions about how features in Scala work.
Examples: Scala does not have "break" or "continue", while "return" does not behave as many people think it behaves. The "yield" keyword in "for" expressions is also totally different than the "yield" in C# or Python or Ruby. Actually "for" expressions in themselves are actually monad comprehensions - powerful, elegant, but definitely not your grandma's foreach. Also, collections are immutable by default.
Are collections immutable by default in Scala? I thought each each was treated as a separate, but equal package (scala.collection.mutable and scala.collection.immutable) and collections within scala.collection itself can be either mutable or immutable since they're super-classes to both subpackages. The difference between the super-package collections and the subpackage collections.immutable being that collections.immutable was guaranteed to be immutable.
I've kind of avoided "yield" so far and opted for the functional equivalents. Something like
val result: Array[Int] = for (elem ← n if n % 2 == 0) yield 5 * elem
just looks more readable as:
val result = n.filter(_ % 2 == 0).map(5 * _)
or in more functional syntax:
val result = n filter { _ % 2 == 0 } map { 5 * _ }
I don't think imperative code is necessarily painful in Scala, it's just constructed a bit differently. On the other side of the paradigm, functional language advocates seem to say functional programming in it is also painful[1]. Just seems Scala cannot 100% please everyone 100% of the time.
[1] https://groups.google.com/d/msg/scala-functional/kvbaE6cAzqM...
> On the other side of the paradigm, functional language advocates seem to say functional programming in it is also painful[1]
Worth pointing out that the people advocating for a better language in that thread, including the one that started it, have problems with Haskell too (currently the poster child for functional programming). It is the reason why many of them are using Scala, whether they like to admit it or not. In that thread it is even argued that lambda-calculus itself is outdated because it is inherently sequential.
Scala attracted many idealists that aren't pleased with any mainstream language. On one hand it is good, because it moves the language forward. By comparison the Go community is kind of toxic. On the other hand, people that don't get the context of that discussion jump to conclusions.
That project looks interesting though. Looks like it's almost based on the new async abilities in C# 5.0[1]. Have you tried it any yet in Scala?
[1] http://fizzylogic.nl/2012/05/04/adding-asyncawait-support-to...
This definitely threw me for a loop when I started using Scala. I banged my head against the keyboard a few times trying to get for comprehensions to do what I thought they should do.
Once I began to fully understand the relationship between for comprehensions and monadic operations, especially on Futures and Options, I began to understand their power.
That was also my impression. Clojure is sometimes painfully restrictive (I need forward declarations for functions if I use them before they are defined? In a compiled language in 2013? Really?), but at least it is curated.
The difference between Scala and Clojure is the difference between ML and Lisp. Languages from the ML family are statically typed by definition, therefore they need slightly more features to be expressive. On the other hand, the trade-off is worth it for many people, because the compiler actually helps you - for example it's far easier to work with various functors (such as monads) in ML languages, than it is to do that in Lisp.
Also, Clojure is not "painfully restrictive" or "curated". Name one thing that Clojure doesn't allow you to do.
I would like reader macros because they would enable the implementation of sweet-expressions (http://readable.sourceforge.net/).
I keep thinking with Scala though, I'm going to run into some really awful looking code one day from someone overly abusing all of its features. I know know even the most restrictive languages can be abused, but it just feels like Scala leaves the window much more open for that.
I also keep thinking that, but it never really seems to happen in my experience.
Google returns this: http://docs.scala-lang.org/style/ or this: http://davetron5000.github.io/scala-style/index.html but do you have any that you'd recommend?
Most important thing is to just stay consistent with whatever you decide upon more than which formal style you choose. If I were working in a team with Scala, then I would stick with a formal spec (or just let the IDE auto-format for me to adhere to the team's style when committing).
This reminds me a lot of C++: powerful but unless you agree on a consistent style and only using a subset of its functionalities, you end up with nightmare code bases.
Too much features: Scala has everything, it seems like the language designers coudn't make a choice about what is best. "Whoo this is cool, lets add it". One word: implicits, arrgh
Also the fact that is built on top of java... When you design a good language, you should try to do it right, and leave all other out. However this is a design choice of Scala. And I think this choice makes the language a short term language, just as a stepping stone for java programmers to better languages.
- end of rant -
Imagine, for example, math. Sometimes, I want 1/3 to be exact (i.e. a rational), so that 1/3 * 3 == 1, other times I want 1/3 be a float (eg. when doing numeric algebra). In a language with implicits, I could simply import the correct math object that provides the correct implementation of /, and use it in the whole module. Furthermore, if this math implementation is passed as an implicit parameter, every other library/function I use (even in another module) automatically uses the implementation of / that I want.
This could be used in many other situations as well, such as memory management, where we could have an implicit policy (allocate on stack, heap, reference-counting, GC, ...), "opening" of classes (import a class and an implicit extension of it), and many other.
In a way, this is similar to what Haskell type-classes do, except that it can actually be controlled by the programmer.
You could argue that you should use them with care, but i'd argue not to include them in the language. You'll go c++ all the way.
Implicits are very powerfull for creating DSL's in Scala. And indeed scala is a good language for doing DSL's. But for me understanding what was happening by reading code was difficult. And i think code should be easy to understand.
It beats the heck out of having to do the following in Java:
BigInteger x = new BigInteger(someBigNumString);
BigInteger sum = x.add(new BigInteger("1000");
When you can do this in Scala (or similar in C#):
BigInt x = BigInt(someBigNumString)
BigInt sum = x + 1000
If you're going to say it can be abused, lots of things can be abused in any language. I prefer sanity in this case for implicits over risk of abuse. Having to use something like BigInteger in Java without implicits just makes my head hurt trying to read and write code using it.
There were two things struck me as questionable about the extensive DSL support in Scala. First, Scala source files that used one library's DSL ended up looking like they were written in a different language than Scala source files using another library's DSL. That, to me at least, makes it harder to read the source quickly and understand whats going on. This wasn't a horrible problem, but I found it somewhat burdensome to reorient myself when switching between DSLs, so I feel like it's an overall negative feature of the language. Sort of the opposite of the benefit that more consistant looking languages like Python and Go provide.
It also means, at least for me, that and IDE is necessary in order to understand what's going on in source files using certain DSLs. I'm an Emacs user and this is the first time I've felt like I really should have been using an IDE, which was irritating.
My second objection was that because of ambiguities between implicit conversions in different DSLs, source files that used more than one DSL had to fall back on explicit conversions and therefore not really use the DSLs. That made some source files using a given library look very different from other source files using the same library, since one was written using the DSL and the other wasn't.
This is really my major objection to the language. In many other ways I really enjoyed Scala and wish I could use it more. Yet I wish DSLs and implicit conversions were used much more sparingly in Scala libraries.
You mean implicit conversions, right? Because implicit parameters are the single best thing since sliced bread.
Considering features: Well, it certainly depends where you come from. If you come from Scheme, Scala is huge. But if you come from Java or C# or F# or ..., Scala is refreshingly small, consistent and self-contained.
Regarding implicits: Most languages have implicits, they are just hard-coded into the language and will be there forever. In Scala, you can just de-import the ones you dislike and if enough people dislike those, they might even get deprecated and removed.
Implicits seem to be really the feature all people except actual Scala users love hating, especially exactly those kinds of implicits which aren't even widely used anyway. Implicit conversions make up maybe 10% of all usages of “implicit ” and require a feature import.
Features: Compared to Java, scala has a lot more features. It has functional programming for example, but its not done right, due to it's java bases. For example, try currying, you need extra syntax to curry functions.
Implicits: They might have a place, but see my comment above this one.
The author in the article is complaining about 18 different ways to define a function. Of those 18, the ones which use postfix operators create a feature warning already and will stop being accepted without the appropriate flag in the future.
If you eliminate the ones which use additional but pointless curly braces (Really, what's the point? Why not add 5 curly braces instead of 1?), you are pretty much left with either a named variation (n =>) and an anonymous variation (_). That seems pretty reasonable.
Features:
Compared to Java, Scala also removes a lot of stuff. Having read both language specs, I say Scala comes out as a winner, because the actual features it has are actually working and don't consist of tons of pointless cruft like in Java or C#.
Implicits:
Really, implicits seem to be a big deal for those people not using Scala. For actual users of Scala, they are not. I have never touched a codebase where implicit conversions posed such an issue as it is claimed in blogs. In practice, implicit conversions are pretty rare and mostly used for Java compatibility. The good thing is that you can get rid of the ones you don't like in Scala, which you cannot do in pretty much all other languages (where they are built into the language itself).
""" If a grand unified theory of programming language existed, its implementation would be called Scala """
I love what Jetbrains does though and actively read their blog as they keep improving it. Kotlin has a bright future (I think some of the developers of Groovy are working with Jetbrains on it), but still a language in its infancy.
Today the Groovy P.M. announced they're adding statically-typed traits (http://groovy.329449.n5.nabble.com/Adding-Trait-to-Groovy-td...) to Groovy, talking about them like they're an innovation. But they were already implemented by former Groovy++ developer Alex Tkachman (https://code.google.com/p/groovypptest/wiki/Traits) 2 years ago. Groovy added static compilation into Groovy 1 year ago by copying it from Tkachman's Groovy++ codebase, then announced it to the world as "Groovy 2.0" without crediting him. Now they're trying the same trick again, laundering the Groovy++ Traits and passing it all off as "Groovy 2.2".
Alex Tkachman is now one of the Kotlin developers (along with Groovy's creator James Strachan). So which codebase would you trust: one laundered without credit from someone else's implementation (Groovy), or a second try from the actual person who wrote the first attempt (Kotlin)?
The potential growth for Kotlin usage will be on Android platform especially after the new Android Studio is based on IntelliJ 13. Kotlin fits nicely here and it's a relatively small language.
Scala though is quite a pioneering language on the JVM. I think a lot of Kotlin features and design are influenced by Scala.
Random question, but how far along is Ceylon's development compared to Kotlin's? I know they're both relatively new still, but just wondering how feature complete it is so far.
[1] http://confluence.jetbrains.com/display/Kotlin/Null-safety
I hate to say it because I like JetBrains and have given them lots of money over the years but I prefer Ceylon to Kotlin. They are very similar languages but I just like the Ceylon syntax more.
It's worth mentioning the positive side of more concise syntax for closures - as someone who previously used lamdbas heavily in python this is a real win. "Seq("1", "2", "foo").map({n => stoi(n)})" should just be "Seq("1", "2", "foo").map({stoi(_)})" - or, in this particular case, "Seq("1", "2", "foo").map(stoi)". Of course, the price is shown at the end as having more than one way to write the same thing - but the differences in those examples are (IMO) superficial and don't impair readability.
The specific problem of infix/suffix methods should be solved with 2.10's compiler flags. They should also go some way towards improving source compatibility (features for which the syntax is expected to possibly change will stay behind flags), while 2.10 introduces a better binary compatibility policy. Still, most of the criticism is fair, and I'm pleased to see a comprehensive impression post like this.
scala> def theSquareMullet(i:Int) = i * i
theSquareMullet: (i: Int)Int
scala> def theHoffSquareMullet({ mullet: => Int }) = mullet * mullet
<console>:1: error: identifier expected but '{' found.
def theHoffSquareMullet({ mullet: => Int }) = mullet * mullet
^
scala> def theHoffSquareMullet(mullet: => Int) = mullet * mullet
theHoffSquareMullet: (mullet: => Int)Int
scala> theSquareMullet(theHoffSquareMullet(10))
res0: Int = 10000Since then, it has become such a strong favorite that I have remodeled part of my own hobby programming language based on Scala.