views:

18982

answers:

17

First note the inflammatory subject title is a quotation made about the manifesto of a UK political party in the early 1980s. This question is subjective but it is a genuine question, I've made it CW and I'd like some opinions on the matter.

Despite whatever my wife and coworkers keep telling me, I don't think I'm an idiot: I have a good degree in mathematics from the University of Oxford and I've been programming commercially for almost 12 years and in Scala for about a year (also commercially).

I have just started to look at the Scala collections library re-implementation which is coming in the imminent 2.8 release. Those familiar with the library from 2.7 will notice that the library, from a usage perspective, has changed little. For example...

> List("Paris", "London").map(_.length) 
res0: List[Int] List(5, 6)

...would work in either versions. The library is eminently useable: in fact it's fantastic. However, those previously unfamiliar with Scala and poking around to get a feel for the language now have to make sense of method signatures like:

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

For such simple functionality, this is a daunting signature and one which I find myself struggling to understand. Not that I think Scala was ever likely to be the next Java (or /C/C++/C#) - I don't believe its creators were aiming it at that market - but I think it is/was certainly feasible for Scala to become the next Ruby or Python (i.e. to gain a significant commercial user-base)

  • Is this going to put people off coming to Scala?
  • Is this going to give Scala a bad name in the commercial world as an academic plaything that only dedicated PhD students can understand? Are CTOs and heads of software going to get scared off?
  • Was the library re-design a sensible idea?
  • If you're using Scala commercially, are you worried about this? Are you planning to adopt 2.8 immediately or wait to see what happens?

Steve Yegge once attacked Scala (mistakenly in my opinion) for what he saw as its overcomplicated type-system. I worry that someone is going to have a field day spreading fud with this API (similarly to how Josh Bloch scared the JCP out of adding closures to Java).

Note - I should be clear that, whilst I believe that Josh Bloch was influential in the rejection of the BGGA closures proposal, I don't ascribe this to anything other than his honestly-held beliefs that the proposal represented a mistake.

+4  A: 

I don't know how to break it to you, but I have a PhD from Cambridge, and I'm using 2.8 just fine.

More seriously, I hardly spent any time with 2.7 (it won't inter-op with a Java library I am using) and started using Scala just over a month ago. I have some experience with Haskell (not much), but just ignored the stuff you're worried about and looked for methods that matched my experience with Java (which I use for a living).

So: I am a "new user" and I wasn't put off - the fact that it works like Java gave me enough confidence to ignore the bits I didn't understand.

(However, the reason I was looking at Scala was partly to see whether to push it at work, and I am not going to do so yet. Making the documentation less intimidating would certainly help, but what surprised me is how much it is still changing and being developed (to be fair what surprised me most was how awesome it is, but the changes came a close second). So I guess what I am saying is that I'd rather prefer the limited resources were put into getting it into a final state - I don't think they were expecting to be this popular this soon.)

andrew cooke
I think he want's to know whether people without PhDs from Cambridge can handle Scala 2.8.
Ken Bloom
Haha: touche! Well, I said that scala 2.8 is easy to use - my question was more about what it would look like to someone browsing the API to see if they liked it, assuming they had no previous experience in Scala.
oxbow_lakes
@andrew - from the looks of yout website (http://www.acooke.org/), you are not uncomfortable with visually intimidating concepts
oxbow_lakes
Anyone occupied with Malbolge programming, even if it's "just" Hello World, is unlikely to be intimidated by anything.
Carl Smotricz
+3  A: 

Scala has a lot of crazy features (particularly where implicit parameters are concerned) that look very complicated and academic, but are designed to make things easy to use. The most useful ones get syntactic sugar (like [A <% B] which means that an object of type A has an implicit conversion to an object of type B) and a well-documented explanation of what they do. But most of the time, as a client of these libraries you can ignore the implicit parameters and trust them to do the right thing.

Ken Bloom
Yes, view syntax is makes thing faster to grasp.
egaga
+10  A: 

I have an undergraduate degree from a cheap "mass market" US university, so I'd say I fall into the middle of the user intelligence (or at least education) scale :) I've been dabbling with Scala for just a few months and have worked on two or three non-trivial apps.

Especially now that IntelliJ has released their fine IDE with what IMHO is currently the best Scala plugin, Scala development is relatively painless:

  • I find I can use Scala as a "Java without semicolons," i.e. I write similar-looking code to what I'd do in Java, and benefit a little from syntactic brevity such as that gained by type inference. Exception handling, when I do it at all, is more convenient. Class definition is much less verbose without the getter/setter boilerplate.

  • Once in a while I manage to write a single line to accomplish the equivalent of multiple lines of Java. Where applicable, chains of functional methods like map, fold, collect, filter etc. are fun to compose and elegant to behold.

  • Only rarely do I find myself benefitting from Scala's more high-powered features: Closures and partial (or curried) functions, pattern matching... that kinda thing.

As a newbie, I continue to struggle with the terse and idiomatic syntax. Method calls without parameters don't need parentheses except where they do; cases in the match statement need a fat arrow ( => ), but there are also places where you need a thin arrow ( -> ). Many methods have short but rather cryptic names like /: or \: - I can get my stuff done if I flip enough manual pages, but some of my code ends up looking like Perl or line noise. Ironically, one of the most popular bits of syntactic shorthand is missing in action: I keep getting bitten by the fact that Int doesn't define a ++ method.

This is just my opinion: I feel like Scala has the power of C++ combined with the complexity and readability of C++. The syntactic complexity of the language also makes the API documentation hard to read.

Scala is very well thought out and brilliant in many respects. I suspect many an academic would love to program in it. However, it's also full of cleverness and gotchas, it has a much higher learning curve than Java and is harder to read. If I scan the fora and see how many developers are still struggling with the finer points of Java, I cannot conceive of Scala ever becoming a mainstream language. No company will be able to justify sending its developers on a 3 week Scala course when formerly they only needed a 1 week Java course.

Carl Smotricz
After one week of a Java course, you're ready to be let loose on some serious software development! I don't think Scala is trying to take Java's place, or ever thinks it will be the next Java. But I do think they can aim to get the success of, say, Ruby or Python which have a significant user base. The question is, "have they screwed this up?"
oxbow_lakes
Thanks for making my post prettier :) Your question concerned some details added to the pre-existing picture. If I weren't fully exerting myself trying to understand the 2.7 feature set, I might have been able to grasp the finer points. My personal take is that the "update" of the collections API was just adding a little more insult to some already pretty serious injuries. Clever folks like yourself will manage, less clever people like self may have already run away screaming.
Carl Smotricz
Ruby: No. Not unless someone comes up with a Scala app that approaches the lethality of Rails. Lift is not that app; I bought the book but gave up on trying to understand it. Python: No. Scala is not nearly as "friendly" as Python. It's also later to the party.
Carl Smotricz
Sorry bout all the comments. 1 week is a joke for practically any language, but that doesn't prevent managers from putting that joke into practice. I was once given 3 days to "crash-train" a group of C++ developers into Java. I asked for 5 days but got shorted for budget reasons.
Carl Smotricz
+1 for "but some of my code ends up looking like Perl or line noise." scala has so many great things, but using punctuation for method names on collections seems like a step backwards.
Peter Recore
@Carl - great points. I think Scala was always going to have a problem gaining traction in the "middle ground". I just worry that this new API is going to cost it dearly even at the higher level. Steve Yegge once attacked (unfairly IMHO) Scala for its over-complicated type-system. Someone is going to have a field-day with this!
oxbow_lakes
For my first job I was given a C++ book at the end of the interview to learn before I started work on the Monday. You're all wusses.
Tom Hawtin - tackline
@Tom - Hah! I was given two books on Ada and told to come in the next day knowing it.
Erik Engbrecht
@Tom @Erik You boys have it easy. I was given the circuit diagrams to the computer (no CPU back then), and told I had two hours to fix a bug *as* the interview.
Daniel
Note I wasn't claiming that Scala was going to supplant either Ruby or Python, merely that it has a chance of becoming a language which is widely used in the commercial world because it *scratches an itch that exists* (i.e. a decent, useable language on the JVM).
oxbow_lakes
@Daniel @Tom @Erik I was once given a 0 and a 1 and asked to use them to solve the knapsack problem in linear time during the interview. I gave it a shot but unfortunately I only had time to create Eclipse (which I suspect is reducible to knapsack). #tall_tale
Alex Miller
@Alex That shows lack of imagination. Place one big zero to the left, and two other smaller zeros on it's right: one above the other, the top one slightly to the left. Place the one between these two smaller zeros, going from the lower left to the top right. Say that's the chance of solving knapsack in linear time. There, you're done. :-) +1 for equating Eclipse and Knapsack, though. :-)
Daniel
A: 

I suggest you try Clojure for a few weeks. Afterwards Scala will seem like a piece of cake.

bugspy.net
Hi bugspy, we've met before in a Clojure discussion. I found Clojure refreshingly simple. Fewer symbols, simpler syntax, more consistency. Clojure manages to get more mileage out of less complexity, or so it seems to me. Once you've wrapped your mind around the Lisp core...
Carl Smotricz
Maybe its just me and I am an idiot, but Clojure is really tough to read and understand. Try to read some clj files from the distribution and then tell me its refreshingly easy
bugspy.net
Clojure is very *different* from what you're used to, but it's not that complex.
Chuck
Scala seems to be the kind of language that tries to make complexity more manageable by adding some management complexity of its own. Most Lisps (including Clojure), on the other hand, basically try to reduce complexity to a minimum (both in the language and in code). These are _very_ different approaches with different strengths and weaknesses, and knowing one doesn't really help a lot when trying to learn the other. I, for one, find Clojure code very easy to read, while all that type constraint syntax that Scala provides seems pretty arcane to me. I guess it comes down to experience.
Matthias Benkard
@Matthias, After working to Clojure for past 2 months, all I can tell is after you get used to ir, it is much simpler than Scala. The initial learning curve (especially for non fp developer) is high, but afterwords, I agree. Not to mention it is much more fun then Scala
bugspy.net
With Scala's operator "overloading", can you make a program look like APL? :-)
Ralph
+20  A: 

Is this going to put people off coming to Scala?

Yes, but it will also prevent people from being put off. I've considered the lack of collections that use higher-kinded types to be a major weakness ever since Scala gained support for higher-kinded types. It make the API docs more complicated, but it really makes usage more natural.

Is this going to give scala a bad name in the commercial world as an academic plaything that only dedicated PhD students can understand? Are CTOs and heads of software going to get scared off?

Some probably will. I don't think Scala is accessible to many "professional" developers, partially due to the complexity of Scala and partly due to the unwillingness of many developers to learn. The CTOs who employ such developers will rightly be scared off.

Was the library re-design a sensible idea?

Absolutely. It makes collections fit much better with the rest of the language and the type system, even if it still has some rough edges.

If you're using scala commercially, are you worried about this? Are you planning to adopt 2.8 immediately or wait to see what happens?

I'm not using it commercially. I'll probably wait until at least a couple revs into the 2.8.x series before even trying to introduce it so that the bugs can be flushed out. I'll also wait to see how much success EPFL has in improving its development a release processes. What I'm seeing looks hopeful, but I work for a conservative company.

One the more general topic of "is Scala too complicated for mainstream developers?"...

Most developers, mainstream or otherwise, are maintaining or extending existing systems. This means that most of what they use is dictated by decisions made long ago. There are still plenty of people writing COBOL.

Tomorrow's mainstream developer will work maintaining and extending the applications that are being built today. Many of these applications are not being built by mainstream developers. Tomorrow's mainstream developers will use the language that is being used by today's most successful developers of new applications.

Erik Engbrecht
"it will also prevent people from being put off". this. absolutely. scala is the first language that makes engineering with something comparable to haskell (in the power of its type system) a possibility for many of us. there is no f***ing way i could persuade work to use haskell, but scala really has a chance and for that i love it and will (when i think it make sense) try to get it adopted, or at least accepted, at work.
andrew cooke
+1 from me too. Given the premise that Scala places more emphasis on linguistic depth and rigor than mass approachability, these answers fit perfectly.
Carl Smotricz
"Tomorrow's mainstream developers will use the language that is being used by today's most successful developers of new applications." +1. Brilliantly said.
Vasil Remeniuk
+58  A: 

I do not have a PhD, nor any other kind of degree neither in CS nor math nor indeed any other field. I have no prior experience with Scala nor any other similar language. I have no experience with even remotely comparable type systems. In fact, the only language that I have more than just a superficial knowledge of which even has a type system is Pascal, not exactly known for its sophisticated type system. (Although it does have range types, which AFAIK pretty much no other language has, but that isn't really relevant here.) The other three languages I know are BASIC, Smalltalk and Ruby, none of which even have a type system.

And yet, I have no trouble at all understanding the signature of the map function you posted. It looks to me like pretty much the same signature that map has in every other language I have ever seen. The difference is that this version is more generic. It looks more like a C++ STL thing than, say, Haskell. In particular, it abstracts away from the concrete collection type by only requiring that the argument is IterableLike, and also abstracts away from the concrete return type by only requiring that an implicit conversion function exists which can build something out of that collection of result values. Yes, that is quite complex, but it really is only an expression of the general paradigm of generic programming: do not assume anything that you don't actually have to.

In this case, map does not actually need the collection to be a list, or being ordered or being sortable or anything like that. The only thing that map cares about is that it can get access to all elements of the collection, one after the other, but in no particular order. And it does not need to know what the resulting collection is, it only needs to know how to build it. So, that is what its type signature requires.

So, instead of

map :: (a → b) → [a] → [b]

which is the traditional type signature for map, it is generalized to not require a concrete List but rather just an IterableLike data structure

map :: (IterableLike i, IterableLike j) ⇒ (a → b) → i → j

which is then further generalized by only requiring that a function exists that can convert the result to whatever data structure the user wants:

map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c

I admit that the syntax is a bit clunkier, but the semantics are the same. Basically, it starts from

def map[B](f: (A) ⇒ B): List[B]

which is the traditional signature for map. (Note how due to the object-oriented nature of Scala, the input list parameter vanishes, because it is now the implicit receiver parameter that every method in a single-dispatch OO system has.) Then it generalized from a concrete List to a more general IterableLike

def map[B](f: (A) ⇒ B): IterableLike[B]

Now, it replaces the IterableLike result collection with a function that produces, well, really just about anything.

def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That

Which I really believe is not that hard to understand. There's really only a couple of intellectual tools you need:

  1. You need to know (roughly) what map is. If you gave only the type signature without the name of the method, I admit, it would be a lot harder to figure out what is going on. But since you already know what map is supposed to do, and you know what its type signature is supposed to be, you can quickly scan the signature and focus on the anomalies, like "why does this map take two functions as arguments, not one?"
  2. You need to be able to actually read the type signature. But even if you have never seen Scala before, this should be quite easy, since it really is just a mixture of type syntaxes you already know from other lanugages: VB.NET uses square brackets for parametric polymorphism, and using an arrow to denote the return type and a colon to seperate name and type, is actually the norm.
  3. You need to know roughly what generic programming is about. (Which isn't that hard to figure out, since it's basically all spelled out in the name: it's literally just programming in a generic fashion).

None of these three should give any professional or even hobbyist programmer a serious headache. map has been a standard function in pretty much every language designed in the last 50 years, the fact that different languages have different syntax should be obvious to anyone who has designed a website with HTML and CSS and you can't subscribe to an even remotely programing related mailinglist without some annoying C++ fanboi from the chucrh of St. Stepanov explaining the virtues of generic programming.

Yes, Scala is complex. Yes, Scala has one of the most sophisticated type systems known to man, rivaling and even surpassing languages like Haskell, Miranda, Clean or Cyclone. But if complexity were an argument against success of a programming language, C++ would have died long ago and we would all be writing Scheme. There are lots of reasons why Scala will very likely not be successful, but the fact that programmers can't be bothered to turn on their brains before sitting down in front of the keyboard is probably not going to be the main one.

Jörg W Mittag
@Jorg - that is an awesome answer; thank you. Whether you have a degree or not, you are a brighter man than I. The only quibble I have is that I do understand *the broad picture* of what is going on in the method signature. However, the details are still confusing: how is `That` being inferred and linked to the type `B` being one question that springs to mind. Where are the implicits coming from being another. Even without these detailed observations, I still feel personally that this is a complex signature. But evidently there are people like you out there who are not fazed by this at all!
oxbow_lakes
Nice explanation, but you have convinced me even more that the Scala 2.8 "map" method signature is very complicated.
Derek Mahar
Jorg, I don't believe the concern is on the ability for a dedicated and sharp person to be able to immediately understand the signature. The concern is the time and thinking required. It took me a few minutes even to understand the question (I read a little about Scala). Then it took longer to go through your explanation, which makes sense (great answer).But this is not the type of time cost you want to inflict upon new users of a language. Ideally it will be incredibly easy to get into, and full of depth to organically grow in use and maintain interest.
Mark Essel
A language that looks like this: def map[B](f: (A) ⇒ B): IterableLike[B]is much more inviting than one that looks like this:def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Mark Essel
I find it quite interesting that you start by claiming to only know basic, ruby and smalltalk, and continuing that you have no academic background in the subject matter. ...and then later claiming knowledge on the complexity of type systems in languages such as Miranda and Clean; languages mostly known only among serious programming languages geeks and academics.
Sami
@Sami, he probably is a very prolific programmer, likes to learn many languages after all some people just love to code.
Randin
+18  A: 

Well, I can understand your pain, but, quite frankly, people like you and I -- or pretty much any regular Stack Overflow user -- are not the rule.

What I mean by that is that... most programmers won't care about that type signature, because they'll never see them! They don't read documentation.

As long as they saw some example of how the code works, and the code doesn't fail them in producing the result they expect, they won't ever look at the documentation. When that fails, they'll look at the documentation and expect to see usage examples at the top.

With these things in mind, I think that:

  1. Anyone (as in, most people) who ever comes across that type signature will mock Scala to no end if they are pre-disposed against it, and will consider it a symbol of Scala's power if they like Scala.

  2. If the documentation isn't enhanced to provide usage examples and explain clearly what a method is for and how to use it, it can detract from Scala adoption a bit.

  3. In the long run, it won't matter. That Scala can do stuff like that will make libraries written for Scala much more powerful and safer to use. These libraries and frameworks will attract programmers atracted to powerful tools.

  4. Programmers who like simplicity and directness will continue to use PHP, or similar languages.

Alas, Java programmers are much into power tools, so, in answering that, I have just revised my expectation of mainstream Scala adoption. I have no doubt at all that Scala will become a mainstream language. Not C-mainstream, but perhaps Perl-mainstream or PHP-mainstream.

Speaking of Java, did you ever replace the class loader? Have you ever looked into what that involves? Java can be scary, if you look at the places framework writers do. It's just that most people don't. The same thing applies to Scala, IMHO, but early adopters have a tendency to look under each rock they encounter, to see if there's something hiding there.

Daniel
+146  A: 

I hope it's not a "suicide note", but I can see your point. You hit on what is at the same time both a strength and a problem of Scala: its extensibility. This lets us implement most major functionality in libraries. In some other languages, sequences with something like "map" or "collect" would be built in, and nobody has to see all the hoops the compiler has to go through to make them work smoothly. In Scala, it's all in a library, and therefore out in the open.

In fact the functionality of map that's supported by its complicated type is pretty advanced. Consider this:

scala> import collection.immutable.BitSet
import collection.immutable.BitSet

scala> val bits = BitSet(1, 2, 3)
bits: scala.collection.immutable.BitSet = BitSet(1, 2, 3)

scala> val shifted = bits map { _ + 1 }
shifted: scala.collection.immutable.BitSet = BitSet(2, 3, 4)

scala> val displayed = bits map { _.toString + "!" }
displayed: scala.collection.immutable.Set[java.lang.String] = Set(1!, 2!, 3!)

See how you always get the best possible type? If you map ints to ints you get again a BitSet, but if you map ints to strings, you get a general Set. Both the static type and the runtime representation of map's result depend on the result type of the function that's passed to it. And this works even if the set is empty, so the function is never applied! As far as I know there is no other collection framework with an equivalent functionality. Yet from a user perspective this is how things are supposed to work.

The problem we have is that all the clever technology that makes this happen leaks into the type signatures which become large and scary. But maybe a user should not be shown by default the full type signature of map? How about if she looked up map in BitSet she got:

  map(f: Int => Int): BitSet     (click here for more general type)

The docs would not lie in that case, because from a user perspective indeed map has the type (Int => Int) => BitSet. But map also has a more general type which can be inspected by clicking on another link.

We have not yet implemented functionality like this in our tools. But I believe we need to do this, to avoid scaring people off and to give more useful info. With tools like that, hopefully smart frameworks and libraries will not become suicide notes.

Martin Odersky
I feel like a naughty schoolboy! Thanks very much for taking the time to respond here. I think that the balance of answers has shown me that I need not worry; there'll be enough people who are not intimidated at all.
oxbow_lakes
No, I think you were absolutely right to hit on that point. And other people will be scared unless we do something about it.
Martin Odersky
Martin, I like your suggestion to show a simplified method signatures and hide the general details behind a link.
Derek Mahar
That's a great suggestion. There are quite a number of people here at work who would be scared of the former as they expect the later.
wheaties
Presenting simplified type signatures is probably a topic for human reference book writer.
Ken Bloom
I think a solution that would work at least as well is more explanations in the docs. I wouldn't find the signatures so intimidating, if it weren't for the fact that most methods (and even most classes) don't have more than a single sentence describing their purpose and operation.
Nick Johnson
Update: The final Scala 2.8 release has a mechanism like the one I described. If you look up BitSet in the scaladocs you find: def map [B] (f: (Int) ⇒ B) : BitSet[B][use case] Builds a new collection by applying a function to all elements of this bitset.
Martin Odersky
+5  A: 

Hello oxbow_lakes, Unfortunately the signature for map that you gave is an incorrect one for map and there is indeed legitimate criticism.

The first criticism is that by subverting the signature for map, we have something that is more general. It is a common error to believe that this is a virtue by default. It isn't. The map function is very well defined as a covariant functor Fx -> (x -> y) -> Fy with adherence to the two laws of composition and identity. Anything else attributed to "map" is a travesty.

The given signature is something else, but it is not map. What I suspect it is trying to be is a specialised and slightly altered version of the "traverse" signature from the paper, The Essence of the Iterator Pattern. Here is its signature:

traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)

I shall convert it to Scala:

def traverse[A, B](f: A => F[B], a: T[A])(implicit t: Traversable[T], ap: Applicative[F]): F[T[B]

Of course it fails -- it is not general enough! Also, it is slightly different (note that you can get map by running traverse through the Identity functor). However, I suspect that if the library writers were more aware of library generalisations that are well documented (Applicative Programming with Effects precedes the aforementioned), then we wouldn't see this error.

Second, the map function is a special-case in Scala because of its use in for-comprehensions. This unfortunately means that a library designer who is better equipped cannot ignore this error without also sacrificing the syntactic sugar of comprehensions. In other words, if the Scala library designers were to destroy a method, then this is easily ignored, but please not map!

I hope someone speaks up about it, because as it is, it will become harder to workaround the errors that Scala insists on making, apparently for reasons that I have strong objections to. That is, the solution to "the irresponsible objections from the average programmer (i.e. too hard!)" is not "appease them to make it easier for them" but instead, provide pointers and assistance to become better programmers. Myself and Scala's objectives are in contention on this issue, but back to your point.

You were probably making your point, predicting specific responses from "the average programmer." That is, the people who will claim "but it is too complicated!" or some such. These are the Yegges or Blochs that you refer to. My response to these people of the anti-intellectualism/pragmatism movement is quite harsh and I'm already anticipating a barrage of responses, so I will omit it.

I truly hope the Scala libraries improve, or at least, the errors can be safely tucked away in a corner. Java is a language where "trying to do anything useful" is so incredibly costly, that it is often not worth it because the overwhelming amount of errors simply cannot be avoided. I implore Scala to not go down the same path.

Tony Morris
Hi Tony - thanks for your thoughtful input here. I would make 2 responses to it. The first is that I did not mention the "average programmer" and do not believe that Scala is necessarily aimed at one. Whether it is conceited of me or otherwise, I believe I am above average; however, I still feel that the type signature is daunting! I still worry, in other words, that above-average programmers, Scala's target market, may be driven away.
oxbow_lakes
The second point is that I fundamentally disagree with you about what Scala *is*: Scala is a pragmatic language - not a theoretically pure one. Why else would it have been designed atop the JVM? This is a purely pragmatic decision - it is being aimed at developers "in the real world" - a choice which may have necessitated compromises! Also note that Bloch and Yegge are far from average programmers - but that is my point. Even highly respected and intelligent people can have opinions about complexity and purity which differ from yours. Unfortunately for you, they are also highly influential.
oxbow_lakes
Hello oxbow_lakes,It is a stated goal of Scala to appease typical programmers, even at the expense of accuracy and practicality. Above-average programmers are driven away (I have several anecdotes), but not because type signatures are daunting, but because of the nature of some of the mistakes.I didn't say Scala is or isn't pragmatic or theoretic. Furthermore, I don't even subscribe to the (common?) idea that such a dichotomy exists.The Scala libraries have screwed the map signature. I've been working around Scala's mistakes for years now; particularly the libraries. Time to do it again.
Tony Morris
I don't consider Bloch or Yegge to be highly respected or intelligent, but they are indeed quite influential. Yes, this is unfortunate.
Tony Morris
+14  A: 

One way that the Scala community can help ease the fear of programmers new to Scala is to focus on practice and to teach by example--a lot of examples that start small and grow gradually larger. Here are a few sites that take this approach:

After spending some time on these sites, one quickly realizes that Scala and its libraries, though perhaps difficult to design and implement, are not so difficult to use, especially in the common cases.

Derek Mahar
+1 for the helpful links!
Carl Smotricz
+11  A: 

I think primary problem with that method is that the (implicit bf : CanBuildFrom[Repr, B, That]) goes without any explanation. Even though I know what implicit arguments are there's nothing indicating how this affects the call. Chasing through the scaladoc only leaves me more confused (few of the classes related to CanBuildFrom even have documentation).

I think a simple "there must be an implicit object in scope for bf that provides a builder for objects of type B into the return type That" would help somewhat, but it's kind of a heady concept when all you really want to do is map A's to B's. In fact, I'm not sure that's right, because I don't know what the type Repr means, and the documentation for Traversable certainly gives no clue at all.

So, I'm left with two options, neither of them pleasant:

  • Assume it will just work how the old map works and how map works in most other languages
  • Dig into the source code some more

I get that Scala is essentially exposing the guts of how these things work and that ultimately this is provide a way to do what oxbow_lakes is describing. But it's a distraction in the signature.

davetron5000
`Repr` is the traversable representation, ie. `List` or `Set` or `Map`. I think that, as a framework, if you are going to start looking at method signatures (rather than just use the methods by copying examples), you must understand the general design first. IMHO the Scaladoc should be full of example usage
oxbow_lakes
So, how would I have determined what `Repr` meant? I would expect an explanation in the scaladoc, but it was really not obvious to me. I think this is a common pattern in the scaladoc (look at `Actor.react` and `Actor.receive` - I'm told, and have seen, that they do totally different things, yet their scaladoc is identical).
davetron5000
I agree with davetron5000. I am quite familiar with Scala but implicit definitions still make my head ache. And the reason is not implicit per se but how they are used. There should definetely be better documentation and tool support for understanding Scala types.That said, I think the type system really has something important to offer. But we are still only in the beginning of the path of sensible programming.
egaga
+8  A: 

I totally agree with both the question and Martin's answer :). Even in Java, reading javadoc with generics is much harder than it should be due to the extra noise. This is compounded in Scala where implicit parameters are used as in the questions's example code (while the implicits do very useful collection-morphing stuff).

I don't think its a problem with the language per se - I think its more a tooling issue. And while I agree with what Jörg W Mittag says, I think looking at scaladoc (or the documentation of a type in your IDE) - it should require as little brain power as possible to grok what a method is, what it takes and returns. There shouldn't be a need to hack up a bit of algebra on a bit of paper to get it :)

For sure IDEs need a nice way to show all the methods for any variable/expression/type (which as with Martin's example can have all the generics inlined so its nice and easy to grok). I like Martin's idea of hiding the implicits by default too.

To take the example in scaladoc...

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

When looking at this in scaladoc I'd like the generic block [B, That] to be hidden by default as well as the implicit parameter (maybe they show if you hover a little icon with the mouse) - as its extra stuff to grok reading it which usually isn't that relevant. e.g. imagine if this looked like...

def map(f: A => B): That

nice and clear and obvious what it does. You might wonder what 'That' is, if you mouse over or click it it could expand the [B, That] text highlighting the 'That' for example.

Maybe a little icon could be used for the [] declaration and (implicit...) block so its clear there are little bits of the statement collapsed? Its hard to use a token for it, but I'll use a . for now...

def map.(f: A => B).: That

So by default the 'noise' of the type system is hidden from the main 80% of what folks need to look at - the method name, its parameter types and its return type in nice simple concise way - with little expandable links to the detail if you really care that much.

Mostly folks are reading scaladoc to find out what methods they can call on a type and what parameters they can pass. We're kinda overloading users with way too much detail right how IMHO.

Here's another example...

def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1]

Now if we hid the generics declaration its easier to read

def orElse(that: PartialFunction[A1, B1]): PartialFunction[A1, B1]

Then if folks hover over, say, A1 we could show the declaration of A1 being A1 <: A. Covariant and contravariant types in generics add lots of noise too which can be rendered in a much easier to grok way to users I think.

James Strachan
+2  A: 

Don't know Scala at all, however a few weeks ago I could not read Clojure. Now I can read most of it, but can not write anything yet beyond the most simplistic examples. I suspect Scala is no different. You need a good book or course depending on how you learn. Just reading the map declaration above, I got maybe 1/3 of it.

I believe the bigger problems are not the syntax of these languages, but adopting and internalizing the paradigms that make them usable in everyday production code. For me Java was not a huge leap from C++, which was not a huge leap from C, which was not a leap at all from Pascal, nor Basic etc... But coding in a functional language like Clojure is a huge leap (for me anyway). I guess in Scala you can code in Java style or Scala style. But in Clojure you will create quite the mess trying to keep your imperative habits from Java.

Jeff G
It's never about notation (or never more than, say, 10-15% about notation), it's always about the concepts. And if you're reasonably intelligent and you're not bogged down in decades of knowledge from different, possibly contradictory models (as I probably am), then it's usually not too hard to grasp these things. But if you're steeped in one way of thinking about and doing things, then it is at least some effort to adapt and many react against such changes. It's just human psychology / nature. (I wonder how Weinberg's Psychology of Computer Programming holds up after almost 40 years?)
Randall Schulz
@Randall Schultz and Jeff G: Syntax/notation is reasonably easy for a smart person to deal with. Different names for the same concepts, basically. Coming up to speed in a new language is just a matter of practice. HOWEVER, the step from procedural to functional programming is... frighteningly wide. It's really a different way of thinking. I've been dabbling with Clojure for some months and find it a relatively "easy," enjoyable FP language. But I still need inordinate amounts of time to puzzle out stuff that would be straightforward in procedural programming.
Carl Smotricz
+6  A: 

I'm a Scala beginner and I honestly don't see a problem with that type signature. The parameter is the function to map and the implicit parameter the builder to return the correct collection. Clear and readable.

The whole thing's quite elegant, actually. The builder type parameters let the compiler choose the correct return type while the implicit parameter mechanism hides this extra parameter from the class user. I tried this:

Map(1 -> "a", 2 -> "b").map((t) => (t _2) -> (t _1)) // returns Map("a" -> 1, "b" -> 2)
Map(1 -> "a", 2 -> "b").map((t) =>  t _2)            // returns List("a", "b")

That's polymorphism done right.

Now, granted, it's not a mainstream paradigm and it will scare away many. But, it will also attract many who value its expressiveness and elegance.

Thomas Heywood
A: 

What about error messages in use site?

And what about when comes the use case one needs to integrate existing types with a custom one that fits a DSL. One have to be well educated on matters of association, precedence, implicit conversions, implicit parameters, higher kinds, and maybe existential types.

It's very good to know that mostly it's simple but it's not necessarily enough. At least there must be one guy who knows this stuff if widespread library is to be designed.

Sujen
But one of the primary points is the difference between the library from the perspective of a *user* and the creators. Obviously the creators need an impressive understanding of the language features required (e.g. higher-kinded types, implicit precedence) - the question is: "do the users?"
oxbow_lakes
+8  A: 

Same thing in C++:

template <template <class, class> class C,
          class T,
          class A,
          class T_return,
          class T_arg
              >
C<T_return, typename A::rebind<T_return>::other>
map(C<T, A> &c,T_return(*func)(T_arg) )
{
    C<T_return, typename A::rebind<T_return>::other> res;
    for ( C<T,A>::iterator it=c.begin() ; it != c.end(); it++ ){
        res.push_back(func(*it));
    }
    return res;
}
skyde
...and they say Scala is obscure. Duh!
missingfaktor
Aiiieeeee! Ditto Rahul
oxbow_lakes
+2  A: 

I have a maths degree from Oxford too! It took me a while to 'get' the new collections stuff. But I like it a lot now that I do. In fact, the typing of 'map' was one of the first big things that bugged me in 2.7 (perhaps since the first thing I did was subclass one of the collection classes).

Reading Martin's paper on the new 2.8 collections really helped explain the use of implicits, but yes the documentation itself definitely needs to do a better job of explaining the role of different kind of implicits within method signatures of core APIs.

My main concern is more this: when is 2.8 going to be released? When will the bug reports stop coming in for it? have scala team bitten off more than they can chew with 2.8 / tried to change too much at once?

I'd really like to see 2.8 stabilised for release as a priority before adding anything else new at all, and wonder (while watching from the sidelines) if some improvements could be made to the way the development roadmap for the scala compiler is managed.

Matt