It's good to hear the core team say they want to focus on simplifying the language. I've always felt scalas reputation as a hyper-complex language was not deserved, but it sure isn't a simple language either.
I think it gets the reputation because even though it has a relatively limited number of constructs, they're all almost always in play. And they're almost all so basic that you'll actually encounter them on a regular basis, and often in novel use cases. So there's a certain combinatorial complexity that doesn't exist in languages that actually have more syntactic forms.
Apparently there is a faster incremental complier in sbt these days, but I can't seem to find any info online about how the compiler performance has changed over time.
I get the impression that compiler preformance is being worked on, and is improving over time.
I didn't use scala in the older days, and started only recently, I used Java previously. And I'm quite ok with the times. Sometimes it does slow down a bit, but most of the time for most cases I think it's alright.
Compilation speeds are largely dependent on the type of code you're writing. At London's Scala Exchange last year, Odersky claimed he can get 10k lines/second (10x slower than javac, but still not bad) out of scalac by writing simple imperative code, but libraries that make heavy use of the type system and implicit scope can be as slow as 1 line/minute.
I consider it fair to expect the compiler to be slower when it's doing more heavy lifting, but it would definitely be nice to see the exponential blow-up on the tail curbed in future.
edit: To clarify, the numbers above were what Odersky claimed; I haven't verified them. The 1 line/minute was claimed of trying to build Shapeless - I've never seen anything approaching that in the wild.
I get that that's an upper limit, but that's still pretty shocking. Is there an overarching reason for this type of performance? Examples of this style of code?
Code with many implicit parameters and higher-kinded types is hard to compile, as the compiler needs to solve essentially a Prolog-ish unification problem. Scalaz is a popular library written largely in this style (e.g. [1]). (FWIW I've never seen 1 line/minute.)
OCaml and Haskell offer very similar functionalities and their compilation times are lightning fast.
The main reason why Scala is slow is because the compiler is poorly written. Take a look at the articles from Paul Phillips, one of the Typesafe cofounders who left the company in frustration, he's probably the person who knows scalac the best and he says the code base is basically hopeless.
Note that 1/3rd of Martin's presentation is about Dotty, and that's basically where he spends most of his time these days, he hardly contributes to Scala any more [1].
> OCaml compiles pretty fast, especially if you target bytecode.
Yes, but OCaml doesn't "offer very similar functionalities".
Haskell is quite a bit slower if you consider that you often have to compile not only your own code, but also the sources of your dependencies in the beginning. Additionally, you have to fight with Cabal, which tends to be very unpleasant due to the lack of any reasonable support for exotic things like "versions". Then you might discover hacks like "sandboxing". Hours not spent coding.
I can't speak about OCaml, but Haskell doesn't have subtypes. That's where a lot of the complexity of Scala comes from as well as being a source of annoying bugs:
def f(x: Int) = if (x % 2 == 0) { x } else { None }
(This compiles, but the type of `f` is not `f: Int => Option[Int]`.)
[edit: the bug is not in the scala compiler, the bug is in my code - I almost certainly did not want `f` to have type `Int => Any`. My phrasing, now edited, was misleading. ]
That is not a bug. That is subtype inference working correctly. If you (mistakenly) expected the return type of f to be Option[Int], say so, and you'll get a compile time error telling you about your mistake:
scala> def f(x: Int): Option[Int] = if (x % 2 == 0) { x } else { None }
<console>:7: error: type mismatch;
found : Int
required: Option[Int]
def f(x: Int): Option[Int] = if (x % 2 == 0) { x } else { None }
I believe Ceylon will actually further refine Int | Option[Int] to simply Option[Int].
Option[Int] is simply an alias to the type Int | Null, so Int | Option[Int] would become Int | Int | Null after replacement, which simplifies to Int | Null since Int | Int is equivalent to just Int.
The one line per minute was observed when trying to compile a query over an HList backed record with more than 300 columns. The problem was a polynomial increase of the size of the implicit search tree. This is due to the way implicits are used in shapeless HList library. Slick has a different approach which is much faster, but slightly less general.
The gist is that once you have [edit: recursive] typeclasses or implicits your search can become arbitrarily large and slow. There's nothing that can be done about it by the compiler except arbitrarily pruning the search tree. Or otherwise put, you should factor in implicit search complexity when designing your libraries.
I'm not sure that's a sufficient explanation. Idris and Haskell (with extensions) also have Turing complete type systems. I've never seen either even approach performance like 1 line/minute in real code.
I've written a lot of Scala and I don't think I've seen anything as slow as even 1 line/second. Odersky was talking about Shapeless, which is an edge case in that it is a home for all the type-heavy calculations that scalac can compile but isn't currently optimised towards.
It's quite easy to get extremely slow type inference in expressive typing systems. This code
let f0 = fun x -> ( x, x ) in
let f1 = fun y -> f0( f0 y ) in
let f2 = fun y -> f1( f1 y ) in
let f3 = fun y -> f2( f2 y ) in
let f4 = fun y -> f3( f3 y ) in
let f5 = fun y -> f4( f4 y ) in
f5 ( fun z -> z );;
took at least 3 months (!) to type-infer when I ran it on my 2008 MacBook using the standard Ocaml compiler. I have not tried since. Type inference algorithms have horrendous worst-case complexity. Fortunately that worst-case complexity usually doesn't matter in practise.
I think you got that wrong by a factor of 10. I get between 500 and 1000 lines / sec on my laptop. It depends on the code style. The more straightforward the code the faster the compile. Still with incremental compilation it means I wait rarely more than a couple of seconds.
Thanks Martin, unfortunately it's past the point where I can edit my original comment or I'd go back and fix it. As I recall you said it off-mike in Bill Venners' talk, otherwise I would have fact-checked it!
Anyway, details aside I thought it was a great illustration of the impact on compiler performance that code complexity can have.
I do a lot of scala development and the compile times are fine since we have many projects but each project is fairly small (microservices). Incremental compilation is essential for reasonable compile times. We use maven with zinc.
Scala has always been multi-paradigm -- that can be a strength or a weakness. Martin Odersky seems brilliant, and I've enjoyed watching some of the talks he's given, but he also seems to define words in a way that goes against the way I use those same words. For instance, he seems to conflate "module" and "object" to the point that any language with "modules" is also an object-oriented language, which is odd, since that would make Haskell and Erland object-oriented. I'm thinking of what he wrote here:
"Objects done well provide a lightweight module system (in the sense of ML). The requirement for a good module system is something that's often overlooked when all you do is a simple application, but its lack becomes painfully apparent for large systems and systems that are maintained over time. You can go the SML route and provide a module system and a functional core language. But then there's the pressure that you want to generalize your modules to be more flexible, which means you want them to become recursive and first-class. If you do that, you end up with a de-facto object system in addition to your core language of algebraic data types and functions. Scala's approach of unifying modules and objects is more parsimonious: The same constructs define the core language and the module language. So Scala is simpler, in the sense that fewer concepts are needed to describe the total feature set."
Others have already commented on this, and I have nothing more to add, but I do find myself doubtful about whether the "Scala is simpler" is justified. Scala has always been multi-paradigm, so I don't think of it as simple -- and, again, that can be a strength or a weakness. I'm reflecting on what was written here: http://scala-programming-language.1934581.n4.nabble.com/OOP-...
Modules as Odersky refers to them here (modules "in the sense of ML") do not exist in Erlang or Haskell at all. They are a unique typing discipline.
In MLs, in large part to ensure that HM-style type inference remains "complete", the module type language is stratified from the value type language. This feels a bit repetitive, causes slow expansion of flexibility and power in the module language, and makes it difficult to refer to modules dynamically.
For some, these are all good things. In this point of view, modules are "large" in a way that makes them difficult to reason about and so the restrictive language they're manipulated with is vital for making them reasonable.
For others, you might as well just unify the "large" module language and the "small" value language. If you do this carefully you might not even lose "complete" HM inference [0].
This is the path that Scala takes though it unabashedly tosses out HM inference for the a highly incomplete (e.g. "local") subtype/supertype logic.
Now there's a bit of an assertion that floats around that Scala's objects are essentially equal in power to what ML's modules would be if they were first class. I'm not sure if anyone could quite make this formal prior to the core calculus clean-up that is going through with dotty. Perhaps after that point the unique features of Scala will be emphasized... or we'll truly determine that Scala is just a unique approach to ML modules which has a different type inference engine.
No, ML modules are usually early bound which prevents open recursion eg
module First = struct
let rec even x =
if (x >= 0) then (
print_endline "even!";
odd (x-1)
) else
()
and odd x =
if (x >= 0) then (
print_endline "odd!";
even (x-1)
) else
()
module Second = struct
include First
let odd x =
if (x >= 0) then (
print_endline "weird!";
even (x-1)
) else
()
end
Second.odd(3)
(* weird!
* even!
* odd!
* even! *)
In ocaml you can use classes for open recursion but that is implemented using dynamic dispatch. For static dispatch you would have to hack something together using a record that is passed itself.
That's more of an issue with implementation than with typing. I mean more like, in an OO language it is possible to declare an interface with a method that returns the final subtype (i.e. the object's this type), which isn't even know yet at the point the interface is defined.
They seem related to me though. Open recursion requires calling the method from the final subtype rather than the current type - `even` would have to call `this#odd` instead of `odd`. The core problem in both cases is not being able to refer to the final subtype in any way.
Hmmm, even if modules could refer to this final subtype you would probably have to choose between doing it via dynamic dispatch or sacrificing separate compilation, since the parent module doesn't know what method to dispatch to at the time of compilation.
There are recursive modules but you're right if you're noting that modules don't offer open recursion. That's definitely something Scala offers that ML modules cannot.
For instance, he seems to conflate "module" and "object" to the point that any language with "modules" is also an object-oriented language, which is odd, since that would make Haskell and Erland [sic] object-oriented.
I cannot weigh in with regards to Haskell, but in the case of Erlang this actually isn't all that odd. The actor model is to a large extent an object system for modelling concurrency - this being per Alan Kay's definition of OO as isolated units that communicate via message passing, as opposed to the more common definition of polymorphism/encapsulation/inheritance, which in practice is usually a quasi-procedural sugar coating.
Admittedly this does neglect some of the more detailed Smalltalk properties like class objects holding shared state, but the terminology behind OO is murky and Erlang exhibiting elements of it can nonetheless be argued.
" Erlang might be the only object oriented
language because the 3 tenets of object
oriented programming are that it's based
on message passing, that you have
isolation between objects and have
polymorphism."
I don't think he's conflating the ideas, so much as pointing out that Scala's ideas of "objects" can do what other module systems can do, but are "first class" in the sense that the can be created on the fly and passed around as values. This has to do with things like path-dependent types and being able to import from arbitrary object instances instead of just from static namespaces.
I don't think he's conflating modules with objects. He's saying that if you have (class-based) objects, you don't need modules because object classes already provide superset of the functionality of modules. In particular they provide open recursion, which is something he thinks you're going to want to have anyway.
I started off learning Scala in a 2 man band startup for 3 or so years and moving to a company with 20+ full time Scala developers was a huge eye opener. All the things that hooked me about Scala like taking advantage of its relatively un-opinionated structure to be quite expressive with how you build things turned out to be major pain points when you scale out into teams who rotate developers on frequent basis.
I think I'm paraphrasing something I read about Twitter when I say that everyone who uses Scala ends up taking a subset of the language they are happy with, and that ends up being the case at a team level and intra-person level too (starting at the new place ended up with some very frosty pair programming sessions).
Add to that the necessity to cross train every developer who joins because recruitment is hard enough without specifying experience in a relatively obscure language and you have a constant cycle of painful recruitment, on-boarding and maintenance.
Or C++. The whole "But you can only use a subset of the language if you want" part will particularly resonate with anyone who wrote C++ in the past couple of decades.
Every year I evaluate Scala for adoption. I'm a pragmatist, a polyglot, and usually never say no to seeing how things can improve my execution; which is why I chose to leave the door open for Scala.
And every year it doesn't make the cut for me (various reasons, probably well-known - complexity, compiler, tooling).
This is happening for the last, oh, 4-5 years now. Each year, I take away two weeks from my free time to try and force myself into it.
This year I made a special effort knowing that Spark and big companies adopted Scala. And it lucratively looks like data science is adopting Scala (or does it?).
Knowing LinkedIn is saying "enough" is a real breather for me. At this point, I can stop. Hopefully it will trigger a chain reaction, and leave Scala for the academics.
Sounds more like a JavaEE senior enterprise architect who was concerned that he needed to learn something new, and thankfully found a reason why he does not. :-)
You're welcome to view my github account (my nick = my handle) and judge if I am that person.
And now for feedback: the one thing that I don't miss is the Scala fanboys hateisms, such as that one. To improve as a platform, as a community, you must be willing to be open to opinions of others rather than mindlessly tag and bag honest opinions into stereotypes. When this comes into the Scala world, I'll give it another try.
"Knowing LinkedIn is saying "enough" is a real breather for me. At this point, I can stop. Hopefully it will trigger a chain reaction, and leave Scala for the academics."
You later speak of "hate" while justifying on the decision of one company your dismissal of a whole ecosystem. The chain reaction comment was tasteless and in no way looks like an opinion trying to make the platform better as a community.
If you don't like it, drop it.
Also FWIW in my experience with academics, most of them use Python, go figure.
-- EDIT
I don't usually reply to comments like this one but this time I could not resist. Sorry.
"The Play framework works with Java"...yeah so does Akka, Spark, etc but my experience is that it isn't first class support and many things are just tacked on for a Java API to underlying Scala constructs.
"slim down the amount of required tooling"...how? You can't even properly navigate the Play source code (e.g. "go to reference") without a Scala plugin (IntelliJ or Eclipse). And the libraries they use are still gonna carry around the big 'ol Scala runtime with them.
As a huge Scala fan, some of this fills me with apprehension.
Existentials should always be a last resort, so it's ok if their syntax is a bit cumbersome; I find the forSome style a lot less confusing in its implications (e.g. "why can't I add a String to a List[_ <: String]" is a common newcomer question) and it avoids confusion with higher-kinded types. So if anything I'd rather drop the List[_] syntax, and use List[T] forSome {type T} exclusively. (Eliminating existentials entirely would be nice, but they're needed for Java interop).
The dotty approach of replacing type parameters with type members fills me with fear. Type parameters are simple and reliable; type members are confusing and the compiler often needs more help to get them right. I can appreciate the desire to not have two features that overlap, but this is removing the feature that works well in favour of the feature that doesn't.
Monads for effects work really well, and the community is just starting to get a library stack together that makes them easy - look at e.g. http4s for where the grassroots innovation is. They're simple to reason about because they're just ordinary types following the ordinary rules, and we have a lot of library support for making them easy to work with. By contrast implicits are still the most confusing and error-prone part of the language - look at all the trouble people have with Future and ExecutionContext. The example given in the slideshow looks like a perfect use case for scalaz Kleisli. Rather than another specialized language feature, the truly scalalike solution would be to make it easier for "function literals" to have user-defined types - perhaps k{ body } to have body be promoted to a Kleisli, a la s"" interpolators.
Scala gets a lot right, and I don't think I'd ever be tempted away to Haskell - strictness and impurity are simply too useful. Some parts can't be changed - subtying is here to stay (and needed for interop), and much as I wish tuples could be replaced with HLists, they probably can't. That by itself is enough to leave room for a successor to eat Scala's lunch. But for now it's a brilliant language, fun and safe and commercially viable; I really do love the language, and a few of these things (union types) could make it even better. But too many of these ideas feel like missteps.
I'm not expert in any of this stuff, but reading that slide, I was kind of getting the impression that existential types and higher-kinded types are being unified, in the grand scheme of Dotty exploiting theoretical equivalences of previously separated concepts. Same with the type parameter/member thing. I think the idea is that syntax will support both options, as seen with the analogous introduction of the value parameter syntax for traits, but the underlying implementation will be abstract members. This seems like it will make writing type level code or interop code much simpler, because there's only one underlying implementation to worry about. But re-reading your comment, I think you agree with that benefit. Do you know why abstract members were chosen as the underlying implementation? Are they more general?
I agree that native HList functionality within tuples and case classes would be really huge for practical programming. It's a huge pain to abstractly define transformations over families of classes. It's awesome that Shapeless works, but more native support within the language could maybe help remove some of the challenge of actually using Shapeless.
> I think the idea is that syntax will support both options, as seen with the analogous introduction of the value parameter syntax for traits, but the underlying implementation will be abstract members.
Right; my problem here is that type inference handles type parameters fine and often doesn't handle type members without an explicit type. If the implementation is always type members that means we're always in the unpleasant case.
> Do you know why abstract members were chosen as the underlying implementation? Are they more general?
Yeah they are - there are some things you can't express as type parameters that you can express as type members. But there's value in making the simple case simple.
Ah gotcha. Well, can't the type inference just work the same as it does now, if you happen to use type parameters? And possibly, couldn't type inference that works in these cases be extended to type members? I would hope that this would be a side benefit of pushing towards more formal and unified underpinnings of surface features.
> Well, can't the type inference just work the same as it does now, if you happen to use type parameters?
I think it can only work with type parameters because they're constrained in what they can do. If type parameters compile down to type members, presumably there is no "marker" that says that that type member obeys those constraints - if there is then it wouldn't really be unification of type members and type parameters.
String was a poor example, let's make it "why can't I add a Long to a List[_ <: Number]". With the more verbose syntax "List[T] forSome {type T <: Number}" the issue becomes much more obvious IMO - T could e.g. be Float.
Aha, that makes more sense. I interpret a type like `List[_ <: Number]` as a list with any kind of elements, whereas `List[T] forSome {type T <: Number}` makes sense to be a list with a specific kind of elements, with the type of the elements constrained (of course, assuming that List is invariant).
Interestingly Scala 2.12 will have support for user defined types using function literals (it's actually in 2.11 behind a compiler flag). This feature is referred SAM (single abstract method) functions [1].
Also, there are plans to move tuples to something more like HLists. You can see it here[2] as part of 3 under 'Don Giovanni'.
Yeah, I know about SAM support. But that will only happen if the type is known, and type-annotating every short {} is a pretty big price. Or can I do something like:
myKleisli >=> {a => Option(a.toString)}
and have SAM figure out that that's another Kleisli?
Scala is a great language, I think it's far ahead of the curve compared to anything else out there (swift, rust, Java 8, Kotlin, Ceylon) in terms of being a useful functional / OO language with static typing.
One issue I have with it. I don't think it's complex, but I think people are not spending the right time learning it. People learn the subset of features they like and stay with it, and because there are so many ways to skin a cat with it, everyone have their own style. It could have benefit from the concept that other languages have of "there is always one best way to do things". I mean, on one hand I can write 20 lines of Java in 10 lines of Scala or less (and enjoy it 100X more) but I can do it in 1000X different ways.
We use scala on a company wide basis and even though everyone is very expressive, well, everyone is VERY expressive.
I think that if a company enforces strict scala style rules, best practices and sticks to it (using automatic style / structure rules that throw compile errors / warnings and need special care to turn off) than Scala can be a big asset to a company.
I'm sure there could have been a better solution to someone who needs a statically typed, OO/FP hybrid language that runs on the JVM. But currently Kotlin / Ceylon are not there for my taste. And the others, are either not JVM languages or not OO, or not statically typed.
There is a group of very passionate people in EPFL and TypeSafe and the scala community that don't follow Martin like a heard. there are at least 2 well known forks of Scala compiler, one large fork of scala collections (by one of Scala's greatest committers and also later greatest critique). Criticism is accepted and no one follows blindly around the founder's opinions (although I think he is doing a good job so far navigating it)
I mean, Scala is perhaps over-featured, perhaps can be a little complex if you use it to write libraries (until you spend some time actually learning it), perhaps it gives you too much strength, but even if it's experimental, academic, theoretical, then it's an experimental / academic / theoretical super fun language that I can actually use at work! how crazy is that? I think Scala is beautiful, a pure joy to use, and I'm so lucky I can use it instead of Java 8 or any other language in the world.
Until Kotlin / Ceylon is mature enough, Scala is the answer to anyone targeting the JVM and want a modern language. Clojure is cool and hip, but I find it much less productive personally, and much more complex, sorry, maybe I'm not smart enough (and, as I said, I prefer static typing)
If you are a Java developer and never tried it, don't believe the lies, Scala will grow on you. and unless you are a constant naysayer / devil's advocate, you'll never go back.
> One issue I have with it. I don't think it's complex, but I think people are not spending the right time learning it. People learn the subset of features they like and stay with it, and because there are so many ways to skin a cat with it, everyone have their own style. It could have benefit from the concept that other languages have of "there is always one best way to do things".
I think that's the dark side of having both the OO side and the FP side working well.
I'm not sure if I want something like OCaml, where everyone tells you to just ignore the OO part of the language.
---
I think the talk mentioned all the right things, and shows that the people in charge listen and address issues raised by the community.
Also, just look at the productivity. Which other language can claim that people work on a redesigned compiler, a new IR, a shared bytecode backend, and a rewritten macro engine at the same time, in addition to developing and evolving the current language, compiler and library?
Scala's clearly doomed...if the comments here hold water that is. Got a chuckle over a claim in this thread that OCaml and Haskell compile times are "lightning fast" compared to Scala -- wow, maybe OCaml, but Haskell, I mean, seriously, even Haskellers will raise their eyebrows with that claim...
There are some really really desperate people in this thread who keep posting this "the sky is falling!!!" type of claim in every Scala-related submission. :-)
> Haskell compile times are "lightning fast" compared to Scala -- wow, maybe OCaml, but Haskell, I mean, seriously, even Haskellers will raise their eyebrows with that claim...
As someone who just started using Scala coming from Haskell, scalac does seem much slower than ghc -O3 and tons slower than ghc -O0 or ghci.
I'm also very annoyed by not being able to load full scala source files into the repl because the package names at the top aren't valid for the repl.
Let me assure you, Scala is the nicest and most productive language I have ever used. Don't just assume that the naysayers are right, try it yourself (and please be fair and give it time) and you WILL love it.
I have seen people who were average Java programmers who were afraid (right to their bones) pick it up even if out of coercion rather than willingness :P and start to like it.
I don't understand why people suggest Java, Scala is better in every imaginable way. Also there maybe more than one ways to do things, but I don't get why that is a problem. Code comes from within a person like art and it's bound to be different. Don't the large projects always have different style? I don't see how sane code albeit written in different styles would become unmaintainable/unreadable.
I concur. I started out with all the usual preconceptions about Scala, "But it's too complex!", "The compiler is too slow", etc... (I was very into Clojure at the time, so that colored my vision a bit too)
I then made an honest attempt to learn the language and put it to use and I couldn't be happier with the outcome. It's such a productive language! the type-system is awesome, and really helps navigate from an idea to a solution, the ecosystem is stunning, with very high-quality projects for every use case you can think of. Just look at Spark, Finagle, ScalaZ, the various Typesafe projects...
Please people, don't be put off by the negativity parroted by many detractors. Give Scala a shot, you might be pleasantly surprised and end up with a very powerful tool on your side.
Compilation time - just to point one measurable advantage of java.
Also please remember that code is read much more often than it is written, so having many different ways to do single thing may not sound like a such good idea for people maintaining your code.
I agree that compilation is a lot slower but it's actually not that much for any practical use. In any case recompilations happen a lot more than from scratch compilations, which are fast.
Don't you agree that different styles will be there no matter what in any high level language? You will always find code written by other people to be different. Some comments make it look like the different styles feel like different languages but short of writing Java in Scala you won't find that to be the case.
I will agree that some codebases are slightly more complex but they are libraries and they are complex because they want me to have a nicer, richer API.
Scala is certainly worth studying for a bit (like most languages, I'd say), you should just not plan on being able to use it professionally (like most languages).
I studied Scala with the express intent of working professionally with Scala; then I went looking and found a job writing Scala. Its not an academic language at all.
If LinkedIn is any indication there is absolutely no shortage of open professional Scala positions.
Why are you so negative on Scala? Better yet, why are you so unequivocally negative on any programming language?
Like every language, Scala has strengths and weaknesses. It makes sense for some teams and not for others. Why don't we debate how its strengths and weaknesses can best be managed and understood rather than just pointing out one company that decided some aspect of the language didn't make sense for them.
When there's lack of objective direct information, the evidence of adoption or "churn" might be a good substitute: http://www.quora.com/Is-LinkedIn-getting-rid-of-Scala
Of course, it's difficult to judge LinkedIn's motives but it certainly raises valid questions and concerns.
There is objective and direct information. Study the language and it's libraries. Then look at your needs and make a judgement based on reason. There is no other way around this. You could look at other companies experience but then you would need a large sample size and detailed analysis of why they succeeded or failed. Using a sample size of one web company you might as well study the entrails of a dog and you will get the same results if you make technical decisions like this.
I actually had _no idea_ LinkedIn used Scala until I read further down this thread. I am referring to, of course, the large number of contact requests I receive from recruiters about open Scala positions.
The problem with Scala isn't productivity for a single developer or a small team, or a matter of how much you like it, but how productive it is in large teams. There are big problems of separate teams in the same company writing Scala code that the other teams can't understand, and arguments over style taking over most of the code reviews.
I'm in the midst of learning Scala, and I assure you I'm motivated to learn it.
However, at first pass, it appears to include all the worst aspects of Perl, Python, etc. The one thing I hate is when a language has multiple ways to do things, and you have to memorize them because it's not obvious. This is why I despise Perl with all my heart.
For example, the whole "class.function(x)" being equivalent to "class function x" annoys the hell out of me. Having _ as a overloaded magic symbol is another perlism that also annoys me. It either means the implied array member in a function OR it is used to tell the compile that you're passing in a function to a variable. I hate this. Why bother using the same magic symbol? There are a ton of other things about Scala like this that I hate because it's non-obvious and things you just have to memorize.
That said, I'm still motivated to learn it and understand Scala, but I'm worried I'm wasting my time.
> Having _ as a overloaded magic symbol is another perlism that also annoys me. It either means the implied array member in a function OR it is used to tell the compile that you're passing in a function to a variable. I hate this.
He's probably referring to the passing of partially applied functions. I've never quite understood why you need `_` as well: you are already defining your function with the strange Curry syntax (f(param1)(param2)), you shouldn't need to pass "f _" to tell the compiler that on top.
Being able to use dots and parenthesis or not has a very good reason for being: It makes the concept of operators disappear. In a custom class, a + b is the same as a.+(b), instead of doing it the Java way, where blessed Java libraries can do things that are impossible for my own extensions. The C++ way of supporting such a thing relies on very specific sequences of what can be an operator, and what cannot, making things actually harder.
At the cost of making writing in-language DSL easier, like the one in ScalaTest, the language lets people do really ugly things, if they don't like other people reading their code. It's a tradeoff. I like to be able to have an assertion that goes " myVal should contain("A")", and that be valid ScalaTest code, with very good error handling, but I see how others can disagree.
Undescore is overloaded in a few more ways that you are listing too, as a wild card in case statements and type definitions. My favorite is how we can turn a sequence into a vararg by using the Punched-In-The-Face operator, :_. That nonsense really means that we are providing a type annotation (:), and the actual type to use should be whatever it is(_), but as a vararg (). If you know the exact type, you could go : Int, but really, :_ works the same way.
Now, as you go through Scala, the darkest realization is not that it has too many features, but that it's possible reach a point where you think it doesn't have enough. I have spent most of the week bemoaning the fact that shapeless' HLists are not anywhere near as easy to use as I'd like because the type system needs even more power.
> I like to be able to have an assertion that
> goes "myVal should contain("A")", and that
> be valid ScalaTest code, with very good error
> handling, but I see how others can disagree.
This is so clearly a false economy! What you gain there in expressiveness you lose tenfold in ambiguity — and not just in that line, but in the latticework of exceptions you now have to keep suspended in your mind as you read every other line of code. It just doesn't make sense to me that you'd prefer things that way.
Funny to see people defending the complexity of the language in these comments. So very HN.
My perspective of dev'ing in scala since 2009 (and I love scala):
"Scala isn't that complicated, just takes some time to learn."
Scala is complicated. Like really potentially super complicated, and the compiler error messages can be hyper-cryptic. It was written by academics (versus "developers") and it shows.
New developers will end up asking someone else a basic language question about every 10 minutes, mostly because they don't even know what to google for.
I've been using it for years and I still have to lookup prepending versus appending to lists because I can't remember if it's x :+= y or x +:= y, let alone ::: versus :: versus ++ or ++=. Really? Why not #!:@## while we're at it?
It's crazy that in these slides he says "I wanted a hipster language" -- most languages use [] for arrays so I used (). WHY!!!!? Just to be different? No actual real advantage? That's a terrible reason and a great way to make it hard for new people to adopt your language.
It doesn't help that there are 50 ways to do the same thing and the language is totally agnostic as to what you should do. It's almost like being an alien, coming to Earth, and trying to learn to have sex with humans from someone who is bi-sexual and into every fetish there is.
---
It would be really great if they could canonicalize the language in the way that python has, and once having done so further simplify their syntax so mere mortals can use it effectively. Programming is hard enough without the language being difficult, too.
It's crazy that in these slides he says "I wanted a
hipster language" -- most languages use [] for arrays so I
used (). WHY!!!!? Just to be different? No actual real
advantage? That's a terrible reason and a great way to
make it hard for new people to adopt your language.
You might not get it, but the slide makes fun of knee-jerk reactions like those shown in your comment.
Scala does things for a good reason. Not caring to figure out the reason doesn't mean the language is wrong.
Care to point out the reason then? Not sure why you assumed I don't care to find out, especially given I've stated that I've been using Scala since 2009 and love the language.
It's () instead of [] because it's a regular function call. It's related to the scalability thing that Odersky also mentions (as much functionality in libraries as possible, rather than in the language).
I'm assuming it's to unify the `apply()` operation between collections (maps, sequences, arrays, etc). The collection library derives from a trait hierarchy, and an array is one of these collection types.
Not just between collections, but functions as a whole. An indexed sequenced is essentially a mapping (read: function) from the integers to whatever the element type is. Scala makes that explicit, rather than creating another mapping operator, as though they failed to notice the symmetry.
I would characterize this sort of thinking as one of the core principles of the language design. The designers search for underlying generality and bring it to the surface of the language. This can be a little frustrating at times, since humans aren't necessarily geared toward abstraction. But investment in understanding the abstractions pays off again and again.
The square brackets are used already for type parameters on types. I do think they are easier to read than angle brackets are, for some reason. There was some discussion on this point in the Rust community as well recently where it was noted several people found square brackets easier to read and wanted to emulate Scala here (and another group wanting emulate D, using () for both!).
Another reason is that an IndexedSeq is really itself a function (extends Function1), so the parens are literally function application, not some specially interpreted syntax for indexing.
When it comes to arrays, they use () to emphasize the fact that this is a function- arr(1) is arr.apply(1)- instead of directly accessing an element like other languages.
Scala makes sense and has a logic behind all its reasons, but sometimes it seems to go against convention for the sake of its own philosophy.
I love how this is the only thing that people seemed to comment on. And I appreciate everyone's suggestion of unifying function calls being a good thing plus other aesthetics.
>It's almost like being an alien, coming to Earth, and trying to learn to have sex with humans from someone who is bi-sexual and into every fetish there is.
compare that to Java - landing and learning how to do it in 16th century somewhere like Spain - engaging in that sinful activity in the most vanilla and least sensual way with only purpose of procreation and only when. Thanks God progress can't be stopped :)
Indeed. If you make something expressive then some people are going to express themselves in obtuse ways. There is no way out of that tradeoff. Of they don't have to share the code with anyone else then it's fine. But if you have a team and you don't code review for clarity then you are in trouble no matter what language you are using. The other thing is that the expressivity of Scala makes it actually possible to make your code even clearer.
> It's crazy that in these slides he says "I wanted a hipster language" -- most languages use [] for arrays so I used (). WHY!!!!? Just to be different? No actual real advantage? That's a terrible reason and a great way to make it hard for new people to adopt your language.
func<Future<List<Option<String>>>> vs func[Future[List[Option[String]]]]
>>func<Future<List<Option<String>>>> vs func[Future[List[Option[String]]]]
>Which one is easier on your eyes?
i don't get the joke here. Or are you seriously implying that one is in someway better than the other? (i'm curious as i've been in the industry for more than two decades, so my eyes just filter that crap automatically anyway)
Granted I'm biased as I'm primarily a scala dev these days but I've always preferred the square brackets over the angle brackets. At least for me it is actually more readable.
Angle brackets aren't even very readable, couple that with the fact that they are also OPERARTORS and you are looking at some major complexity in your parser to distinguish between bracket usage and operator usage (possible, but requires looking ahead, worse syntax errors).
> It's crazy that in these slides he says "I wanted a hipster language" -- most languages use [] for arrays so I used (). WHY!!!!? Just to be different? No actual real advantage? That's a terrible reason and a great way to make it hard for new people to adopt your language.
Parentheses for array and map access really bugged me until I grokked functors. They're really all doing the same thing, and the mathematical symmetry of using the same syntax for all of them is very pleasing.
:+= and +:= are very unidiomatic. No they're not banned entirely and maybe they should be, but I think that would make certain people even more upset. But what you're supposed to use is x :+ y and x +: y; with either one x ends up before y, and if you got them the wrong way around then it won't compile. Likewise ::: versus :: - if you get it wrong, it won't compile (at least if you're using wartremover and/or strict compiler flags. Again, it would be nice to remove these misfeatures entirely - but given how much fuss there is about enterprise use and backwards compatibility, Scala has chosen to put a lot of effort into ensuring that old code still compiles).
It's very rare that you'd need to read the difference between x :+ y and x +: y, or x :: y and x ::: y. All of those give very similar results (a list of x followed by y), so it's good that they look similar. If you know one and not the others, the very fact that they look similar is a big hint that they're doing something similar.
Prepend and append are very different. And you do need to know, because for many scala collections one is O(N) and the other is O(1) [1], plus the importance of knowing order.
The difference between x :: y and x ::: y could mean List(List(1), 2, 3) versus List(1, 2, 3).
> Prepend and append are very different. And you do need to know, because for many scala collections one is O(N) and the other is O(1) [1], plus the importance of knowing order.
You know the order, at least in idiomatic code; "x :+ y" x comes before y, "x +: y" x comes before y. (There's a misfeature where you can sometimes write x +: y as y +: x, but don't do that; use brackets if you need to (x +: y))
O(N) versus O(1) is sometimes important but it is a detail IMO; anyone who cared about the distinction would already be reading the code very carefully, it's precisely the sort of thing that a casual reader should be able to gloss over.
> The difference between x :: y and x ::: y could mean List(List(1), 2, 3) versus List(1, 2, 3).
Exactly. Which the type system will catch; if you're using wartremover that will be an immediate error (inferred type containing Any), if not then you'll see an error as soon as you try to actually use the result.
To me :+ versus +: isn't obvious compared to saying .prepend or .append, which is my point. I shouldn't have to look that up.
As far as :: versus :::, depending on type inference it can be a much more later error that is confusing. The type error messages are cryptic compared to what it could say. Worse, if you then take it and serialized it to JSON or something then you won't even get a compile error, so it may not be for a while that you even realize there's and error and that can be hard to trace down depending on your code.
I really am failing to see why you're defending this. It's like trying to defend programming without a debugger because you have printf. Why not make things clearer, always? Why can't error messages be easier to understand and more human friendly? Shouldn't that be the goal?
.prepend wouldn't be able to use the : magic; once you're used to it "x :+ y"/"x +: y" is more intuitive than "x append y"/"x prepend y" because in the first example x always ends up before y.
> As far as :: versus :::, depending on type inference it can be a much more later error that is confusing. The type error messages are cryptic compared to what it could say. Worse, if you then take it and serialized it to JSON or something then you won't even get a compile error
Which is why you should use wartremover and strict compile flags ( https://tpolecat.github.io/2014/04/11/scalac-flags.html ), so that won't happen. (It would be nice to make these things completely illegal by default, but not nice enough to break backward compatibility over)
> I really am failing to see why you're defending this. It's like trying to defend programming without a debugger because you have printf. Why not make things clearer, always? Why can't error messages be easier to understand and more human friendly? Shouldn't that be the goal?
I think people really underestimate the value of conciseness. The difference between a function or class that fits on one screen and one that doesn't is really huge. For commonly-used operations, I'd rather pay the upfront cost of learning the symbols and be able to read shorter code forever.
Of course there's a tradeoff, and I do think certain scala libraries lean too far to the symbolic side. Sometimes I like to think about a programming language that didn't allow any symbols (e.g. you'd write arithmetic like "(1 plus 2) times 3"). But the extra characters aren't free.
I used OCaml before switching to Scala professionally, and I must say I prefer Scala's type system. It makes almost no space for errors/mistakes when you do things conventionally, like putting types on public members.
The idea of cleaning up the syntax a bit (XML, procedure, etc..) is great, but I'm not sure to understand what's "A better treatment of effects" (slide 44)? What's intended?
There is some research going on how Scala can start checking and enforcing purity. Having an IO type constructor with the usual monadic convenience operations is one possibility, but people are actively looking into other approaches.
130 comments
[ 3.0 ms ] story [ 187 ms ] threadI get the impression that compiler preformance is being worked on, and is improving over time.
I consider it fair to expect the compiler to be slower when it's doing more heavy lifting, but it would definitely be nice to see the exponential blow-up on the tail curbed in future.
edit: To clarify, the numbers above were what Odersky claimed; I haven't verified them. The 1 line/minute was claimed of trying to build Shapeless - I've never seen anything approaching that in the wild.
I get that that's an upper limit, but that's still pretty shocking. Is there an overarching reason for this type of performance? Examples of this style of code?
https://michid.wordpress.com/2010/01/29/scala-type-level-enc...
I can't comment on the details, I'm more of of Clojure guy.
[1] https://github.com/scalaz/scalaz/blob/series/7.2.x/core/src/...
The main reason why Scala is slow is because the compiler is poorly written. Take a look at the articles from Paul Phillips, one of the Typesafe cofounders who left the company in frustration, he's probably the person who knows scalac the best and he says the code base is basically hopeless.
Note that 1/3rd of Martin's presentation is about Dotty, and that's basically where he spends most of his time these days, he hardly contributes to Scala any more [1].
[1] https://twitter.com/odersky/status/574665768484339713
It took only one sentence to show that you never used OCaml or Haskell, so I'm not sure how serious the rest of your claims should be taken.
Yes, but OCaml doesn't "offer very similar functionalities".
Haskell is quite a bit slower if you consider that you often have to compile not only your own code, but also the sources of your dependencies in the beginning. Additionally, you have to fight with Cabal, which tends to be very unpleasant due to the lack of any reasonable support for exotic things like "versions". Then you might discover hacks like "sandboxing". Hours not spent coding.
[edit: the bug is not in the scala compiler, the bug is in my code - I almost certainly did not want `f` to have type `Int => Any`. My phrasing, now edited, was misleading. ]
scala> def f(x: Int): Option[Int] = if (x % 2 == 0) { x } else { None } <console>:7: error: type mismatch; found : Int required: Option[Int] def f(x: Int): Option[Int] = if (x % 2 == 0) { x } else { None }
A language that supports union types (e.g. Ceylon) will type this expression as Int|Option[Int], which is as specific as you can get.
Option[Int] is simply an alias to the type Int | Null, so Int | Option[Int] would become Int | Int | Null after replacement, which simplifies to Int | Null since Int | Int is equivalent to just Int.
The gist is that once you have [edit: recursive] typeclasses or implicits your search can become arbitrarily large and slow. There's nothing that can be done about it by the compiler except arbitrarily pruning the search tree. Or otherwise put, you should factor in implicit search complexity when designing your libraries.
edit: reworded for clarity
Theoretically, there is nothing stopping you from writing code which will never finish compiling if you have a Turing-complete typesystem.
let f0 = fun x -> ( x, x ) in let f1 = fun y -> f0( f0 y ) in let f2 = fun y -> f1( f1 y ) in let f3 = fun y -> f2( f2 y ) in let f4 = fun y -> f3( f3 y ) in let f5 = fun y -> f4( f4 y ) in f5 ( fun z -> z );;
took at least 3 months (!) to type-infer when I ran it on my 2008 MacBook using the standard Ocaml compiler. I have not tried since. Type inference algorithms have horrendous worst-case complexity. Fortunately that worst-case complexity usually doesn't matter in practise.
Anyway, details aside I thought it was a great illustration of the impact on compiler performance that code complexity can have.
"Objects done well provide a lightweight module system (in the sense of ML). The requirement for a good module system is something that's often overlooked when all you do is a simple application, but its lack becomes painfully apparent for large systems and systems that are maintained over time. You can go the SML route and provide a module system and a functional core language. But then there's the pressure that you want to generalize your modules to be more flexible, which means you want them to become recursive and first-class. If you do that, you end up with a de-facto object system in addition to your core language of algebraic data types and functions. Scala's approach of unifying modules and objects is more parsimonious: The same constructs define the core language and the module language. So Scala is simpler, in the sense that fewer concepts are needed to describe the total feature set."
Others have already commented on this, and I have nothing more to add, but I do find myself doubtful about whether the "Scala is simpler" is justified. Scala has always been multi-paradigm, so I don't think of it as simple -- and, again, that can be a strength or a weakness. I'm reflecting on what was written here: http://scala-programming-language.1934581.n4.nabble.com/OOP-...
In MLs, in large part to ensure that HM-style type inference remains "complete", the module type language is stratified from the value type language. This feels a bit repetitive, causes slow expansion of flexibility and power in the module language, and makes it difficult to refer to modules dynamically.
For some, these are all good things. In this point of view, modules are "large" in a way that makes them difficult to reason about and so the restrictive language they're manipulated with is vital for making them reasonable.
For others, you might as well just unify the "large" module language and the "small" value language. If you do this carefully you might not even lose "complete" HM inference [0].
This is the path that Scala takes though it unabashedly tosses out HM inference for the a highly incomplete (e.g. "local") subtype/supertype logic.
Now there's a bit of an assertion that floats around that Scala's objects are essentially equal in power to what ML's modules would be if they were first class. I'm not sure if anyone could quite make this formal prior to the core calculus clean-up that is going through with dotty. Perhaps after that point the unique features of Scala will be emphasized... or we'll truly determine that Scala is just a unique approach to ML modules which has a different type inference engine.
[0] http://www.mpi-sws.org/~rossberg/1ml/
They seem related to me though. Open recursion requires calling the method from the final subtype rather than the current type - `even` would have to call `this#odd` instead of `odd`. The core problem in both cases is not being able to refer to the final subtype in any way.
Hmmm, even if modules could refer to this final subtype you would probably have to choose between doing it via dynamic dispatch or sacrificing separate compilation, since the parent module doesn't know what method to dispatch to at the time of compilation.
[0] http://stackoverflow.com/questions/23006951/encoding-standar...
I cannot weigh in with regards to Haskell, but in the case of Erlang this actually isn't all that odd. The actor model is to a large extent an object system for modelling concurrency - this being per Alan Kay's definition of OO as isolated units that communicate via message passing, as opposed to the more common definition of polymorphism/encapsulation/inheritance, which in practice is usually a quasi-procedural sugar coating.
Admittedly this does neglect some of the more detailed Smalltalk properties like class objects holding shared state, but the terminology behind OO is murky and Erlang exhibiting elements of it can nonetheless be argued.
- Joe Armstrong
http://www.infoq.com/interviews/johnson-armstrong-oop
http://www.quora.com/Why-is-LinkedIn-getting-rid-of-Scala
I think I'm paraphrasing something I read about Twitter when I say that everyone who uses Scala ends up taking a subset of the language they are happy with, and that ends up being the case at a team level and intra-person level too (starting at the new place ended up with some very frosty pair programming sessions).
Add to that the necessity to cross train every developer who joins because recruitment is hard enough without specifying experience in a relatively obscure language and you have a constant cycle of painful recruitment, on-boarding and maintenance.
And this argument is nonsense.
Edit: Looks like zak_mc_kracken beat me to it. Which I think just makes the point even more obvious
Every year I evaluate Scala for adoption. I'm a pragmatist, a polyglot, and usually never say no to seeing how things can improve my execution; which is why I chose to leave the door open for Scala.
And every year it doesn't make the cut for me (various reasons, probably well-known - complexity, compiler, tooling).
This is happening for the last, oh, 4-5 years now. Each year, I take away two weeks from my free time to try and force myself into it.
This year I made a special effort knowing that Spark and big companies adopted Scala. And it lucratively looks like data science is adopting Scala (or does it?).
Knowing LinkedIn is saying "enough" is a real breather for me. At this point, I can stop. Hopefully it will trigger a chain reaction, and leave Scala for the academics.
And now for feedback: the one thing that I don't miss is the Scala fanboys hateisms, such as that one. To improve as a platform, as a community, you must be willing to be open to opinions of others rather than mindlessly tag and bag honest opinions into stereotypes. When this comes into the Scala world, I'll give it another try.
You later speak of "hate" while justifying on the decision of one company your dismissal of a whole ecosystem. The chain reaction comment was tasteless and in no way looks like an opinion trying to make the platform better as a community.
If you don't like it, drop it.
Also FWIW in my experience with academics, most of them use Python, go figure.
-- EDIT
I don't usually reply to comments like this one but this time I could not resist. Sorry.
I think criticizing something that you decide not to use is pretty valid, doesn't justify an ad-hominem attack, and certainly doesn't count as "hate".
He's not hating Scala, he's just desperate selling his 5 years out of date opinion about it on every occasion he can find.
"slim down the amount of required tooling"...how? You can't even properly navigate the Play source code (e.g. "go to reference") without a Scala plugin (IntelliJ or Eclipse). And the libraries they use are still gonna carry around the big 'ol Scala runtime with them.
Existentials should always be a last resort, so it's ok if their syntax is a bit cumbersome; I find the forSome style a lot less confusing in its implications (e.g. "why can't I add a String to a List[_ <: String]" is a common newcomer question) and it avoids confusion with higher-kinded types. So if anything I'd rather drop the List[_] syntax, and use List[T] forSome {type T} exclusively. (Eliminating existentials entirely would be nice, but they're needed for Java interop).
The dotty approach of replacing type parameters with type members fills me with fear. Type parameters are simple and reliable; type members are confusing and the compiler often needs more help to get them right. I can appreciate the desire to not have two features that overlap, but this is removing the feature that works well in favour of the feature that doesn't.
Monads for effects work really well, and the community is just starting to get a library stack together that makes them easy - look at e.g. http4s for where the grassroots innovation is. They're simple to reason about because they're just ordinary types following the ordinary rules, and we have a lot of library support for making them easy to work with. By contrast implicits are still the most confusing and error-prone part of the language - look at all the trouble people have with Future and ExecutionContext. The example given in the slideshow looks like a perfect use case for scalaz Kleisli. Rather than another specialized language feature, the truly scalalike solution would be to make it easier for "function literals" to have user-defined types - perhaps k{ body } to have body be promoted to a Kleisli, a la s"" interpolators.
Scala gets a lot right, and I don't think I'd ever be tempted away to Haskell - strictness and impurity are simply too useful. Some parts can't be changed - subtying is here to stay (and needed for interop), and much as I wish tuples could be replaced with HLists, they probably can't. That by itself is enough to leave room for a successor to eat Scala's lunch. But for now it's a brilliant language, fun and safe and commercially viable; I really do love the language, and a few of these things (union types) could make it even better. But too many of these ideas feel like missteps.
I agree that native HList functionality within tuples and case classes would be really huge for practical programming. It's a huge pain to abstractly define transformations over families of classes. It's awesome that Shapeless works, but more native support within the language could maybe help remove some of the challenge of actually using Shapeless.
Right; my problem here is that type inference handles type parameters fine and often doesn't handle type members without an explicit type. If the implementation is always type members that means we're always in the unpleasant case.
> Do you know why abstract members were chosen as the underlying implementation? Are they more general?
Yeah they are - there are some things you can't express as type parameters that you can express as type members. But there's value in making the simple case simple.
I think it can only work with type parameters because they're constrained in what they can do. If type parameters compile down to type members, presumably there is no "marker" that says that that type member obeys those constraints - if there is then it wouldn't really be unification of type members and type parameters.
Can you explain this, or point to a source that does?
Also, there are plans to move tuples to something more like HLists. You can see it here[2] as part of 3 under 'Don Giovanni'.
[1] - https://typesafe.com/blog/scala-211-has-arrived [2] - http://www.scala-lang.org/news/roadmap-next
edit - I think the need for explicit types for each SAM was fixed by https://issues.scala-lang.org/browse/SI-8310
One issue I have with it. I don't think it's complex, but I think people are not spending the right time learning it. People learn the subset of features they like and stay with it, and because there are so many ways to skin a cat with it, everyone have their own style. It could have benefit from the concept that other languages have of "there is always one best way to do things". I mean, on one hand I can write 20 lines of Java in 10 lines of Scala or less (and enjoy it 100X more) but I can do it in 1000X different ways.
We use scala on a company wide basis and even though everyone is very expressive, well, everyone is VERY expressive.
I think that if a company enforces strict scala style rules, best practices and sticks to it (using automatic style / structure rules that throw compile errors / warnings and need special care to turn off) than Scala can be a big asset to a company.
I'm sure there could have been a better solution to someone who needs a statically typed, OO/FP hybrid language that runs on the JVM. But currently Kotlin / Ceylon are not there for my taste. And the others, are either not JVM languages or not OO, or not statically typed.
There is a group of very passionate people in EPFL and TypeSafe and the scala community that don't follow Martin like a heard. there are at least 2 well known forks of Scala compiler, one large fork of scala collections (by one of Scala's greatest committers and also later greatest critique). Criticism is accepted and no one follows blindly around the founder's opinions (although I think he is doing a good job so far navigating it)
I mean, Scala is perhaps over-featured, perhaps can be a little complex if you use it to write libraries (until you spend some time actually learning it), perhaps it gives you too much strength, but even if it's experimental, academic, theoretical, then it's an experimental / academic / theoretical super fun language that I can actually use at work! how crazy is that? I think Scala is beautiful, a pure joy to use, and I'm so lucky I can use it instead of Java 8 or any other language in the world. Until Kotlin / Ceylon is mature enough, Scala is the answer to anyone targeting the JVM and want a modern language. Clojure is cool and hip, but I find it much less productive personally, and much more complex, sorry, maybe I'm not smart enough (and, as I said, I prefer static typing)
If you are a Java developer and never tried it, don't believe the lies, Scala will grow on you. and unless you are a constant naysayer / devil's advocate, you'll never go back.
I think that's the dark side of having both the OO side and the FP side working well.
I'm not sure if I want something like OCaml, where everyone tells you to just ignore the OO part of the language.
---
I think the talk mentioned all the right things, and shows that the people in charge listen and address issues raised by the community.
Also, just look at the productivity. Which other language can claim that people work on a redesigned compiler, a new IR, a shared bytecode backend, and a rewritten macro engine at the same time, in addition to developing and evolving the current language, compiler and library?
As someone who just started using Scala coming from Haskell, scalac does seem much slower than ghc -O3 and tons slower than ghc -O0 or ghci.
I'm also very annoyed by not being able to load full scala source files into the repl because the package names at the top aren't valid for the repl.
I have seen people who were average Java programmers who were afraid (right to their bones) pick it up even if out of coercion rather than willingness :P and start to like it.
I don't understand why people suggest Java, Scala is better in every imaginable way. Also there maybe more than one ways to do things, but I don't get why that is a problem. Code comes from within a person like art and it's bound to be different. Don't the large projects always have different style? I don't see how sane code albeit written in different styles would become unmaintainable/unreadable.
I then made an honest attempt to learn the language and put it to use and I couldn't be happier with the outcome. It's such a productive language! the type-system is awesome, and really helps navigate from an idea to a solution, the ecosystem is stunning, with very high-quality projects for every use case you can think of. Just look at Spark, Finagle, ScalaZ, the various Typesafe projects...
Please people, don't be put off by the negativity parroted by many detractors. Give Scala a shot, you might be pleasantly surprised and end up with a very powerful tool on your side.
Don't you agree that different styles will be there no matter what in any high level language? You will always find code written by other people to be different. Some comments make it look like the different styles feel like different languages but short of writing Java in Scala you won't find that to be the case.
I will agree that some codebases are slightly more complex but they are libraries and they are complex because they want me to have a nicer, richer API.
If LinkedIn is any indication there is absolutely no shortage of open professional Scala positions.
Like every language, Scala has strengths and weaknesses. It makes sense for some teams and not for others. Why don't we debate how its strengths and weaknesses can best be managed and understood rather than just pointing out one company that decided some aspect of the language didn't make sense for them.
However, at first pass, it appears to include all the worst aspects of Perl, Python, etc. The one thing I hate is when a language has multiple ways to do things, and you have to memorize them because it's not obvious. This is why I despise Perl with all my heart.
For example, the whole "class.function(x)" being equivalent to "class function x" annoys the hell out of me. Having _ as a overloaded magic symbol is another perlism that also annoys me. It either means the implied array member in a function OR it is used to tell the compile that you're passing in a function to a variable. I hate this. Why bother using the same magic symbol? There are a ton of other things about Scala like this that I hate because it's non-obvious and things you just have to memorize.
That said, I'm still motivated to learn it and understand Scala, but I'm worried I'm wasting my time.
I have no idea what you are talking about.
At the cost of making writing in-language DSL easier, like the one in ScalaTest, the language lets people do really ugly things, if they don't like other people reading their code. It's a tradeoff. I like to be able to have an assertion that goes " myVal should contain("A")", and that be valid ScalaTest code, with very good error handling, but I see how others can disagree.
Undescore is overloaded in a few more ways that you are listing too, as a wild card in case statements and type definitions. My favorite is how we can turn a sequence into a vararg by using the Punched-In-The-Face operator, :_. That nonsense really means that we are providing a type annotation (:), and the actual type to use should be whatever it is(_), but as a vararg (). If you know the exact type, you could go : Int, but really, :_ works the same way.
Now, as you go through Scala, the darkest realization is not that it has too many features, but that it's possible reach a point where you think it doesn't have enough. I have spent most of the week bemoaning the fact that shapeless' HLists are not anywhere near as easy to use as I'd like because the type system needs even more power.
My perspective of dev'ing in scala since 2009 (and I love scala):
"Scala isn't that complicated, just takes some time to learn."
Scala is complicated. Like really potentially super complicated, and the compiler error messages can be hyper-cryptic. It was written by academics (versus "developers") and it shows.
New developers will end up asking someone else a basic language question about every 10 minutes, mostly because they don't even know what to google for.
I've been using it for years and I still have to lookup prepending versus appending to lists because I can't remember if it's x :+= y or x +:= y, let alone ::: versus :: versus ++ or ++=. Really? Why not #!:@## while we're at it?
It's crazy that in these slides he says "I wanted a hipster language" -- most languages use [] for arrays so I used (). WHY!!!!? Just to be different? No actual real advantage? That's a terrible reason and a great way to make it hard for new people to adopt your language.
It doesn't help that there are 50 ways to do the same thing and the language is totally agnostic as to what you should do. It's almost like being an alien, coming to Earth, and trying to learn to have sex with humans from someone who is bi-sexual and into every fetish there is.
---
It would be really great if they could canonicalize the language in the way that python has, and once having done so further simplify their syntax so mere mortals can use it effectively. Programming is hard enough without the language being difficult, too.
Scala does things for a good reason. Not caring to figure out the reason doesn't mean the language is wrong.
I would characterize this sort of thinking as one of the core principles of the language design. The designers search for underlying generality and bring it to the surface of the language. This can be a little frustrating at times, since humans aren't necessarily geared toward abstraction. But investment in understanding the abstractions pays off again and again.
Another reason is that an IndexedSeq is really itself a function (extends Function1), so the parens are literally function application, not some specially interpreted syntax for indexing.
Scala makes sense and has a logic behind all its reasons, but sometimes it seems to go against convention for the sake of its own philosophy.
But does that mean everyone agrees with the rest?
compare that to Java - landing and learning how to do it in 16th century somewhere like Spain - engaging in that sinful activity in the most vanilla and least sensual way with only purpose of procreation and only when. Thanks God progress can't be stopped :)
func<Future<List<Option<String>>>> vs func[Future[List[Option[String]]]]
Which one is easier on your eyes?
>Which one is easier on your eyes?
i don't get the joke here. Or are you seriously implying that one is in someway better than the other? (i'm curious as i've been in the industry for more than two decades, so my eyes just filter that crap automatically anyway)
func(Future(List(Option(String))))
Parentheses for array and map access really bugged me until I grokked functors. They're really all doing the same thing, and the mathematical symmetry of using the same syntax for all of them is very pleasing.
Prepend and append are very different. And you do need to know, because for many scala collections one is O(N) and the other is O(1) [1], plus the importance of knowing order.
The difference between x :: y and x ::: y could mean List(List(1), 2, 3) versus List(1, 2, 3).
[1] http://docs.scala-lang.org/overviews/collections/performance...
You know the order, at least in idiomatic code; "x :+ y" x comes before y, "x +: y" x comes before y. (There's a misfeature where you can sometimes write x +: y as y +: x, but don't do that; use brackets if you need to (x +: y))
O(N) versus O(1) is sometimes important but it is a detail IMO; anyone who cared about the distinction would already be reading the code very carefully, it's precisely the sort of thing that a casual reader should be able to gloss over.
> The difference between x :: y and x ::: y could mean List(List(1), 2, 3) versus List(1, 2, 3).
Exactly. Which the type system will catch; if you're using wartremover that will be an immediate error (inferred type containing Any), if not then you'll see an error as soon as you try to actually use the result.
As far as :: versus :::, depending on type inference it can be a much more later error that is confusing. The type error messages are cryptic compared to what it could say. Worse, if you then take it and serialized it to JSON or something then you won't even get a compile error, so it may not be for a while that you even realize there's and error and that can be hard to trace down depending on your code.
I really am failing to see why you're defending this. It's like trying to defend programming without a debugger because you have printf. Why not make things clearer, always? Why can't error messages be easier to understand and more human friendly? Shouldn't that be the goal?
> As far as :: versus :::, depending on type inference it can be a much more later error that is confusing. The type error messages are cryptic compared to what it could say. Worse, if you then take it and serialized it to JSON or something then you won't even get a compile error
Which is why you should use wartremover and strict compile flags ( https://tpolecat.github.io/2014/04/11/scalac-flags.html ), so that won't happen. (It would be nice to make these things completely illegal by default, but not nice enough to break backward compatibility over)
> I really am failing to see why you're defending this. It's like trying to defend programming without a debugger because you have printf. Why not make things clearer, always? Why can't error messages be easier to understand and more human friendly? Shouldn't that be the goal?
I think people really underestimate the value of conciseness. The difference between a function or class that fits on one screen and one that doesn't is really huge. For commonly-used operations, I'd rather pay the upfront cost of learning the symbols and be able to read shorter code forever.
Of course there's a tradeoff, and I do think certain scala libraries lean too far to the symbolic side. Sometimes I like to think about a programming language that didn't allow any symbols (e.g. you'd write arithmetic like "(1 plus 2) times 3"). But the extra characters aren't free.
The idea of cleaning up the syntax a bit (XML, procedure, etc..) is great, but I'm not sure to understand what's "A better treatment of effects" (slide 44)? What's intended?
There is some research going on how Scala can start checking and enforcing purity. Having an IO type constructor with the usual monadic convenience operations is one possibility, but people are actively looking into other approaches.