Scala – The good, the bad and the very ugly
slideshare.net
slideshare.net
Specifically:
- Code on slide 3 has typos. (Yeah, that's minor)
- Lambdas are slower than Java 8 -- that's because Scala currently supports Java 6+. Java 8 has been released for 6 months. This is a ridiculous complaint.
- Heavy in terms of concepts -- another ridiculous complaint. If you want to keep on writing Java, keep writing Java. If Scala didn't bring new stuff to the table it wouldn't be interesting.
- Implicits -- agreed they can be misused. Type classes are the way forward.
- I don't understand many of the "very ugly" complaints. Yes, collections have lots of methods. Is this surprising? Yes, library code may be written in an abstract way. So what? Yes, DSLs look like DSLs. Yes, abstracting over arity is a problem in all statically typed languages. etc.
There are valid complaints to be made about Scala. I feel this talk demonstrates a lack of understanding of the language, and many of its complaints are in fact misunderstandings.
To me the biggest issue this talk reveals is that if you come from an OO background (which I assume the author does) then learning Scala will require a change of mindset. I don't think it is fair to make this a language complaint though. Scala makes it fairly obvious what you're getting yourself into and, as I said above, if you wanted to keep on writing code the way you have in the past it's not clear why you are using Scala in the first place.
Ah! But that’s the point, because Scala is pulling a bait-and-switch. If it were only a modern statically typed language I wouldn’t complain so much about it (and I really do complain a lot about Scala, I guess). Yes, I find its gaudy indiscrimination aesthetically unpleasing[1], but that’s a matter of personal taste. The problem is that Scala still markets itself as “a better Java”, and people are drawn to it so they wouldn't have to write getters and constructors. And at first, Scala does seem to be that. Only after a while you realize that it’s a whole other beast altogether — not necessarily the one you bought into. If Scala were marketed as “a JVM language Haskellers can learn to live with”, I’d have no issue with it (except the aesthetics, that is :)).
[1]: Yet, with its near-infinite list of features it can't even type immutability, which even Java 8 can through its pluggable type systems.
I am broadly agreed with you. Scala could do with trimming, and I'm optimistic that both Typelevel and Typesafe will accomplish this in the near future.
So abstract classes are the unnecessary bits in Scala? :) Choosing to do it all at once shouldn't surprise you as it's kind of Scala's modus operandi. I would say no single language needs algebraic types and inheritance and structural types and dynamics (and implicits and macros).
The deal with the devil Scala made, IMO, is when it tried to be both a research language and an industry language at the same time (Java interoperability is but a small part of this deal) without realizing that what's good for research (many different ways of doing things) is often bad for industry.
It's the Las Vegas of languages: gaudy and confusing, but if you look at just a tiny part of it and squint, for a second you can convince yourself you're in Paris.
It will be interesting to see what Scala is like in a couple of years. I think (hope) many of the issues will be resolved. Just going over the list you give:
- Implicits are useful. Implicit conversions, the evil part of implicits, are mostly going away via deprecation and other mechanisms.
- Structural types might go away if higher kinds are curried, or there is syntax for partially applying a higher kind.
- Dynamics. Who uses this? Why was it even added? I'd nuke it in a second but I don't know of any plans to remove it.
- Macros aren't even officially in the language yet, so it's a bit early to call for their removal :)
Ultimately is comes down to implementations. The idea of statically typed FP inspired languages has been around forever, but the implementations just haven't been up to scratch. Where are the alternatives to Scala (that is, statically typed, run on the JVM)? Things like Kotlin etc. are still in development and don't really offer much over Java. It might be in 5 years that Rust has a sufficient ecosystem to make it a viable alternative to the JVM. I think a lot of big data systems (in the area of Cassandra / Kafka / Hadoop) projects would happily move over to Rust, just to avoid GC issues. Haskell is the other alternative with traction, but it's an even further leap for most developers so I'm not convinced.
We do know that FP does allow for more general abstractions, but those usually come at a cost. They are harder for people to understand, and frankly, haven't been proven to increase code quality and maintainability. Yes, they're elegant like mathematical equations, but equations don't need to be changed and maintained by large teams of people over many years. A language like Haskell gives you more tools to think of your program ahead of time at the expense of thinking about it when it runs (with a debugger, profiler etc.), and I'm not sure that's the tradeoff the industry should make. Math is a great tool, but I'd learn how to catch a ball a lot faster by trial and error, then by learning how to rigorously compute its trajectory.
I think people in the industry should wait for more evidence of the utility of the more advanced FP concepts before rushing to adopt them. Of course, that doesn't mean people should be working on novel approaches and trying them. But my problem with Scala is that it is really a research language that tries different unproven approaches (and that answers pretty much all your questions about why certain features were ever included -- that and the non discriminating taste of its designers). But it's dangerous because it tricks people into thinking it's something else.
The worst thing about Scala seems to be that the community always have to deal with a single nutjob on Jihad, first Harrop, then Colebourne, then Beust, now that guy.
now I'm wondering - does Clojure then suffer the same crufting? or it's less interoperable?
Update: reading the Clojure docs, the main issue I see is compiling Java code against Clojure code. Clojure has a number of constructs for calling Java code and creating Java objects, but it's not clear to me how you define an API in Clojure that Java code can then call.
Well, you made me laugh. :)
But the real deal is compiling stuff to JVM bytecode ahead of time, which Java code can then be compiled against. It's not clear to me that Clojure provides this, which is what I was getting at.
As for the misunderstandings - the "bad" parts are ..bad. The ugly parts may not be bad, but are ugly (which is subjective, and I think it's implied it's subjective)
Slide 8
- Compiler too slow. A common complaint. Agreed it could be faster.
- Ecosystem. Don't really get the point here. Yes, Scala has different idioms to Java, so naturally Java libraries don't make for idiomatic Scala code. There are many mature Scala libraries. Binary incompatibility has not been a problem for me in at least two years, and it is a necessary artifact of Scala compiling a language that is not Java to JVM bytecode.
- Lambdas I addressed above.
Slide 9
Don't know what point you're making here.
Slide 10
Mostly addressed above. Syntax doesn't bother me. There are regular rules and the alternatives are a consequence of those regular rules. Would consider removing eta-expansion. Never had an issue with any of the rules though.
Slide 11
See above.
Slide 12
See above on type classes.
Slide 13
This is very generic. Applies to all languages.
Slide 14-15
Don't really get it. You can write code in many different ways. Applies to all languages.
Slide 16
This is very generic. Applies to all languages.
Slide 17
Don't get the point you're trying to make with this code.
Slide 18
This is presumably a slide that summarises this section. Without hearing what you have to say here I can't really interpret this.
Perhaps "very ugly" refers to method names like "/:". (Example on slide 22. There are many more examples of "very ugly" in that slide, too.)
This reflects on the culture, not the language, but it means in practice you will need to read lots of code with random punctuation used for method and function names. Unless you never use any libraries and never work with other Scala developers who write code like this.
In my two or so years of Scala I've yet to see anyone actually use /: or similarly named methods, and if they did I would make sure it never gets past a code review. Yes, the methods are still there, but in my experience people avoid them (even Odersky thinks they were a bad idea), and libraries with a lot of symbolic methods (Scalaz, and everyone's favorite whipping boy, Dispatch) are not particularly mainstream.
So my experience at least has been the opposite of what you assert. I would instead say that "... in practice you will NOT need to read lots of code with random punctuation used for method and function names."
True, the IDEs are poor, for a certain definition of poor. Had I not used IntelliJ for Java, for example, I'd find IntelliJ for Scala amazing. Knowing how much better it can be spoiled me, but frankly, IntelliJ for Scala is not bad. It just could be better. Also, Emacs has a very robust Scala mode.
True, there's a lot to learn before you can consider yourself fully fluent. You do not need to know everything, however. And once you've started on the path, things tend to flow naturally. For example, implicit conversions are easy to grasp. Once you understand them, implicit parameters and type classes are not much more complicated. Once you know type classes, it opens the door to a lot of functional "design patterns" - functors, applicatives, monads... these are not strictly necessary, but they're fun to learn about. And they teach you algebraic data types, which in Scala means case classes, sealed traits, ... it all sort of flows naturally.
True, it's easy to write absolutely un-maintainable code. While that's true of any language, Scala makes it rather easier than most. It's also very easy to write highly maintainable, legible code, and to avoid complex, ascii art based operators (or at the very least to offer wordy equivalences at 0 cost through `@inline`). I feel that saying "it can be hard to read, if you don't follow basic guidelines" is a bad reason not to use a language. A good reason to be careful, though.
My personal experience is that, once you start feeling comfortable with the language, you get much more productive than with Java. It does require some initial work, though: if all you know is OO, learning how to design your code for composition rather than inheritance takes a while - it takes a while just to realise that it's not a bad idea, let alone embrace it!
Also, ScalaCheck. Man, do I wish there was a good Java equivalent for some of my legacy code (that would not require me to rewrite all of my tests).
You can write perfectly readable Scala. It just takes some taste and common sense, or alternatively follow guidelines such as: http://twitter.github.io/effectivescala/
We've found IntellJ + Scala to be an excellent combo for our purposes.
I agree that as far as real IDEs go, IntelliJ is the best - but that's not saying much. The rest are pretty awful. They all do many things poorly, whereas Sublime does a few things very well.
Regarding IDE support, which inevitably comes up when discussing Scala, an honest question: what are good IDEs for Ruby, Python, Clojure, JavaScript, Haskell, OCaml? Is there a good IDE for C++ besides Windows-only Visual Studio? For C? It seems that Scala always get compared to Java in that domain, but in my experience Java is the exception, not the norm.
(Edit: I assume support for CLR languages is great too?)
Ruby: RedMine/IntelliJ
Python: PyCharm/IntelliJ
Clojure: Cursive/IntelliJ
JavaScript: IntelliJ + all JetBrains IDEs
Haskell: Dunno
OCaml: Dunno
Is there a good IDE for C++ besides Windows-only Visual Studio?: CIDR undoubtedly will be, but it's still in beta right now.
For C: AppCode
Seriously, JetBrains just make fantastic IDEs.I could go on and list a number of features that Scala typesystem supports natively which C++ does not (e.g. type bounds, path dependent types, variance control, existentials, abstract types...), but there is no need to do that.
There is one much bigger difference between them: C++ templates are not a first-class citizen of the C++ type system. They are just a (turing complete, but quite limited) macro-language bolted on top. Actually the compiler does not perform any typechecking of generic code. All the typechecking happens after macro expansion when generics are gone, and the typechecker needs to understand only concrete types. This is completely different than in Scala/Haskell/F#/C#/Java/OCaml typesystems, which can reason about generic types and can fully type-check generic code.
I've never seen a C++ IDE that could fully type-check template-heavy library code before its actually used beyond just syntax checking and limited type-checking the non-generic types. This is something that can't be done just because of how C++ templates are specified ("duck-typing"), not due to an implementation detail in the compiler/IDE. This is also the reason why good error-messages from templates are so hard to make - type errors are detected at the concrete level (late), not at the generic level (early). This is going to change when C++ finally gets "concepts" and will be able to reason about generic types (but this would be still a very long way to something like Haskell or Scala has).
For a certain value of "fun", I guess.
Generally I find in engineering that it's best not to add abstraction (or other forms of complexity) to a system unless there are strong, clear benefits to doing so. The more we learn about Scala, it's just not clear that it delivers those benefits (in proportion to the time investment it demands).
It's not that I don't "dig" abstraction. It's just that I have an infinite list of things to learn about (some fun, some not so fun) in any given development environment. (In general, most of these are in the non-fun category: dealing with dependencies,build tools, and legacy quirks that can never be fixed).
And another infinite list in my own problem domain -- you know, that thing I'm supposed to be, theoretically, directly working on (in the service of which all of these fancy software tools were supposed to be a means, not an end). Plenty of very real and juicy abstractions. More than I can ever hope to get to the bottom of, in fact.
But don't get me wrong. If applicatives and such are your bag, then that's great. Maybe Scala is the right language for you, then.
We use Scala because it is speedier to push features. I work much quicker in it, and we don't have to worry about a lot of the stuff we would in Java. That said, we don't use a bunch of the most complex features of the language (I am just talking simple pattern matching, map/flatmap/filter/unzip). So far, it's actually the most productive language we've used.
Our dig is the community and things peripheral from the core language: documentation is generally awful (Play, SBT). Dependencies management is awful (SBT doesn't work). Libraries are overly complex (Dispatch). And compile times suck.
This is why, despite feeling real weird about it, I'm writing my current personal project in Rails rather than Play. It's one case where worse-is-better kind of benefits me--it forces me to focus on my problem, rather than on all the cool bright-shiny-objects that are not my problem.
(There's also a discussion to be had about the Scala-should-be-Haskell crowd, who I think come from a good place but are led by some of the most overtly poisonous people I've ever had to deal with.)
But they are fun in that, once you start understanding what the fuss is all about, they open your brain to new ways of thinking, which is always good - instead of learning how to be really really good with a hammer, I like to know about screwdrivers as well, for the odd case where that nail is kind of screwy.
I do understand your point about an infinite amount of things to learn in a finite amount of time. What I personally do is focus my study of tedium (build tools, say) and domain-specific concepts for work-hours. These things are required for me to be good at my job, and it seems fair that I improve on them while doing that job.
The other, more theoretical (type theory, functional abstractions, fun data structures...) or less directly applicable (odd languages, new concepts such as reactive programming or actors...) subjects I study on my own time, when I have it, when and if I feel like it.
It means that, for example, it took me a solid year before I felt I had some degree of fluency in Scala, which was frustrating. On the plus side, I now have some degree of fluency in Scala.
'Scala the language', is imho very nicely designed, the problems arise in the compiler implementation and the core libraries. Scala carries around too much dead weight in it's core libraries. Some poor choices were made while scala wasn't widely used yet and it's very hard to fix that now. If you look at the roadmap for scala it's obvious that they are trying to address these issues.
OO here meaning polymorphism over types of your data 'object'. The diffrence is that you usally never mutate your object.
It is fair to say however that the emphasis of clojure is functional and your code is expected to be functional style, only when you really need it, you start adding polymorpism but even then protocolls are expected to be a implementation detail quite often. Also, we access our objects the same way we do our hashmaps and even the same function often work on both objects or hashmaps.
Some people might of course dislike this approche where OO is not really not used in the traditional way and is kind of pushed down. So clojure I would say, is techniclly multi-paradigm but culturally its not.
Complexity with dynamic languages grows with the size of the project. I know that because of the focus on purity & immutable data structures clojure mananges to mitigate this problem but I'm afraid it's still there.
The last few years several features have been added to clojure that increased the complexity(/surface area) of the language and the documentation is often a mess. I'm not a clojure hater, just pointing out that the complexity with clojure lies elsewhere.
edit: kinda forgot about Ocaml (~18 yrs old apparently)
I was talking about language complexity, not how complex the project is.
That said, I have nothing against static typing, my argument was not really about typing at all. It was more about how OO and functional interact in clojure compared to java. Also types by itself dont really make all that good of a documentation, at least not the kind you care about when looking something up in the internet.
I am a fan of schema, and I think the future really is in the combination of schema and core.typed. I dont really like to devlop with pre set types and structures, but you could with schema/core.typed. I prefer to work dynamiclly and once im happy with the shape of my data, I 'set it in stone' by writing the correct schema for it. Then you can just always validate everything during devlopment/staticlly. When you deploy you can turn on validation only for data from the outside. This is how I would like to do it, until schema and core.typed work together I just use schema.
Until you need to decipher someone else's code full of NIH macros.
Take one example, core.match. Now in a language that does not have pattern matching code that can be easly written with pattern matching is very hard to read. In clojure its very easy to read.
Now one might argue that a 'good' langauge should have support for pattern matching. To that I say, the language creators can never have all the features everybody wants, it will slow down devlopment of the language and increase complexity.
I would rather read one or two nice clojure macros that reduce tons of boilerplate as you would need in other languages. The same happens in other languages, for exmaple rust. I really enjoy using macros there as well. Give me a language with macros 100%, it improves read and write ability in the waste majority of cases.
My point is that there are many types of code complexity and abusing macros for your in-house DSL is one of them.
This happens a lot in many Lisp shops.
Yes, but it doesn't even have types! (Except clojure-typed, which is so cumbersome and verbose that it's faster to just write Java.)
Also, core.typed can do things that java can not.
> Yes, but it doesn't even have types!
While I understand what you mean, you should write down what you mean. Clojure has types, but not static typing.
Isn't that a very low bar?
> Clojure has types, but not static typing.
Types are – by definition – static.
(defalias AnyMonad
"A monad with bind, result, and optionally zero and plus."
(TFn [[m :< (TFn [[x :variance :covariant]] Any)]]
'{:m-bind (All [x y]
[(m x) [x -> (m y)] -> (m y)])
:m-result (All [x]
[x -> (m x)])
:m-zero (U (All [x] (m x)) Undefined)
:m-plus (U (All [x]
[(m x) * -> (m x)])
Undefined)}))
If you say so ...Some people are willing to invest the time needed to learn to play piano, guitar, violin...
Others are happy to be able to play triangles.
Analogies are so OO.
It's a scalable language by design.
And then as you add more and more features suddenly a case class has 22 and the whole thing crashes down but nobody told you about the 22 airity limit because "the ivory tower says thats bad design and I don't care what the real world needs" and although redesign is simple enough, its kinda shocking. I wonder what other silent spinning propellers can be walked into without warning. Maybe none, maybe lots, but I don't look forward to the ensuing ivory tower tongue lashing because I dared to use it in the real world.
Languages shouldn't get in your way. Even if the real world IS doing it wrong, it should at least support you failing with some style and grace.
And as the powerpoint shows, that compiler is possibly the slowest compiler I've ever used for a given complexity of task. Really... my project was an internal use only super specialized vaguely crud app using play framework for weird engineering data, but nothing fundamentally shocking or unusual, and a full compile from clean source shouldn't take 7 minutes and 33 seconds. What is that like one second per line of source?
Those complaints said, everything worked and it was vaguely enjoyable and interesting although a boring CRUD app does not exactly scratch deeply into the language features. Was a fun experiment, probably wouldn't do it again.
Works fine for me:
scala> case class Foo(a1: Int, a2: Int, a3: Int, a4: Int,
a5: Int, a6: Int, a7: Int, a8: Int,
a9: Int, a10: Int, a11: Int, a12: Int,
a13: Int, a14: Int, a15: Int, a16: Int,
a17: Int, a18: Int, a19: Int, a20: Int,
a21: Int, a22: Int, a23: Int, a24: Int)
defined class Foo
> 22 airity limitTons of other languages have limitations like this too. I wonder why people are obsessed with it only when comparing Scala.
C#: 16 for Func/Action http://msdn.microsoft.com/de-de/library/dd402862%28v=vs.110%...
Java: 2 (BiFunction<T,U,R>) http://docs.oracle.com/javase/8/docs/api/java/util/function/..., 255 for methods
Plus, it's on the roadmap to get fixed, unlike in most other languages.
> 7 minutes and 33 seconds
You setup is definitely broken.
You know quite well that the removal of this restriction is brand new and it would be very easy to encounter it in the wild.
Why do you go out of your way to use smarmy tactics to argue against anytime someone who has a legitimate complaint? It would be way more productive to acknowledge the weaknesses and then tell the good story of Scala.
What would elevate someone from HN "armchair expert" in your mind, such that their complaints were valid? Is it even possible for someone to mention something they don't like about Scala without you immediately dismissing them as not knowing what they are talking about?
The OP hasn't been using Scala for long so many of his gripes boil down to lack of experience. You have to learn the ropes, the (myriad) corner cases, etc. of the language before things start to click.
It's like starting out in Haskell, where on earth do you even begin to understand this utterly new paradigm, much less go into production with large scala projects in it? The answer is: you don't, you learn, learn, learn until you're well grounded in the language and its frameworks; then you bet the bank on it because you're sold on its clear-as-day powers.
I'll go out on a limb and say that the only viable type safe alternatives to Scala and its ecosystem are C#/F# on .NET, and Haskell. In other words, yes, Scala has its warts, but overall is pretty much unmatched in terms of expressivity, power, and performance.
Letting SBT do the build may work, but come on. This is the official IDE! Is there any acknowledgement in scala-ide.org that you should let SBT to do the build? Do Odersky and the guys at Typesafe use that setup, or do they suffer their IDE silently?
I haven't had much luck with IntelliJ either.
As Scala users we're basically guinea pigs in the IDE department. Having suffered from the relative stone ages of 2010 era Scala tooling I can honestly say that if you're considering picking up the language, you've come at a great time ;-)
re: sbt running the show, not sure about IntelliJ but the core Scala IDE devs will drop that bit of knowledge when a user moans on the mailing lists about blocked UI, spurious syntax errors, and other bundles of joy.
Builds are always scripted with explicit settings, which anyone can run, with the same results, regardless of what editor and preference settings they use. (so long as needed compilers are installed on server/workstation)
Incremental compilation in the IDE is useful because you see errors as you type. This is an entirely separate issue from reproducible builds, etc.
Eclipse for Java does this perfectly, and I assume many other IDEs do so too. Scala IDE, which is built on top of Eclipse, does a terrible job at this. For a statically typed language such as Scala, it's aggravating when your tools report spurious compilation errors.
I lost track somewhere in the first ten minutes or so, but it looked like he was importing/using multiple DSLs and helper libraries. After I lost track of the exact details, I started scanning for the gist of what he was doing.
After an hour, he had what looked like the most massive clusterfuck I've ever seen in a project file -- all to do something that would take a dozen lines or so of simple FP script. Seemed like every functional thing he used was either also an object or had to be bolted into an object graph for it to work. The project file had scores of things in it.
This did not leave a good impression. It reminded me of when I saw my first C/Win32 app and realized you needed a couple hundred lines of code and several files just to say "hello world" -- except this was a couple orders of magnitude more complex. It was a god-awful abomination.
Hopefully Scala projects are not like this.
I'm okay with using DSLs. Hey, if you have good FP, flaunt it. My concern after watching this, however, was whether or not the JVM development environment itself encourages complicating things beyond the most minimum thing needed to solve a problem when you're using it in a functional manner. (I haven't done Java in a decade). So, for instance, could I have just written a simple 12-line script to solve the problem he was banging around? Or would I have to create some kind of object with a "main" method? Could I just add in a test file and write functional tests from there, aka JUnit, or do I have to bolt something in that then requires a separate project structure and so forth (aka JUnit)
There's no right or wrong answer for any of these types of project configurations. Heck, I like my tests in a separate project. It just looked like every time he had a new need, the project got 14 times more complex. The solution to one problem made the entire development environment more complicated for everything else. That's heading in the wrong direction, no?
Admittedly I only had a brief glance. Thanks for the answer!
As numerous people before me have said, the language is a mess. Although it offers some benefits, the syntax is so absolutely bloated that you're probably better off taking the time to really consider whether or not you absolutely need it for all of the headaches and unreadability you're going to run into in terms of code. There aren't many Scala developers out there and the learning curve can and likely will punish you when things need to get done, assuming you're bringing in new developers.
The open source libraries all generally seem to have glacially slow development processes, which in some cases might be considered acceptable, but when the main Scala team pushes out 2.11.x (and to some degree actively encourages its use) and X framework you're using literally cannot run because library Y is not compiled against it, you end up stuck on Scala 2.9/2.10 which is really unpleasant for you because you're missing out on the speed increases and other quality of life improvements (how many times have you run into the 22 argument limit for case classes on 2.10?).
Perhaps I'm asking for too much, but Scala strikes me as a language that's supposed to be moving a bit faster than Java in terms of development, but that doesn't really seem to be the case. All in all, while it has some neat parts, if I never got to work with it again I wouldn't be crying about it.
There really are a bunch of new features and a faster development pace than Java; look at the differences between 2.11 and 2.9 (e.g. macros).
I really hope Java 8 will slow down Scala's growth.
For Haskell at least, the GHC runtime is getting pretty good, and seems to have at least basic tools for GC analysis etc. I'm ignorant of MLs so perhaps someone can speak to their status.
Of course there's the much-touted "Java Ecosystem" but it's looking crustier than ever methinks. Maven?? Blech! Also, it doesn't seem wise anymore to build a website on Servlets/JSP/SpringMVC etc, esp. if you want to attract devs. Rest APIs maybe.
What's the killer feature these days recommending the JVM?
Just picking one example from the list, performance: How is GHC's runtime dealing with 100GB+ heaps?
I'm on record as being a Scala skeptic; I've already run into things that the type system seems to encourage but causes headaches, and the size of the language means that no matter how small a subset you write yourself, you can't help but page out when someone else's subset is different than yours. I know that C++ or Perl wizards eventually get to the point where this isn't a problem, and I guess that Scala is positioning itself as Java++, so the same caveats apply.
object MyApp extends App {
code here
}
I tend to use Maven to build my projects, so test classes have to go in src/main/test, have names ending in Test, and have their test methods annotated with @Test. But there's nothing to stop you making another App that just runs tests when it's executed, if you want to do that.Things should be orthogonal, and that's usually something Scala is very good at, e.g. the way (scalaz) Futures are handled is IMO a very elegant balance between exposing the difference between sync and async code and not making it too cumbersome to use.
property("to and from file") = forAllNoShrink(genArrayForSeries)( data => {
withTempDir(f => {
val (stagingDir, dataDir) = mkdirs(f)
val s = SequentialBinaryV1Storage(dataDir, stagingDir)
val id = SeriesIdent(UUID.randomUUID().toString)
val oldSeries = BufferedSeries(id, data._1, data._2)
s.write(oldSeries)
val newSeries = s.read(id).get
((oldSeries.ident == newSeries.ident) :| "identities do not match") &&
((oldSeries.data == newSeries.data) :| "data series do not match")
})
})
Not much DSL, though there are a few helper functions handling stuff like creating a tempdir for the test and deleting when finished.So the impression I get from your comment is that this was a fairly large and/or complex project he was attempting to demonstrate. Maybe it just wasn't real appropriate.
Implicits are dangerous, sure. Typeclasses are vital and extension methods are nice, but it might be better to cover these use cases with something more specific. That said, these days the IDEs flag up implicits so it's not really a problem day-to-day.
Concise really helps readability at the function/module level - there's a huge drop in readability when a function reaches the point that you can't fit it on one screen. It may well be that the 1-line scala version of a method takes exactly the same time to read as the 10-line java version - but if it means you can fit your whole class on one screen, that's still a win.
Symbolic method names are bad and I wish the community would move away from them.
The definition of ++ is perfectly sensible once you stop panicking and start actually reading it. As is the parser; sure, it's a DSL, it uses some short symbols, but I defy you to find a better way to express the parser given. When you're building up a complex parser, it's well worth having a concise notation.
jsonFormatX are legacy cruft. In a modern json library you can avoid them by using Shapeless instead; hopefully spray-json will do this too.
The .toSet() example is deprecated and will give a warning if you actually try and run it.
Java-8 style lambda compilation is already available under an experimental flag, and the next release will have full support.
Oh yes, this is one of the things that bother me the most about Scala, actually. I don't mind if there are conceptually different ways of achieving the same goal, as you put it, because those different ways usually have different trade-offs; if you're doing things one way instead of the other, you know why you're doing it, there's a certain benefit in doing it this way.
But syntactic diabetes is bad because it ultimately provides no real benefit. Different people will write different code based simply on their tastes and preferences and pretty soon you'll have a mess in your project codebase, unless you enforce strict rules and conventions about writing code. Furthermore, people who work in a team that enforces one set of conventions may have trouble when joining another team that uses a different set of conventions. In Java, for example, this is not the case. Yes, there are things that the language itself doesn't enforce, and conventions are used, but these conventions are well known, and there's probably no Java developer on Earth who wouldn't adhere to them. When a totally new Java developer joins the team, she can usually read code right away, because there are no surprises with regards to the syntax. Sure, she'll need to spend some time perhaps to really get what's going on, because the code might be complex, but the syntax itself won't stand in her way.
But the brackets, braces and dots are just such a trivial part of the syntax. Is anyone really getting confused about the difference between
opt.foreach{s => println(s)}
opt.foreach(s => println(s))
opt.foreach(println)
opt foreach println
? I really can't imagine a developer who's learnt one having trouble reading the other. opt foo bar baz buz bif baf
Quick - is buz the method or argument? You have to count to figure it out. Not so hard with java style opt.foo(bar).baz(buz).bif(baf).In my view dropping the . should only be done for non-alphanumeric operators, e.g. foo |+| bar |> baz.
It's actually worse than that because one method application that takes an argument can return either an object that can have a method called on it, or a function which can be immediately applied, or some object that doesn't have the appropriate method but can be implicitly converted to one that does - so without knowing the implementation, there is no unique translation of that string into method calls and objects. Your IDE will probably italicise random words in your DSL code for no obvious reason.
A separate issue is that without knowing the implementation you can write code and not know when or how many times it will be evaluated, because if you pass it into an argument that argument may be call by name.
What it all adds up to is that you can look at a piece of code and have very little clue about what it is actually doing underneath. And what is much much worse - it's usually a leaky abstraction so you actually need to know what it's doing underneath and this happens all the time in common libraries in the name of providing a nice DSL.
But really - this is why you have a style guide. Make your style guide say "Always use . unless a math operator". Then the guy that does
foo map x + y filter < 2 foreach println
gets bonked in the head and told to rewrite it.
You would do the same in Java to the guy who wrote a 600 line method, right? Should the JVM enforce the no 600 line method rule, or can we deal with it in style guides? Because the 1 time I need to write a 900 line method, I am sure glad the JVM doesn't limit me.
I kind of agree with you, but I think the flexibility over delimiters actually makes it easier to keep code like this clear - you can write something like
opt.foo{ bar.baz(buz bif baf) }
And it's very obvious which brackets go together and what's at which level of nesting.But if you were reading the code on github, on a blog post, or in a chat you wouldn't have that advantage.
Yes it will. This is not Haskell where different functions have arbitrary precedence; Scala functions are evaluated left to right (except a very short list of mathematical operators) unless they end in ':'. The only possible meaning of "a b c d e f g" is the one where b, d and f are methods and c, e and g are arguments. You don't need a heavyweight IDE to work that one out.
https://gist.github.com/kaseyjunk/d58f00a4b1865feb94cc
No highlighting that helps.
2) You've moved the goalposts. The original parent said that he found the call syntax confusing, you responded by saying your heavyweight IDE prevents that confusion from happening, and I pointed out the tradeoff required for that. Now you've gone back and just said it isn't confusing and that it is something you have "to work out".
The fact is, some Scala developers find the call syntax confusing and some Scala developers read Scala code in editors that do not have the power to help them suss that out. That is a cost to the flexibility in call syntax. Is that cost worth it? For some people yes, for some no, but don't deny the cost.
If this were true, how would ghc know how to compile Haskell programs?
Scala has some great ideas, but it's so easy to abuse it. I know, I know, you can shoot yourself in the foot with any language. But there are languages that have several safety mechanisms you need to circumvent in order to be able to shoot yourself in the foot, and then there are those that give you a gun and a book called "How to shoot yourself in the foot".
Additionally, you could just define which style you want let the IDE enforce it (or on check in).
There should be only one way to express a given language operation, and this way should be the simplest and most elegant. Not just because of aesthetic (which is crucial when speaking about readability), but also because it would combine the most harmoniously with other parts of the language.
It seems to me that at this point scala should deprecate all non-essential syntactic sugar and features and reduce the language to its "core". Or, at the very least, people should start a fork with that goal. Hell, it could even be just a compilation option.
This is not possible in general, because concepts rarely coincide cleanly with syntax. For example, you can't have both currying and closures if you insist on this.
Most of the "syntactic diabetes" examples in the talk are of this kind: They are actually separate, general concepts that happen to overlap. And some don't even overlap, but the author does not seem to fully understand the language.
For example, that you can write both f(x) and f{x} is simply because f{x} is essentially the same as f({x}) and the parser allows you to drop the parentheses if they directly surround braces. But `{x}` and `x` are not the same: the first is a scoped block, the latter is a variable. You cannot use a variable to express a scoped block and you cannot use a scoped block to express a variable.
There IS unnecessary conceptual overlap in Scala, but you can find that elsewhere: For example, there's quite a bit of conceptual overlap between view bounds and type classes. But it's difficult to blame the language for it: much of this conceptual overlap exists to make the Java interoperability story less painful (of course, you could argue that Scala shouldn't try so hard to be interoperable with Java at the cost of language simplicity, but there are tradeoffs either way).
a b {c d (e f g.h(i))}
In Haskell you'd have to write that as something like: a b (c d (e f (g h i)))
//or alternatively
a b $ c d $ e f $ g h $ i "Concise" doesn't necessarily mean fast to write or easy to readThere are real pain points in Scala when you try and scale it from single developers to teams working on a project and most of them are to do with the flexibility of the language.
I think all companies working with Scala end up settling on a sub-set of the language that they are happy with. In that sense, the bad is irrelevant: you are never put in a situation where, say, you are forced into using implicits (apart from light use in external libraries like lift-json) so if you don't use them you never suffer their downsides. If you obsess over parts of a language you don't even have to use... then well I'm afraid I have nothing but scorn for people like that.
At team-scale then your main pain point is trying to get style of writing that everyone can get behind. Code reviews can be painful when developers with different ideas on how to solve a problem butt heads and pull requests turn into "That's not how I would have written it" instead of critiquing the actual code presented.
The tooling and compiling I completely agree with. SBT is a horrific mess. I don't have a single good word to say about it.
About Scala specifically? No, indeed. About languages which make it possible to create custom ASCII operators? Certainly. I don't know how the Scala culture about this is, but my experience with Haskell is that once people run with it, you get awful ASCII DSLs with cryptic operators all over the place.
> I think all companies working with Scala end up settling on a sub-set of the language that they are happy with.
So, pretty much like C++, a language that people love to hate. The problem is that, out in the wild, you're going to end up with legacy code made by people who picked a different sub-set.
The problem is that, out in the wild, you're going to end up with legacy code made by people who picked a different sub-set.
This is the situation I've been in for the last year and I agree that for every point I make in praise of language flexibility this is the strongest counter-point.
The latest version of dispatch doesn't have that many operators anymore. http://dispatch.databinder.net/Combined+Pages.html
However, as time has gone on, I've found that my coding style in Scala has evolved to the point where I want low-level libraries to work in an asynchronous way. There are now also overloaded, human-readable methods for most (if not all) of the symbolic operators.
These days it is my HTTP client of choice.
IME, its possible to be just as unreadable with the more verbose custom alphanumeric operators (functions/procedures) that every structured/OO/functional programming language lets you create as with terse non-alphanumeric symbolic operators; all that eliminating the latter does is to limit how concise [1] it is possible for even a well-designed DSL to be.
[1] Note that concise isn't just terse, but also clear.
Yes, that happened in Scala too. Luckily another set of Haskell slingers wrote us Scalaz, so it's not all bad.
With scala you can write test that are concise and readable with ScalaTest or ScalaCheck. The readability largely depends on the quality of the library that you use but also the user.
I'd like to do functional programming, I'm doing server/web based stuff mostly. I'd like the language to have a big(large) ecosystem. Clojure is fun and all, but it's more or less a hackernews language. There are only a few serious businesses using it. It also lacks a web framework like Play!. Same goes for Haskell. So besides all the bad stuff of scala, having play and quite a large ecosystem is why i wanted to try it.
And seriously, the web story for Clojure is just fine. It's just componentized, it's not missing.
Are you talking about Scala or Clojure? I've only seen those names mentioned with their Scala use, what are some of their Clojure projects?
Netflix: they definitely use it for Hadoop stuff, probably elsewhere too. And from this presentation they do a fair bit of Java interop with it: https://speakerdeck.com/daveray/clojure-at-netflix
Twitter/BackType produced Apache Storm, which is written in Clojure.
Not sure about the Guardian, I should ask, but they're definitely using it.
> how awesome web frameworks are on this side of the grass
This is kind of the point he was trying to make, clojure really does not have any major webframeworks. Clojure just does web devlopment diffrently.
A hacker news comment is hardly the place for impressive writeups about web devlopment. There have been post like that in lots of blogs.
Also, I didn't ask to write about web development, merely share information/links like the other comment (https://news.ycombinator.com/item?id=8420463) did.
In fairness, there's a kernel of truth in that almost any article about Clojure seems to get uncritically upvoted, but that's another matter. The fact remains that Clojure, whilst not as popular as Scala, is nonetheless (quietly) in use at a lot of firms.
Some more examples: * CitiGroup EU FX derivatives is pure-Clojure * There's at least three different hedge funds using it. * Deutsche Bank are definitely using it too.
I know i'm kind of spoiled with features because I do a lot of projects which involve django. I do not expect a framework to be as rich as Django. But i prefer having some things integrated. Some might prefer choosing every component in a framework (ORM, url routing system, form validation etc), but when you work in a team or with freelancers, it comes in handy if theres just a way of doing things.
For those of us not familiar with Scala it'd be interesting to see you expand on that statement. Are you talking about the type definitions in this file?
https://github.com/spray/spray/blob/release/1.1/spray-http/s...
respondWithHeader(`Content-Encoding`(UTF8)) { ... }
and the header and its parameters are typed, and so if you make a typo in the name or the value (or try to pass the value of one header to another) then you'll get a compile-time error.http://play.golang.org/p/GeUgsjitVS
func respondWithHeader(h HttpContentEncoding) string {...}Yes the Scala server shown was an interesting example, though I'm not sure if it would be impossible to do in other languages or just harder.
Also having a type for sanitized strings versus unsanitized strings.
The golang stdlib does do this, it's quite handy as a reminder.
I do have issues with it, but mostly with developers using (abusing) it. (And library authors that are a bit religious about the functional paradigm and simply love their operators...
With great power comes great responsibility, the is no better description to this language.
Also, I was looking at the CanBuildFrom hell with fear, but Odersky et al's book on Scala surprisingly did a good job getting the pieces in place for me. It even makes sense of the madness.
http://www.artima.com/shop/programming_in_scala_2ed
Finally, Bozho is one of my most respected contributors on stackoverflow. And I can say that his slides actually do justice to Scala, I might disagree on the conclusions, but the facts are absolutely right.
Give me the Scala pattern matchers (that can also match by type and even by content of case classes, I believe), with the case classes and the actor concurrency model, but keep the horrendous type system and the confused parts of the syntax.
Could you expand on that a bit?
In my experience, Scala is one of the few languages which don't fight against everything you want to express in a typesafe way.
Also, I find the syntax extremely consistent. Easy to remember and almost no special rules.
The type safety goes way overboard with extremely arcane, incomprehensible expressions. The excessive power of the type system makes compiling far too slow. And the pattern matchers mean you can easily get your type back when you need it. I really strongly prefer the more dynamic approach of Groovy. Total type safety is a trap.
Yes, but which one would you remove?
If you disallowed the curly ones, developers would suddenly require an additional language feature to define methods which could be used like this:
using(someResource) {
// do something with ressource
}
Apart from that {} has semicolon inference, while () doesn't. That's extremely helpful, if you have some expression and really want to make sure that it can't be split into something like { doThing1, doThing2 } by an unaware developer.> Total type safety is a trap.
Sure, there are limits on what can be done with a type system, but these options have been growing larger and larger in the last decades.
I wouldn't throw away the last 40 years of progress in that area and start doing stuff manually which any decent compiler can figure out for me.
> Groovy
I haven't heard from Groovy since a long time ago. Is it still actively developed? The last things I saw was that they were struggling to catch up, and work on the new MOP still wasn't finished.
On the Gartner PLI, Groovy is way down on position 20. That doesn't look too promising either ...
It's still the sole language used in Grails, which is losing adoption share to newer web frameworks. Gradle is on the rise, but Gradle will probably soon open its configuration as an API so any language can use it, so Scala and Clojure could become more popular for scripting Gradle in the future.
> Is it still actively developed?
There's a technical developer employed by Pivotal who's presently working on making Groovy work on Android. I don't know if he's working on it full-time or merely squeezing in development between fee-paying consultancy work.
> The last things I saw was that they were struggling to catch up, and work on the new MOP still wasn't finished.
I don't think work on a new MOP has started. It's pitched for Groovy 3 and the next version of Groovy is still version 2.x.
> On the Gartner PLI, Groovy is way down on position 20.
On Tiobe, it's still hovering around position 49, where it's been fluctuating since 2007, sometimes higher, often out of the top 50.
"The Neophyte's Guide to Scala" (http://danielwestheide.com/scala/neophytes.html) is hands down the best language introduction I've ever read though.
For more beginner-centric content perhaps check out:
Learning Scala:
http://shop.oreilly.com/product/0636920030287.do
http://chimera.labs.oreilly.com/books/1234000001798/index.ht...
...or Atomic Scala:
I was looking for a language to move to post-python. I love python but the 2.7->3 jump has been annoying. More than that, I felt I needed static typing for the next big system I did ... too much pain debugging python.
I looked at Scala since it had the JVM behind it. While the language seems decent, it seems too easy to write unreadable code. Multiple ways of doing the same thing ... yada yada.
Friends at Google had been espousing Go for a long time and I didn't bother. Seemed like a proprietary language with little adoption. Two things changed for me. I got some exposure to erlang via elixir. This made me think about the whole channel concept. Second, I had to read code in Docker (which is awesome). I learned a bit of the language and was surprised how small the language was. Really reminded me of C, which I love. There seems to be more adoption of Go .. e.g. Cloud Foundry and others. I like Go enough that I will be spending more time learning and investing in it.
Just by 2 cents.
This is a longer discussion, but in the very first slide he points to the object-orientation as a plus. In my opinion, he's already wrong. "There is no such thing as Object-Oriented programming." See: http://blog.higher-order.com/blog/2008/12/04/no-such-thing/