Scala's great, if you have a gorgeous Haskell program and you want to port it to the JVM. Unfortunately, by itself, that may be a niche market.
If you want a dynamic language, you have lots of great choices. If you want powerful syntactic abstractions, you have Clojure, Lisp or Racket. You can win big with any of these tools.
But some problems benefit from powerful mathematical abstractions, and that's where Haskell and Scala start to shine. For example, if you need to do Bayesian filtering, you can bury all the math in a monad, and make Bayes' rule as easy as an 'if' statement. (I've got a blog post for the curious: http://www.randomhacks.net/articles/2007/02/22/bayes-rule-an... ) And when your library designs start involving generalizations of linear algebra, even Ruby-lovers may learn to appreciate a strong type system.
But this raises the real question: How useful is Scala if you don't need to do functional programming with a strong type system? Most people don't, at least today, and the jury's still out on whether it will ever be mainstream. Certainly, some smaller companies will use Scala and win big in specialized domains. But if Java hackers want to claim that Scala's an inappropriate tool for their jobs, who am I to argue? I write far more Ruby than Haskell, because I encounter lots of work that's well-suited to Ruby. (Of course, there's also Akka and a lot of other useful Scala features, which may appeal to people who don't need FP.)
So if Scala becomes seriously popular, I'll be delighted. But a large fraction of Scala's complexity is devoted to niche use cases, and that may make some people unhappy if they're merely looking for a "better Java".
> How useful is Scala if you don't need to do functional programming with a strong type system?
Functional programming with a strong type system, IMO, has much wider applicability than just the esoteric mathematical abstractions (e.g. Haskell/scalaz) that you're asserting is a niche for Scala.
I can think of many non-scalaz uses of Scala, but even for non-Scala uses, look at Jane Street's evangelism of OCaml (functional + strong type system) for financial systems.
(Note that, personally, while I like the benefits of FP, I admittedly still think in/like aspects of OO, even if just out of habit, so I find Scala's blend particularly nice.)
I think the issue is not that there aren't applications, it's that people just aren't used to looking for them. As an example, let's think of classical geometry. They figured out the area of circles, the volumes of cones, etc without any calculus. If you know the tricks you can figure it out too, or you can just apply a little calculus and it just falls out. I feel that people dismiss the math as unnecessary because they can get by without it, but in reality the math is always there and sometimes provides much simpler solutions.
I've found over the last few years that my thinking has morphed from primarily OO to primarily functional. It isn't for lack of writing OO code, which I do professionally. I find that my brain loves to think in terms of functional transformations on classes of data types.
Suddenly I find myself noticing when things should be expressed as a monad or monoid. I also find myself thinking in type signatures for dynamic languages and silently cursing the language designer who decided a function can return null without warning. I see patterns in my code and find myself wishing I could overload the semi-colon to implement monadic behavior.
I get and have built Probability monads often enough. They seem really cool since keeping normalization around is theoretically nice, but they seem broken in "real" applications.
Everything I do with probability ends up looking mathematically dissimilar to probability. Most algorithms go far out of their way to avoid on-the-fly normalization because it's so expensive. An EM update monad is just the State monad.
I love Haskell (never used Scala) but I find the very things you're marketing it with abhorrent to use.
I don't see how Haskell or Scala are better in mathematical abstractions. I guess it would be equally easier (or even much easier) to abstract away this kind of thing in clojure, you could generate all the checking that you would get in Haskell/Scala. The only real diffrence I see is the compiletime checking, right?
Yeah, the big advantage of Haskell (and Scala) for abstract mathematical code is the compile-time type checking. Normally, I'm extremely happy with dynamic languages, because I make maybe 2 type bugs a year. I mean, it's not that hard to remember whether a variable contains an Employee or a String, and that's all you need for some programs.
But when you're designing a library, and a variable contains the free module over nullable real numbers, then the type checker is your friend. At least I can't keep that stuff straight without lots of help. And Haskell's ability to do compile-time dispatch on the desired return type of a function makes monads cleaner, too.
If you want to do this in Clojure, see "Typing Haskell in Haskell" http://web.cecs.pdx.edu/~mpj/thih/ , and whip up some macros that do Hindley-Milner type inference with type classes. And if you do, please e-mail me so I can play with it. :-)
Scala is not Haskell and in Scala you can only check if a variable contains an Employee or a String. The problem is that such types do not actually contain anything useful about the content within that object, it just says how the object behaves (the messages it responds to).
For instance, say you have a String ... well, a String containing what? A name? A regular expression? A number waiting to be converted to floating point? A bank account number? A phone number? An email?
I don't see compile-time type-checking in Scala as something useful, as most often than not it stands in my way. It does help to alleviate some bugs related to incorrect usage of types, but on the other hand you need tests with good code coverage anyway.
The whole point of having an expressive type system is to encode useful properties in it. If a type of String isn't any use to you, give the value a more expressive type. Make a Name type, or a RegEx type, or whatever. Use unboxed types:
Indeed. I think many people seem to miss the fact that types are a language for describing the data in your program.
I also think many people do not understand the benefits of type abstraction, perhaps because many languages do not even offer it without requiring boxing. Even if your RegEx type is a String, not revealing that to client code is wise engineering.
My favorite example is dealing with user input on the web. Everything from the data passed by the user's browser to the data stored in the database is just a string of bytes. You could go about representing this as a string, but really there are different types of strings, specifically there are sanitized and unsanitized strings. The database should only ever receive sanitized strings and all input from the user is an unsanitized string. Then you have two simple functions that map from one to the other, say, escapeString and unescapeString.
If you don't represent these as different data types it's very easy to accidentally lose track of if you sanitized a string or not. Did you sanitize it before you placed it in your model, or do you need to sanitize it before to display it? Did we unsanitize it when we pulled it from the DB? Should we be displaying it unsanitized in the HTML?
If you encode these differences in opaque types it suddenly becomes impossible to make a mistake. It suddenly becomes very easy to reason about a program. Based on the type you can immediately know what type of string you are dealing with and not have to every ask yourself if it has been sanitized yet.
For me, that reduces the complexity of the application and makes reasoning about the program easier. Wise application of types to semantic differences in data can really make a program easier to build.
That is a poor example since you should not normally have to code like this when handling user input on the web.
You must escape all user input you send to the database, and this is normally done by your database driver by using parametrized queries (be they prepared or not). And when the data is retrieved from the database you generally do not have to unescape anything, especially not since the returned data is not SQL strings but in whatever binary protocol is used and is unescaped (if necessary) by your driver.
So what your code should look like is something like:
db.execute("INSERT INTO foo (a, b) VALUES ($1, $2)", a, b)
So for the database you just have two types. Queries and data. Data should always be treated as unsafe while queries is the special class that could help out if you do a lot of manual query building.
Not so. What if something fails database validation so you want to display it in the form with an error? This can lead to attacks where a malicious user gives the victim a specially crafted URL that inserts a script into their page, then when they access the URL the script executes inside their browser with their session.
For this reason any user input needs to be escaped whenever it is rendered in HTML as well. If you got it from the DB it should be safe, but if you got it from the url parameters it isn't.
Data from the database is just as unsafe as data from URL parameters which is why escaping of data must be done in the presentation layer. This is basically the same thing as SQL queries. You have a template like this (most of the HTML omitted).
<li class="<%= user_type %>"><%= username %></li>
Where username and user_type are variables containing data fetched from the database. This template is then compiled to something like the blow. Strings literals of the HTML-safe type start with s", and concatetnation to the output buffer is <<.
So to implement your own templating language and and template helper functions this is a useful concept. But query building should be in the database layer and HTML building in the presentation layer. People using the database should not have to know of or care about that the data might at some point be displayed in a HTML page.
This makes sense. You're totally right about the database. I've run into that issue before, but I had forgotten.
Your example is similar to the approach that Yesod, a Haskell web-framework, takes. The templating language, Hamlet, will accept many types, such as Text or String, but ultimately everything gets translated into RepHTML before being rendered to a real HTML string that is sent to the client. Whenever you give the template a value it automatically runs the appropriate conversion function based on type to generate something safe for display on the page.
The only way to get from a String to RepHTML is either to use the proper escaping function (usually done automatically) or use a special function to do an unsafe conversion, forcing you to explicitly state that a conversion is safe.
The type system is one of the tools used to guarantee that these things get sanitized. You can generate RepHTML in other places, such as through a widget, or other helper functions, and it knows at that point that you properly escaped it. Without the type system you could run into issues when a function generates HTML (sanitized) and then the final template re-sanitizes it. It would be very awkward to do things like layout templates if things are getting sanitized many times.
Yeah, that is how I expect a templating system to work. The one in Rails (modified ERB)works in the same way. It has a SafeBuffer (name taken from memory) class which is a subclass of String. Strings can be converted into the safe class either by escaping or through unsafe conversion which emans that we say the string is safe.
How about if you want to do stuff only with Employees with a salary greater than X? Consider this case ...
a_employees = employees.filter{|x| x.salary > A}
b_employees = employees.filter{|x| x.salary > B}
# where A > X, B > X
# so both should work with:
def do_stuff(employees) where employees.salary > X
...
In other words, creating new subclasses is a poor substitute for code contracts, especially since many contracts could be checked at compile time.
I'm genuinely surprised that you make only two typing bugs per year. I make about 2 per minute, and I consider myself a good programmer. My higher frequency may be in part because my style of coding relies heavily on the typing system: I recompile after about every line of code I type, and make sure my code always type-checks, so maybe I'm not as carefully planning my programming as somebody who's accustomed to dynamically typed languages. Nevertheless, I find it hard to believe that you don't trip up when you create deeply nested loops/recursion. If you don't, what's the trick?
It is possible to build all kinds of crazy type stuff into any lisp. Look at Qi or Typed Racket they build all kinds of type-stuff into the language (Im not an expert in stuff like this so I don't know how far you could go). There are allready people working on this in Clojure.
A Typesystem in this still combind with some tools to check this befor you run the programm should provide almost everything you get from Haskell or Scala.
This kind of approach does yield the additional benefits:
1. Much easier to change
2. You can add another static analysing system ontop of it
I think the reason why Scala is often used for these niche applications is that:
A) The language doesn't fall apart as soon as you try something not imagined by the original language creators.
B) Pushing the boundaries actually returns useful results.
C) Java isn't able to solve the given task or at least not productively.
That doesn't make Scala a non-general-purpose language.
Probably the majority out there is using Scala as a better Java and is perfectly happy with it.
firstly it is never good when you start out a discussion by saying now I know people will disagree but thats because their bigoted zelots. Its kind of disingenuous to attempt to post a technical dissent filled with personal opinion and preface it with that kind of clause inevitability allowing you to label any dissent as "See those scala zelots are at it again"
That being said this is an article that attempts to raise technical problems with scala but really just list a few of the authors own personal gripes with the language. In order here are his complaints
1. Scala doesn't have a rigid versioned module system
2. The functional way of doing concurrency isn't how I like to do concurrency
3. The scala community isn't helpful enough for me
4. The type system is too powerfull
5. The syntax is too flexable
6. There aren't enough tests in the compiler test suite
Its alot of the same thing I have seen when people try to list "The" problems with the language and not "Their" problems with the language. Technically there is only one argument that could even hold water thats about the module system . Which if he really needs a module system for his work then that is a technical limitation of the language and he might consider using a better tool for his job. The rest of it however is just nonsense and personal opinion pretending to be technical dissent.
Steve's remarks on concurrency seem a totally fair observation to me, don't a large number of functional languages deal with concurrency through immutability and support that at the language level - I can think of Clojure, Erlang, Haskell, F# for example. The fact that it was possible to send a mutable message to a Scala actor made me extremely suspicious when I first used the language.
It's a relatively well acknowledged fact in the community that Scala's builtin actors are heavily flawed. This is why many of us switched to using Akka.
It is also why there are currently plans to integrate Akka actors into the language itself, replacing the builtins.
He does acknowledge that "It could become EJB3" which is a far sight better. But the tone of the rest of his post genuinely seems in conflict with this sentiment.
Another big piece of Scala which makes it a tremendous win over using say, Erlang, Haskell or F#, is that it integrates well with existing Java code. Many shop have been able to do new development in Scala while keeping and leveraging their existing legacy Java codebase. Something that wouldn't be properly available from these other Non-JVM languages.
Clojure of course is JVM based as well; however I'm not as familiar with it and I'll admit I don't know how well it does or does not work with existing Java Code. I do know that a few MongoDB + Clojure driver authors have had issues w/ certain aspects of our Java driver in wrapping it which seemed rather trivial. Not an indictment of Clojure, just the only view of Java compatability I've seen which anecdotally leads me to believe Scala has stronger integration.
Finally, I can't agree enough on the need for modules. It really is a major pain point... but I'm not sure it's one that we can easily fix at this point. I'd still love to see us (The Scala Community) try, however.
My personal experience in wrapping non-trivial Java libraries in Scala and Clojure is that with Clojure it usually just works and it works quickly. In Scala I am usually reduced to an extra hour or two of adding manifests to signatures until the compiler accepts it.
I am disappointed with Scala and having lived through EJB 1, EJB 2 and then onto Spring and EJB 3, I agree with Steve it makes me feel exactly the same as I felt about EJB 1 and EJB 2 - that is I am being sold overcomplicated technology as a panacea. I want a powerful language with a simple syntax, for example Lisp, ML or Haskell, not a powerful language with a complicated syntax like C++. Does Scala really want to be known as Java++?
I think the criticism of implicits is valid and should be addressed by the scala community, it is a frequent occurrence for me to be left scratching my head when reading code because something is bringing in an implicit declaration unbeknownst to me.
Also one complaint not made by Steve is compile times, reasonable in SBT, unreasonable using the typical build tool used in legacy Java projects.
Interoperation with Java from Clojure is generally fairly painless. The largest exception that I can think of is if you are trying to integrate with a library/framework that is heavily object-oriented and requires class inheritance. Clojure is very opinionated on the functional programming aspect, and although it is generally possible to extend classes, it can be relatively painful.
However, if you are only using objects, calling methods, or even implementing interfaces, interoperation for Clojure is quite nice.
Even if the Actors are better, generally people still build programmes with lots of mutability. If don't start to build your application with concurrency in mind you will end up with problems later. With clojure you can be pretty sure that everything is threadsafe by deafault.
This is just how it seams to me from afar. I don't know if that is right.
Functional Programming does deal with concurrency with immutability. And thats how you should deal with it in scala. The fact that you can use mutable constructs in concurrent program is no more a flaw of scala then the fact that I can execute any pointer in C as a function is a flaw of C.
I've been picking up Scala on-and-off for the past few months. "Programming in Scala: Second Edition" is one of the best tech books I've ever read. The authors assume you already know how to program, offer mutable & immutable approaches to nearly everything, anticipate esoteric questions in the footnotes, and even have a good sense of humor.
The book also weighs in at 883 pages and I was astonished how much of it I needed to read to even get started. Once I did, I very much like what I saw. But I was a big fan of ML back in grad school.
I do share some of the blog author's gripes though. Most of the popular Scala libraries are just a mess of DSL operators that have no real world association. I'm constantly having to look up what an operator means. I still have no clue how to use the Dispatch library, since the concepts it encapsulates are about 400 pages deeper into the book than I'm currently at. This, just to issue an HTTP GET request. I really thought there might be something on the lines of Ruby's rest-client library.
Additionally, my issues with versioning occur at a much simpler level. The release notes of any given Scala release are devoid of anything useful. Usually it's just a list of JIRA issue numbers (not the issue titles). And then there was this whole debacle around 2.9.0.1 and how SBT called the version. That took me 4 hours longer to work than was really necessary.
So, anyway, I do have some Scala projects. Incidentally they're all Java interop because I just can't wrap my head around how to use most of the Scala-specific libraries. But I've found it works really well in those situations. Deep down I really do like the language. The Scala ecosystem leaves a lot to be desired, but fortunately I can pull in stuff from elsewhere on the JVM.
BlueEyes is a framework for writing high performance web services. For it's use cases you care whether you're getting or putting. Thus it is explicit. Similarly, you care about performance, and so don't want to parse strings if you can help it -- thus you set the host once rather than parsing a URL.
For a pure ease-of-use library Dispatch is probably the best, if you can figure out the syntax (see earlier discussion). In Dispatch you can write something like
No, I don't take (much) issue with your example's readability, I just thought you were offering a typical snippet for the easy path for "I need to perform a GET".
Of course, more involved interactions require an API with more knobs. Clojure has a number of options, including touching the JDK's HTTP client API, or using a wrapper around something more grounded like clj-http[1] / Apache HTTPComponents.
Dispatch is so often used as an example of hard to read Scala code/operator overloading abuse, that I think it should be shuttered just for the greater good of the Scala community.
That being said, programmers can over-engineer things in any language; it's just that in Java, over-engineered things are "incomprehensible and huge" while in Scala over-engineering things are usually "incomprehensible and small".
Thanks. I ended up using scalaj-http, which was much simpler. But it took me a few days to find it. Dispatch does very well SEO-wise for Scala HTTP. The only other option I had come across was using http-client.
Have any good recommendations for JSON parsers? This was another case where I found the common libraries to be rather obtuse.
I use BlueEyes here (I'm a big fan of BlueEyes). It's JSON library is based on Lift-JSON. Lift-JSON is fairly commonly used, so perhaps you've run across it already. It's actually fairly simple to use and is one of the few parts of Lift that has decent documentation:
Most of the comments here talk about how whatever useful can be done in Scala can be done in some other language. That is not the point, Scala is a good language because
- Compatible with JVM
- Strong type system
- Linear Typing
- Substructal Types
- Local Type inference
- Concurrency constructs built in as actors (Akka)
- Integration of OO and functional paradigms
- Supports Higher Order Programming
- defn-site Variance based Parametric Polymorphism
- Mixin Class Composition for finer grain reuse
- Traits provide stackable behaviors (aspect-oriented style)
- Embedded Polymorphic Domain Specific Language (DSL)
using dependent path types
Every language design is a trade off, but Scala is more expressive and concise than Java. Sometimes that may look to you as code which is unreadable. Other languages like clojure make some other trade offs. But Scala tries to bring some of the benefits of functional programming (in say Haskell) to Java.
>Is it easy for programmers of all abilities to understand and use?
Thats a loaded question. I don't know about you but I have met alot of People who write VBScript in excel spreadsheets that call themselfes programmers. To say the language is bad because programmers of all abailities can't understand and use it will make all languages even the simplisest ones fail that test.
You should be asking can programmers that I will be asked to work with understand it and use it, however your answer to that question I think will say more about the programmers you hire / work with then it will about scala.
The list of features were meant to just illustrate that Scala is not some programming fad, it is strictly more expressive than Java and based on solid programming language principles.
Although,I agree the code may not be easy to understand for everyone in the beginning but with effort and training I believe every programmer can learn enough of it to be more productive.
You do realize the futility of such questions given Turing completeness, right?
It is not about what can be expressed, but about how you express things. You do not need function literals in Scala, but it is sure is more concise and cleaner than anonymous classes in Java. You do not need traits in Scala, but it avoids code duplication or the overhead of wrapper classes or proxies in Java. You do not need case classes and algebraic pattern matching in Scala, but it is far more concise and less error prone than having to write the obscene amounts of boilerplate you would write in Java.
Scala, with its “type-level programming”, crazy operator overloads and weird DSLs, is at a similar precipice as C++ was back when people started doing insane stuff with template metaprogramming (around the time of Alexandrescu's “Modern C++ Design”, 2001 maybe?).
Unfortunately, I don't think many Scala users were around at that time or in that community, so lessons of the past might be learned the hard way again.
There are many encouraging signs too, though, toward better and simpler practices. We'll see which way things go.
Yes, I guess I answered the letter of his question... but I personally wouldn't use collection types indexed by a size unless (a) I really really needed to be sure about this particular invariant (b) there was a bit more sugar and automation. In most cases the added verbosity and complexity involved would not generally be a win over just using an assertion. However, it is nice to know you have the option of static enforcement should it be desirable.
That is not a simple type. And people who still remember the original Pascal will know that you do not want to encourage people to make the size part of the collection type. And it doesn't buy you much if you cannot prove at compile time that the type you use to index into the collecton cannot overflow the collection bounds. Use Ada if you need that.
For instance you can implement a library providing Units of Measurements such that you can track the correct type through computations, e.g:
val time: Time[Int] = 15 s
val length: Length[Int] = 450 m
val speed: Speed[Int] = time / length
The type annotations are of course completely optional.
The interesting thing is that while the implementation is quite complex, the actual user has a very simple interface to develop against.
So while you can write complex code in Scala, Scala allows you to keep the complexity in the library-side, while it would bleed into the use-site in Java (use-site generics, anyone?).
Java can't do that. In fact, they already failed twice with it.
It's unfortunate that there a number of very smart people from the Haskell community that are trying to mold Scala in Haskell's image that also appear to be very prominent and active in the community. Other than having some negative effect on Scala's public image, however, there's nothing wrong with what they are doing. People work on open source projects that interest them, and it is an interesting exercise for some to find out how different Haskell constructs can be encoded in Scala.
However, the rest of us lesser mortals use Scala very differently, and we far outnumber these people. If you pay attention to Martin Odersky, the creator of the language, you'll notice that he is more interested in serving our needs than those of the Haskellites. He's outright refused to make IO monads a core part of the language, for instance, even though they have pushed for it. He's also said that scalaz is on another planet entirely, and he's asked publicly that people stop using symbolic method names in their libraries unless they have external meaning beyond the library. This guy gets it. He really has created a language that is powerful, but also practical, an excellent language for writing code that is readable, maintainable, efficient, and concise.
The author of this article admits that Scala doesn't feel right to him. He then proceeds to try to justify that feeling in his mind with some very weak arguments. For instance, his module argument oh so coincidentally happens to play into fantom's strengths alone, as No other JVM language is trying to tackle this problem right now. He is right about the lack of tests and binary incompatibility, but these are known issues that already have been addressed to some extent and are continuing to be addressed. They are not core issues with the language itself.
Scala is lightyears ahead of Fantom and Fantom will probably never catch up. If Fantom can't win on technical merit, then apparently the next best strategy involves negative blogging!
Disclaimer I like Fantom and it is my language of choice. That said, I agree he (Stephen) for every fault he finds Scala finds a way to recommend Fantom. That strikes me as dubious.
Nevertheless I find this statement:
> Scala is lightyears ahead of Fantom and Fantom will probably never catch up. If Fantom can't win on technical merit, then apparently the next best strategy involves negative blogging!
Baseless at best.
In what aspect is Scala lightyears ahead?
Also what are you implying by saying 'if it can't win on technical merit then best strategy involves negative blogging!'
First Stephen is just one guy.
Second I think Stephen just likes Fantom for the same reasons he dislikes Scala and wanted to blog about it.
The authors and the community have overall been quite ambivalent to Scala. As witnessed by this blog from one of Fantom's authors: http://fantom.org/sidewalk/topic/675
After struggling through using sbt and Maven/Ivy I can say it is categorically worse than what I have used in other languages including ruby-gem python-pip clojure-leiningen (a jvm language) and node-npm. When I say worse I mean doing what the majority of developers want from a module system: easily install modules, not provide a complicated mess of configuration and versions.
This isn't to say scala couldn't adopt a better system, but I don't think the community has an incentive because scala's main appeal is that it has a steep learning curve, but after you get over the hump you can do everything you want and more. I just think that high barrier to entry, as indicated by the post, may not be worth the benefits.
Did you ever try buildr? I've never used sbt, as, coming from a Ruby background, the fact that buildr sits atop of rake appealed to me more than sbt. It uses maven repositories underneath the hood, but then again, as I understand it, so does clojure-leiningen.
Part of me thinks you're conflating two separate things: build systems and package repository systems. Even people who hate Maven's build system (myself included) tend to agree that Maven's package management system is really good, and as you like clojure-leiningen, you must agree in some sense.
Could you go into more detail about what problems you had with sbt? What you describe doesn't really match up with my experience. If you want to use it simply to compile Scala code you can just do 'sbt compile' in the directory containing the Scala files. If you want to add dependencies you just create a file called 'build.sbt' and add lines like:
Where I worked, we switched from Java to Scala a few months ago, and we're all loving it. I really don't understand Stephen Colebourne's criticisms. Well, actually, sure I understand every one of his criticisms, but I could make equally damning or more damning criticisms of just about every programming language. No programming language is perfect. On the other hand, we find Scala to be much more expressive than Java. In Scala, I can write code in a natural way, rather than the way that Java wants to force me to write it. The result is cleaner, more elegant code, that is significantly shorter with much less boilerplate and code repetition, and easier to understand.
Sure the type system is complicated, but I don't really have to understand all its nuances in order to get my program to compile and work. When you use Scala, after a short while you just develop an intuition for it.
The comparison to EJB 2 is a bit nutty, if you ask me, since writing code in Scala tends to be the antithesis of all the terrible Java monster enterprise library crap. The libraries that people use in Scala tend to be much simpler and more straight-forward.
I do agree that there's a contingent of the Scala community who seem to want to rub their fluency with category theory in your face. This is hardly representative of the entire community, however, and I'm sure they must exist in the communities for almost every functional programming language these days. The solution for this is for people to come up with more intuitive explanations for the powerful tools that category-theory inspired abstractions provide. I know that this can be done, and it will be done, when functional programming become mainstream enough that it attracts better writers.
(I, myself, have been thinking of writing up a little essay called "The Mapcat is the state monad of Massachusetts" to try to explain monads in a better way than comparing them to space suits, or whatever. Okay, okay... mapcat isn't a state monad, but I think the title's funny anyway.)
“Sure the type system is complicated, but I don't really have to understand all its nuances in order to get my program to compile and work.”
This is key. People sometimes look at the type signature of the map method (as above) and freak out. It's good to try and understand everything, mind you, and eventually you probably will. The key here is that the crazy signature of the map method simply means the map method will do what you expect. That's it! “But I would write X to do it in my language” is irrelevant, because you don't write the map method. It's provided. There's a paper that describes why the signature is how it is and everything, but you don't care, because it's complicated so that when you're actually using it, it just works.
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
All this complexity to allow for automatic conversions (the following will return a Set[String]) ...
BitSet(1, 2, 3).map { _.toString + "!" }
In a dynamic language, the signature of map is simply this: (a → b) → [a] → [b]
The big difference is that the language doesn't care about types "a" and "b" until runtime. You're the one that cares about it, only on a need-to-know basis. Hence the implicit conversions become explicit (although conversions are less necessary) and code correctness is guarded by unit tests, which you need with Scala anyway. Also, the implementation of "map" in a dynamic language is something that a junior developer can come up with.
So the biggest problems I have with Scala:
1) it is not readable
2) it separates developers in two camps:
library designers and users
3) it does not provide clear benefits
over dynamic languages (Haskell does)
Not only dynamically typed languages, the signature would also look remarkably close to (a → b) → [a] → [b] in ML and Haskell. Your ML and Haskell compiler would also make check that it was called correctly at compile time without extra unit tests.
> Haskell has typeclasses which would probably correspond to structural typing in Scala.
Nah, typeclasses are nominative typing but added post-facto (you can define a typeclass instance for a third party's type). Typeclasses are similar to Scala's traits I think (I don't know if you can add traits to a library's types though).
It does, but it does not support downcasting (it does support upcasting)
For instance, the Ord typeclass extends the Eq typeclass, so any instance of Ord can be used as an instance of Eq. But there is no way to cast an instance of Eq to an instance of Ord.
The Scala code here starts with one Functor (BitSet) and returns a different Functor (Set), depending on the type of the function (in this case, Int => String). If the function had type (Int => Int), it would still return a BitSet.
The signature for fmap does not encode this flexibility.
Can you explain the scala type signature for map? I see no container declared and it is less than obvious to me how it actually represents map across a container. I guess it is the implicit?
I'm a Scala newbie, and it did not take me long to actually understand the type signature here. Of course, when I first saw it I was confused, but it's not magical.
There are probably map-methods elsewhere, but let's take the map defined on TraversableLike[0]. TraversableLike is a base trait for all kinds of Scala collections (let's just pretend trait is like an interface for now, look it up if you're interested in the details).
TraversableLike has two definitions of map in 2.9.1:
The first one isn't so bad, is it? The first one takes a function converting objects of A to objects of B, and returns something that is traversable of B (i.e. perhaps a List[B] or Set[B]).
The second one can return anything you want, as long as you have a function that describes how the objects can be converted. That is what the implicit is for. For instance, if you map a collection over a function that returns a list of integers, but you actually wanted a set of strings - you can define a function that converts your List[Int] to Set[String]. I recently found a description of canBuildFrom on Stack Overflow that explains this in a bit more detail[1].
As a Scala beginner I find that I often can't expect to understand everything at once - a lot of times it's like other languages, but when it's not I usually can't just guess what it does, but actually have to take time to learn it. I don't think this is a bad thing.
it did not take me long to actually understand
the type signature here
Bullshit. You just followed somebody else's public explanation. Not a problem per se, but this doesn't strike me as beginner friendly ... Dr. Brian Beckman also has a great description of monads on Channel9 that doesn't involve category theory. Does that mean that monad comprehensions are also beginner friendly?
if you map a collection over a function
that returns a list of integers, but you
actually wanted a set of strings
Here's some Ruby code for you:
[1,2,3].map{|x| x * 2}.map{|x| x.to_s}.to_set
Ironically I find this code written in a dynamic language to be much more readable. Also, give me first-class functions and recursion in a dynamic language and I can implement all of the above by my own (lists, sets and map).
How about acting less aggressive?
It certainly dosen't help you to get your point across.
> Here's some Ruby code for you
You just tried very hard to not understand the problem at hand, right?
Because the equivalent Scala code looks like this:
Array(1,2,3).map(_*2).map(_.toString).toSet
> I can implement all of the above by my own
Sure, if you OK with your code running magnitudes slower than the built-in stuff.
That's probably the main difference between general purpose languages and scripting languages today: General-purpose languages allow you to implement the appropriate data structures yourself, while scripting languages force you to use the built-in stuff.
The issue discussed here is the implementation and signature of "map", a trivial function that anybody should be able to understand and implement without a sweat.
Sure, if you OK with your code running magnitudes
slower than the built-in stuff
...
scripting languages force you to use the built-in stuff
These 2 sentences don't compile.
You should also realize that the speed of the JVM has nothing to do with the static-ness of the language. The bytecode is in fact dynamic ... the only instances where certain assumptions where made based on Java (the language) being:
1) classes are immutable and can't be garbage collected unless you destroy the corresponding class loader
2) the method dispatching done cannot be overridden (so when calling a method on an implicit object, you also have to specify the interface where that method is defined) ... but this has nothing to do with the inner-workings of the JVM and is being addressed with the work done on InvokeDynamic
Really, if you're worrying about "scripting" specific behavior sneaking in on you, stealing away precious CPU cycles or RAM bytes, then you should stay away from the JVM.
Seeing that you still don't grok the basics discussed here, this is probably my last answer to you.
You still fail to understand that the `map` (and other methods) are far more flexible in Scala, making them play well with sub-typing and inheritance (and in fact with stuff like `String` and arrays which don't implement any collection methods at all).
With your examlpe above, what result collection type would you get when you map with `Int -> String` over a `BitSet` or with `Char -> Int` over a `String`?
> You should also realize that the speed of the JVM has nothing to do with the static-ness of the language.
You have obviously never seen the mess JRuby and Clojure employ to run on the JVM.
The example above was made by me, on purpose to explain the difference, which I did.
On the JVM - I've implemented dozens of parsers and simple compilers, I did a lot of bytecode manipulation. I know my bytecodes, I know very well the challenges involved.
Your oppinion is based on gospel and the authors of Clojure or JRuby dissagree with you ;)
The article seems very fear driven, many of his arguments simply do not gel with my experience.
We have been using Scala for 4 months now and have the first cut of our product released:
The Scala community have been great - we have had insightful answers on the Lift, Akka, Dispatch and Scala users list and on stack exchange.
We have used parallel collections and Akka actors to get good scalability without the usual pain. We do have some mutable data structures where it makes sense - we appreciate the flexibility to do that. The distinction between mutable and immutable data structures is pretty easy to read in the code.
Our code base is very concise, and i think readable for the breath of functionality we have implemented. We have not used type level programming, simple Scala constructs like pattern matching, collections and closures make a huge difference.
You can write obtuse code in Scala - we choose not to.
In short we see Scala as a competitive advantage going forward.
Everything's unreadable until one learns to read it. This is a classic non-argument that people buy into for reasons I can't comprehend. Is Scala harder to read than other languages? Perhaps, but then just say that.
As Rich Hickey pointed out recently, "I can't read German; does that mean it's unreadable?"
I disagree. While I don't know German, I can read German and even will understand some words and in some contexts even the general meaning of the sentence (i.e. restaurant menu or technical texts with large amount of English loanwords/terms).
You don't need to know Python, to understand it on the level of pseudo-code. You don't need to know Clojure to understand it on the level of S-expressions, etc.
There are those who say scala is complicated, and there are those who actually learn it and once they do they love it more than anything out there. So yeah, I love scala.
[edit: also, you're inferring the experience of people from the complaints that they make. that means that you are automatically dismissing anyone who makes certain kinds of complaints simply because you know that some people who make those complaints have little experience of scala. so, for a very simple example, you might find that only people with a very high tolerance for type system induced pain can tolerate scala - then you would be dismissing the majority of people, presumably with valid criticisms of scala, just because they are not part of your (self-selected, exceptional - and not necessarily in a good way) clique.]
I think the case is not that people knowing Scala are unable to see the problems of the language (e. g. scala.Enumeration).
The thing is that people knowing the language can easily tell apart people who never seriously tried using the language from those who did, because the complains of the first group are so much different from the other group.
what do you want me to do? i was less aggressive than you are. i gave links to references. i posted from my own account rather than hiding behind a new one. herd behaviour and sunk costs are good explanations for the kind of response i was replying to - everyone knows that technology creates "fan boys". so what, exactly, are you criticising in what i said?
i don't understand your anger, apart from the fact that you don't like to be wrong.
For the past few years, I've used Scala every time I need to do something on JVM (which isn't too often). Otherwise I use Python or C++. I don't blog about it.
Scala is clearly an improvement over Java (although I wish they'd kept a C-style for loop). I happen to slightly prefer it to Clojure (which is also better than Java for my purposes).
In the non-Java JVM ecosystem, there are always these angry bucket-of-crabs posts from enthusiasts. Ignore them.
Scala feels very much like "Java done right". Scala solves a lot of problems with Java and is better in every respect. In the same way, Subversion solved a lot of problems with CVS and is very much "CVS done right".
But the opportunity that was missed was that, just at the Subversion developers never asked themselves "Is centralized version control the right way to do things?", I feel that the Scala developers equally were so focused on fixing the myriad of problems with Java, they never took the step back and asked themselves "Is imperative/mutable state/exposing-Java's-warts-for-compatibility the right way to do things?" Of course, they've built a much better Java, but it feels that they've been so focused on the trees that they've not seen the wood [1].
Scala is awesome, when combined with AKKA it's even better. We're much more efficient then we ever were in Java. Also, ops doesn't know it's not java since they can use all the same jvm tools.
val myList = "Jim" :: "Bob" :: Nil
myList(println)
Heh to a Java programmer, the answer would be - everything.
Here are my thoughts on it.
- I get val myList is some sort of list...
- Seems to be a list of Strings. But what is ::?
- Nil means list is nullable. Wait is one of the parts of list 'myList(println)' (looks a bit like Smalltalk)?
- Why is println the argument and not the method? Is that syntax correct?!
Compare same thing in Fantom. Note ; is only used as a separator and is equal in all respects to '\n'.
Cons is short for construct and comes from Lisp which has weird names for things; things like car and cdr.
It means construct a new list.
A cons A (or A :: B) means create a new list with A before B, where B can be a list item or a list itself and A is a list item.
The :: operator is right associative so "Jim" :: "Bob" :: Nil actually works like ("Jim" :: ("Bob" :: Nil) ) (Actually all operators that end in : are right associative in Scala.)
i.e. reorder those and add a semicolon or put it on the next line
and I agree with pivo that "Jim" :: "Bob" :: Nil should be List("Jim", "Bob"). I'm not sure if these are the same as _Y_'s Fantom code, but both of these print out "List(Jim, Bob)" in Scala.
Umm, I'd say Scala is to Java what C# was to Java. It cleared some things at expense of come other things. Overall it's pretty cool language (I rarely use :P).
They were an early Java attempt to "save" programmers from the complexities of writing actual systems by adding all sorts of abstractions and supporting server software. They were an abomination, used mainly by "enterprise" shops that were willing to spend money on everything but programmers who knew what they were doing.
As far as I could tell, they were a classic example of the architecture astronaut's tendency to inflict blue-sky designs on others before actually using them in the real world. They sounded great in the marketing brochures, but were hideous in practice, both for development and run-time use.
The EJB3 transition he mentions came about because EJB as a product was getting its ass kicked by Hibernate and related open-source, field-tested software. Eventually they just threw out EJB2 and said, "Hey, EJB3 is a bold, innovative approach that just happens to look exactly like Hibernate."
i used scala for a few months. it sounded very promising, java without the verbosity. but in the end i decided to stop using it.
The biggest problem for me was readabilty. Scala is the first language that i've learned where at first i couldn't just read code and immediately guess what it does.
I think the prime reason for this is that scala permits operator overloading; more than that, in fact, almost every character can be an identifier. This results in often very cryptic code and libraries, because you can't guess what that function does without reading its definition. quick, what's the difference between +++ and ::: ? what's /: and /:\ ? You can't even google it!
The other big problem for me was the type system. At first it sounded really great, and in fact the amount of compile-time code verification that you can achieve is indeed impressive. But in practice, i found myself fighting with the type system a lot, for example when trying to reuse a function with generic type restrictions that I had't written: some time these can get very long and your only choice is to copy-paste them from the original definition.
Also, how do you test that your type constraints are correct? you can't, by definition, write compilable code that would invalidate them.
Finally, it turns out that a lot of the bad stuff that's in java ends up in scala also, because of runtime compatibility concerns. in particular, scala's generics are an extension of java's. so, for example, almost all generic type information is lost at runtime, except for some extra metadata that scala stores in the object. this results in pretty ugly code when you have a dynamic object and you need to use it with a generic method.
>I think the prime reason for this is that scala permits operator overloading; more than that, in fact, almost every character can be an identifier.
I've been toying with the idea of trying scala for a serious project for a few months, and this part scares me. It's so obviously a bad idea it makes me wonder what other dumb things are in there.
Those "random rules" make the code base much easier to read. This kind of thing is a big step backwards for people working on large projects, especially people who need to come up to speed on a large code base.
If you want a dynamic language, you have lots of great choices. If you want powerful syntactic abstractions, you have Clojure, Lisp or Racket. You can win big with any of these tools.
But some problems benefit from powerful mathematical abstractions, and that's where Haskell and Scala start to shine. For example, if you need to do Bayesian filtering, you can bury all the math in a monad, and make Bayes' rule as easy as an 'if' statement. (I've got a blog post for the curious: http://www.randomhacks.net/articles/2007/02/22/bayes-rule-an... ) And when your library designs start involving generalizations of linear algebra, even Ruby-lovers may learn to appreciate a strong type system.
But this raises the real question: How useful is Scala if you don't need to do functional programming with a strong type system? Most people don't, at least today, and the jury's still out on whether it will ever be mainstream. Certainly, some smaller companies will use Scala and win big in specialized domains. But if Java hackers want to claim that Scala's an inappropriate tool for their jobs, who am I to argue? I write far more Ruby than Haskell, because I encounter lots of work that's well-suited to Ruby. (Of course, there's also Akka and a lot of other useful Scala features, which may appeal to people who don't need FP.)
So if Scala becomes seriously popular, I'll be delighted. But a large fraction of Scala's complexity is devoted to niche use cases, and that may make some people unhappy if they're merely looking for a "better Java".