I like Scala. It's a JVM language, it's extremely powerful, but maybe it's too powerful for us mere mortals.
Eclipse allows very fast compilation times, but when I tried sbt, I gave up because I CAN'T wait for compilation: we're in 2013, I'm using a quad core at 3.4GHz, 12GB of RAM and SSD, so I'm not ready to wait.
Eclipse allows fast incremental compilation.
Scala's type system is very rich. I don't know if there exists any type that can't be expressed in Scala. Since I don't know if such a type exists, I don't miss it.
But that's probably too much, and in the end, idiomatic Scala emerges: some libraries use the type system in an idiomatic way. It's working, but understanding method signatures turns into a nightmare. Then you must learn the arcane of Scala to understand how the library works.
However, if YOUR Scala is simple enough, then the language can be cool, cooler than Java, and productive. Can be mixed with Java, runs fine for J2EE...
> I don't know if there exists any type that can't be expressed in Scala.
Scala has a very rich type system, but let us not get ahead of ourselves--Scala, being non-dependently typed, cannot type many useful programs.
For an example of a useful dependent type, consider giving division the type Number -> {x : Number | x != 0} -> Number. Giving division the type Number -> Number -> Number is similar to how older Javas would type List<String> as List and require all get operations to cast from Object--in both cases, the type system is unable to guarantee that your program won't crash.
If you want a glimpse of the state of the art of programming with dependent types, try Agda[0].
How does that actually work? Does that "type" basically compile down to an added n != 0 check at runtime, or is there more sophisticated dataflow analysis/theorem proving going on?
Usually it enforces statically that you cannot create an Integer that violates its preconditions. If you even do so dynamically it'll make sure there's a dynamic check before the dynamic value can substantiate the more specific type.
It is done statically. Types are a compile time construct, languages like Agda and Coq have no type information at runtime. This means if one can't statically prove that their types are correct the code won't compile.
For example if my function returns a Vector[A, N] (a vector of A's with size N), and I try to pass it's return value to a function that expects a of type Vector[A, 2] my code will not compile. This is because there is no way one can prove forall A N. Vector[A, N] satisfies Vector[A, 2].
Not all things are statically checkable. If you want to take in some runtime data and treat it as a Vector[A, 3] then you'll need to include a dynamically failing check like (List -> Maybe (Vector n a)).
I don't know Agda or Coq but I assume all it would take is to test the size and throw a runtime error for it to statically assert that it is the correct size after the test. Now the compiler is helping you write the runtime preconditions checks and handling that you should be writing anyway.
Yeah, that's exactly how dynamic data can enter a statically typed regime of code. Dependent types make it so that it's impossible to bring dynamic data into type-controlled parts of your code without first performing and passing those tests.
Which seems weak since smart developers should do that anyway, but (a) there's still some divide between "should" and "it's impossible" and (b) this is just the tip of the iceberg about what dependent types offer anyway.
It depends. In the most general case, you have to prove that the program you have given has the type you have asserted. This is similar to proving a mathematical theorem. Generally, the computer will assist you in this endeavor--for example, if you want to prove that A implies B, and A and B are linear inequalities, this can be solved automatically.
Generally, the computer will assist you in this endeavor
Kinda. Let's be honest: in production this often turns into a pain in the ass. There's some value in dependent typing, but providing evidence that concatenating UTF-8 strings is associative is not one of them.
I have faith that this will get better. We need standard libraries of proofs just as much as we need standard libraries of code. I know Coq has made progress on this, but it's still early days.
I do agree with you that there are times when 'full' type checking is inappropriate. Typing is a spectrum, and it's a bit of an art to decide how detailed of guarantees to give for your API.
Agda and Idris are both very interesting to me, especially the latter since it was designed with systems programming (read: real-world applications) at its core. They both seem kind of like beefed-up Haskell.
However, I wonder how much actual utility they can provide, seeing as (1) dependent typing is generally acknowledged to be rather difficult (and that's a statement coming from those who generally tend to already be good at a language like Haskell), and then also (2) the fact that a great deal of real-world applications, such as FFI, accepting data over a wire, dealing with exceptions and faulty input, etc, mean that no matter how bullet-proof the code you write is, you'll still have to account for all of the ugliness which the world can throw at you, which means unit testing, exception handling and other things which seem to undermine - to a degree - the strengths of strong typing in the first place.
Or am I exaggerating things? I've written a lot in Haskell and enjoy it a great deal, but at work I use Python and JavaScript, and honestly, although there are some things that would be streamlined away by a strong typing system, particularly in the development cycle, there are still a ton of ugly, mundane real-world things that would still need to be dealt with in much the same way if they were written in Haskell. I would still love to have the opportunity to write in Haskell (or Agda or Idris, etc) at work, but I'm not sure how much trouble it would save me from at the end of the day. Would it? And would the additional mental hurdles of dependent typing add real tangible benefits on top of this?
Rich type system? Can Scala express {x|x is integer, x >= 3} as a type? ATS can. We can even transform this set into unsigned types in C/C++, but in JVM there's no primitive simple way.
As a java Dev I have been watching Scala to see what people make of it. It seems like Scala is generally perceived as an academic exercise.
We all want more powerful tools and infinite expression but at what point are we bikeshedding languages instead of building transparently clear solutions?
It seems more to me to be an academic exercise in compiler complexity that has been wrapped in a shell of "lookit! Java++" as a play for industry acceptance. I haven't been working with it for long, but I feel that there's a lot of interesting stuff that has become unusably complex because of the design decision to support toll-free Java interop. That makes me nervous.
There's a lot of "seems" going around from people who haven't used the language, or dynamic-typing folk who obviously aren't going to pick a language that bets the farm on static types.
As a long-time Java dev myself, Scala is solving problems you don't even realise you have, because you don't know to look for them.
Powerful types, immutable state and FP make a world of difference for writing clear solutions, with better abstractions, less code, less bugs and less bullshit than the horrendous status quo of corporate Java development.
Actually I just want to reiterate, regardless of typing problems that CAN exist and be prevented by a compiler, I do t ha e those problems in my codebase and neither do most people.
> less code, less bugs and less bullshit than the horrendous status quo of corporate Java development.
It may take some getting used to syntax and design wise, but being able to code things up in 1/10 the size of other languages completely blows away the disadvantages of Scala.
I think it may be but I came to the Java ecosystem to escape RoR.... it seems we should be able to do better than emulating Rails minus the existing gem community, no?
I have much more faith in the JVM but would like to see it provide a step beyond Rails rather than catching up. Play is nice because it is trying to accomplish this with Akka, though yes I see there are other issues. As mentioned in another comment, I'm kindof just wishing there was a cool Clojure framework. Maybe I will try one even there is not so much of a consensus as there are around these other emerging JVM frameworks...
I'm trying to escape PHP, but terminal velocity is hard to achieve since now I have Laravel to work with. I'm looking to venture off either into JVM space or Go.
I tried the same thing. I now play with C and Nimrod... And just doubled down on PHP. You'd be amazed at how powerful it can be in the right hands... Or not, as you're using Laravel ;)
Oh come on, that's not fair :) Laravel is a godsend compared to what I had to work with before. However I think I am using it wrong, I dump almost everything into controllers and views and use models for relationships only. Those controllers got fat, real fat.
Clojure doesn't tend to do frameworks on the scale of Rails; all the components exist, but the price for your application only including the parts you use is that you're more or less expected to write the glue code between them.
I've found because of the composability of clojure and its powerful macros, you find that your 'framework' ends up a small collection of macros custom to your application.
I think so. I came from straight servlets, Struts and Liferay Portal and Grails was amazing to me. I can get apps up and running so much faster, with little configuration and things just work. I have never done RoR, so I can't make a comparison, but it is pretty nice IMHO and it's easy to get started, yet is very powerful.
IIRC the Groovy founder said he wouldn't've bothered making Groovy if he'd known Scala existed. You get all the power and flexibility without having to give up type safety.
He certainly did, in July 2009 [1]. To quote him in context:
Though my tip though for the long term replacement of javac is Scala. I'm very impressed with it! I can honestly say if someone had shown me the Programming in Scala book by by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy. So why Scala? Scala is statically typed and compiles down to the same fast bytecode as Java so its usually about as fast as Java (sometimes a little faster sometimes a little slower). e.g. compare how well Scala does in some benchmarks with groovy or jruby. Or this. Note speed isn't everything - there are times when you might want to trade code thats 10x slower for more productivity and conciseness; but for a long term replacement for javac speed is important.
His dissatisfaction with Groovy concerned more than just its speed, and originated much earlier, see his very last Groovy mailing list posting [2] in Dec 2005 just before he left the Groovy development team:
The MOP and introspection APIs do NOT solve the horribly broken name resolution rules in the current RI of Groovy [...] I see no argument yet for why we have to throw away decades of language research and development with respect to name resolution across the language as a whole [...] It just feels totally wrong to break Closures across the entire language just because of some use cases for Markup.
Groovy is sloooooooow, its recent static typing is buggugguggy and not even used by Grails or Gradle, and its closures are broken. Its "recent surge in popularity" was also probably based on deception [3]:
Groovy, which turned up in the [Tiobe] 18th spot last month [October 2013], slid back down to a number 32 ranking [Nov 2013]. "After a long discussion with one of the Tiobe index readers, it turned out that the data that is produced by one of the Chinese sites that we track is interpreted incorrectly by our algorithms. So this was a bug," Janssen said. "After we had fixed this bug, Groovy lost much of its ratings." The ratings slip takes Groovy from a 0.658 percent rating last month to 0.393 percent this month.
This has happened before. In April 2011, Groovy fell from #25 to #65 on Tiobe in a single month after they increased the number of search engines they monitor. Groovy had begun its short-lived rise just after December 2010 when Groovy tech lead Jochen Theodorou "volunteered" his services to Tiobe to help them improve their algorithms.
Except that a huge chunk of the industry outside the Hacker News, Reddit, and start-up bubble is using Java or C#. In fact, I have many CS and AI graduates as friends, who love programming in the Java ecosystem.
After using Haskell, using Java makes me very sad...
In Java's OO paradigm, instance variables are inherently defined separately from their initialization, making it quite difficult to make sure they're always used when initialized, properly.
The nullability stuff bites me over and over :(
Forgetting to use .start() on a thread is a stupid runtime error, instead of using some design where it isn't possible to forget .start() or at least get a compile-time error.
I am also using a lot of C in parallel, and with the C preprocessor, I am finding that C is often more expressive and nicer to use than Java!
Everything takes ridiculous amounts of code.
For example, in Haskell, I can write:
threadIds <- replicateM 10 . forkIO . forever $ do
code .. here ..
To get a thread-pool of 10 threads looping around my code, and put their thread ids in a variable.
In Java, this requires so much effort!
Not to mention the utter lack of sum types and pattern-matching, making tons of Java code that looks like:
For thread pools, use ExecutorService or the Guava flavour. The lack of pattern-matching is a pain, but note that you can use Enum values in switch statements.
As is often the case, writing the code from scratch in Haskell is easier than reusing a library in Java..
Android uses named integers rather than enums, due to some issue with Java enums.. And the switch would only help a bit, the main problem is needing to correctly interpret the associated payload according to the message type. That's what sum types give you, which Java doesn't properly have.
They could be emulated with visitor pattern, if one is masochistic...
I never understood why Java didn't go to proper sum types when it introduced enums. They all have to have the same shape, just distinguished by their method implementations, same as always in OO. What kind mechanism for describing alternatives is that?
I've been using Scala just to learn Play framework (I know I could use Java but I thought I'd be adventurous).
I think in truth, though, if there were a web framework in Clojure as well received as Play I would be bounding down that path instead. Clojure seems to be where a lot of the JVM interested is heading yet we're not there yet for some reason.
I've been wondering - having never used a web framework except for some RoR - what people miss in the idiomatic Clojure way of doing web (composing libraries like Ring, Compojure, Enlive etc). Care to share?
Honestly I haven't used Ring/Compojure/Enlive beyond tutorials so at this point I'm very intrigued but don't have much to say yet.
My belief though is that there is some peace of mind that comes from the idea of what you might call "page composition" -- that this piece of data sits in this template, that it rides on top of this simple model, that it is in ORM from database. There is a huge amount of linearity and convention throughout the stack and because of the dynamic nature of Ruby lots of gems can be sprinkled throughout without one really understanding what they do.
Now, I'm certain this level of abstraction and functional/mixin kindof stuff can be achieved in a Clojure framework but I think it is generally perceived as being a bit more non-linear and DIY (libraries not necessarily playing nicely together). As in "yes I can get all of these pieces together but then if down the line I have to change this piece, how will I accomplish it without breaking everything". Essentially, I think the perception of OO is more alluring in terms of project cohesion, whereas functional programming is seen more of a supposedly incorrect assumption that an HTML document is simply an assembled mass of text.
I'm really just trying to convey that RoR and the like seem to be making a COMPLETE ("in a few lines I can do anything short of my business's custom domain logic") framework out of the box and perhaps there is some stigma attached to the nature of Lisp that makes it seem as though framework developers are not striving to cross these bridges and there is less of a community to keep them in check.
Eh, I wish that made more sense but this is a lot of conjecture based on perceptions -- it's clear that a lot of these communities emerge from hype & reactionary values moreso than anything else. People wanted to shift away from PHP and be more productive without getting radically far away conceptually. I just got dizzy thinking about this lol... but yeah I think Java developers are a bit more open-minded when it comes to application development, seeing things more matter-of-factly than the languages with only MVC/Model2 kind of frameworks. I think if an attractively-packaged Clojure library were to emerge and get the right publicity (sad but thats how the web dev world is...) it could steal the hearts of many Java devs.
In my limited experience with Clojure it seems fun AND powerful. Yes there is a learning curve but that is to take it above and beyond. The simple functionality of most web apps could probably be achieved without writing anything too mind-bending.
Please do respond even if that response involves completely ignoring my rambling... I'm very curious to understand the Clojure community better :)
"Clojurists looking for a standard way to build internet applications will love Pedestal. Rather than composing art out of found objects, they will now be able to mold a single, consistent form to match their vision.
Pedestal may also appeal to developers who have been nervously approaching a functional language but who haven't yet mustered the courage to ask it out on a date. It provides a sterling example of how to use the Clojure ecosystem to its best advantage, reducing the friction usually associated with a language switch."
> My belief though is that there is some peace of mind that comes from the
> idea of what you might call "page composition" -- that this piece of data
> sits in this template, that it rides on top of this simple model, that it
> is in ORM from database. There is a huge amount of linearity and convention
> throughout the stack and because of the dynamic nature of Ruby lots of gems
> can be sprinkled throughout without one really understanding what they do.
Actually, the problem with OO and my experience with Rails is this linearity quickly becomes a web where deriving the sequence of events encompasses more and more of your time as the project grows.
Objects call objects across the system and change the state of each other without care. Making a trivial change involves unrolling this web every time.
And that's why I think you have this backwards:
> Now, I'm certain this level of abstraction and functional/mixin kindof stuff can be
> achieved in a Clojure framework but I think it is generally perceived as being a bit
> more non-linear and DIY (libraries not necessarily playing nicely together). As in
> "yes I can get all of these pieces together but then if down the line I have to change
> this piece, how will I accomplish it without breaking everything".
`require`ing a Ruby gem is as non-linear as you can get. It's global with no entry-point. A gem's presence and effects are not obvious. They're often configured with some mutation like:
MyGem.config do |c|
c.key = "secret"
end
Meanwhile, it's obvious when a namespace of Clojure functions is included. And since they're just functions, they're trivial to compose. Completely different experience from what I was used to in Ruby.
thanks for your input. I see what you're saying about the Closure namespaces and function system making more sense. That's what has been attracting me toward it, along with some general fondness for the elegance of Clojure.
I feel you whole-heartedly about the tangled web of OO. That's why I ultimately chose to leave Rails & start pursuing JVM languages. JVM languages seem to be daunting to Rails/Django folks because of all the "boilerplate, syntax, complexity" but I've found that a lot of the tools are so mature that it is not really such a burden. So yes, as an aspiring programmer who wants to have a reach beyond CRUD, the mystery of Rails & it's "fugly" libs eventually turned me off. Aside from things breaking/slowingdown with every version and needing excessive optimization not to accumulate at the interpreter, I came to the realization that the extra time that would be needed to understand more technologies for the different layers of the application (with Java.... Spring/Hibernate/etc.) there is a gain in that well... you actually understand what is going on rather than this tangled mess. I often had to re-factor code in Rails to kindof fit awkwardly between gems. From studying Javascript I learned a lot about asynchronous/aspect-oriented programming and am pleased to see that these concurrency issues are fundamental to most work that is happening on the JVM. I thought Scala/Play was a healthy medium between these two worlds but I'm starting to understand that maybe one needn't compromise.
I was a full-time Rails developer until a crescendo of disillusionment finally cajoled me to learn Clojure.
I don't really know that I miss anything. The things I might've thought I'd miss are the things that ended up souring the taste of Rails.
Having to come up with my own abstractions or recreate familiar conventions or set up a database were areas where I had to cut my teeth, but I also had to cut my teeth on Rails when I was learning it.
Rather than missing anything from Rails, I find myself using Rails' conventions as a loose model and then simplifying it. For example, my "templates" are now just functions that render html. My "layouts" are just functions that get applied to templates. I don't need to read Rails' template rendering guide to come up with a hack. Instead, modifying my templating system is trivial and obvious.
Thank you for this comment. I'm starting a hobby webapp project and wanted to try Clojure but was probably going to choose RoR out of fear. Now I'll use Clojure :)
Would be interesting to see a blog post demo'ing your workflow.
I'm working with these libraries for a web project now, and I'd say the main problem is lack of comprehensive documentation. If you're doing something slightly off the beaten path and get stuck, it's quite likely that you'll have to resort to the source code to solve your problem.
There's nothing so terrible about that per se--it's a great way to learn--but it can feel like a high friction workflow compared to Rails, especially getting started. I think it's primarily a function of community size and library maturity, but there's a cultural element as well. Rails has more of a beginner-friendliness-is-good mindset (even when library internals are fugly), while in Clojure the focus is more on the strength of the functionality and less on easily grokkable apis (though there are notable exceptions).
This space for Clojure is changing rapidly. The prevailing approach to web dev in Clojure has been to assemble the (already available) libraries that you need into an application. For some, that's sufficient. Others likely need more structure.
The Luminus micro-framework (http://www.luminusweb.net/) is a great choice providing a starting structure around existing libraries. Caribou (http://let-caribou.in/) is a more full-featured framework for building web apps. Pedestal (http://pedestal.io/) provides heavy-duty tools for creating data-heavy single-page apps.
I started learning Scala almost a year ago at my latest job - we use it for production systems at a large multinational investment bank.
Coming to Scala from experience including C, Java and Haskell, I intially found Scala quite difficult. It is true that there are some things in Scala that are not obvious to newcomers, and that are difficult to discover for yourself - such as the use of Implicits, and the strange precedence and binding rules for operator syntax.
That said, it doesn't take long to learn, and once you do, it all makes sense. There are other great languages out there (I'd say Haskell is one), but compared to for example Java, or one of the dynamically typed languages, Scala is superb.
Types, whilst not having the full H-M inference, are brilliant. That the author complains about having types rather than a simple map for keys shows a misunderstanding of what they are there for - the idea is to allow the compiler to prove at run-time what is valid code and what isn't. He comments that tests run too slowly in Scala (they don't - for our production systems building in SBT, a typical test run is significantly less than 10 seconds) but a lot of the time I don't even need to go that far - my IDE already highlights errors in the code as I type, where I have passed in incorrect or insufficient data.
Also, the author makes a strange comment that H-M 'enabled' Monads, and the comment is written in a way that implies that Scala does not have Monads. This is incorrect. Scala has monads, and the Scalaz library has huge support for Monadic programming. We use Monads and Applicative Functors (a close relative) daily to build high level abstractions, and we couldn't live without them. In Scala we say flatMap rather than bind (or >>=), but we mean the same thing. Although thanks to the same flexible method naming that the author complains about, you can in fact say >>= if you wish.
If you've only got a couple of days to use a language, and you're using it for a tiny project, then Scala is not for you. If want to learn a language that can make you vastly more productive whilst at the same time making your code safer and more robust, Scala is a very effective candidate. It's not the only candidate, but you should at least consider it.
I'll echo all of this (minus scalaz, we don't use that).
I'll give an example of the power of Scala's type system. When I first convinced one of our founders to give Scala a try, he used it to write the first pass of our analytics service. He'd never written Scala before but once it compiled, it ran correctly on the first try, that's the power of its type system.
Not to be too big of an ass, but this could just be the skill of your founder. Or do you believe it is impossible to have compiling code that does not do as its author intended?
Obviously it's possible to write code that compiles while still not meeting requirements. My point is that the by leveraging the type system he was able to offload a lot of those checks to compile time rather than runtime.
It's not impossible, but it's harder in Scala. Actually the closest comparison I could make would be Python, where I had a similar experience - as soon as my code stopped producing errors, it was doing what I wanted it to (the difference being that the errors were at runtime rather than compile time). Whereas in Java and C and even ML I've written programs that compiled correctly but did something very different from what they were meant to.
Having never used Scala before, does its type system provide details about errors that other languages do not? Watching a compile fail because of an incorrect type is not something I have run into very often, if ever, in other languages that provide similar type systems.
I mean mistakes can happen and if the type system can catch it for free, so to speak, that is great. I'm not about to argue that it is completely useless. But in terms of probabilities of what kind of bugs might be introduced, type errors seem to be on the low end.
To infer that Scala's type system is powerful enough to catch the more common types of mistakes programmers make, that is quite an impressive claim. I am curious to know more.
In Haskell, and I assume Scala, you can name types of the same form, so I might say a TimeSeries is a list of floating point values. If I use that data type, you can't accidentally pass a different kind of list of floating points even though they're the same type.
A simple example: consider scalaz's NonEmptyList[T] class, which turns a failure to populate a list into a compile error rather than a runtime error.
A more complicated example. In one scala system I worked on we had a master/slave postgres db system. We were replacing a legacy RoR system with a Scala system, and in the RoR system there were all sorts of data inconsistency errors caused by people writing to master and reading from the slaves before replication occurred.
In the Scala system which replaced it, we set up a monadic action system. A function which hit the database would have a type signature either PReader[T] or PWriter[T] - this was the only way to access a java.sql.Connection short of manually calling jdbc. Combining the two forms yields a PWriter:
for {
_ <- putObjectToDB(args)
obj <- getObjectFromDB(args)
yield (render(obj)) // is a PWriter[_]
The whole operation runs in a single transaction against the correct database, and any attempt to do the wrong thing is a compile error.
It's partly culture; Scala makes types that little bit easier to use (e.g. case classes, type inference), so things that you might pass as an untyped Map[String, Object] in other languages, you tend to pass as a case class instead. e.g. using spray in scala, the type system will catch if you misspell a HTTP header, because, as the article complains about, they're represented as types.
(Though of course there is an escape hatch, you can use RawHeader(name, value) if you need to).
Scala has dependent type support, so, yes, it is quite more powerful than most languages in widespread use. You can look at the Shapeless library to see that at work.
However, that is not really what's going on... though Scala type system, even without dependent types, is strictly more powerful that Java's, it really comes down to the ease of use: Scala programmers tend to use types liberally (which was one of the criticisms of the article), and that is part of the "magic".
Part of this is how easy it is to define a type: it can be as short as a single line. So you'll see way less String types in Scala, for instance, or "one type to do it all" like the article wanted for HTTP. Instead, you get many types, in which invalid states are not possible and, therefore, getting the types right is enough to ensure there are no invalid states.
Likewise, the partial type inference offered by Scala makes it possible to not worry about all these types: the compiler knows what type you got, and knows whether it can be used the way you are using it, so you don't have to keep looking up types to get things accomplished, but still get to have the types.
Another part is that Scala support higher order types, something not supported by Java, which makes them more useful. That's what allows monads & companions come in and make an appearance -- it's not that you can't write a monad in Java, it's just that you can't abstract over them.
The final part is emphasis on immutability. When you stick to immutable objects representing valid states, the space for errors not caught by the type system is greatly reduced.
Let's get back to the headers, then. First, yes, you are allowed to add arbitrary headers (which is supported by Spray through RawHeader, something it took me 30 seconds to find out, even though I have never used Spray and have little familiarity with it), but section 14 of RFC 2616 has a nice list of standard headers and the rules they are expected to abide by, so let's have them.
And if you have a header, and it is a X-Forwarded-For, isn't it reasonable to expect the value to be a valid remote address? It is supposed to be a valid remote address, after all. So, if you ask for this header, should you simply get a string that may or may not be actually valid, or should the type system give you an Option that may contain Some valid header, or None, therefore ensuring that you don't just assume you are getting the right thing? And if you get something and retrieve the value, is it preferable to just get a string, that might lead to some ad hoc parsing of the address, or some actual type where you can easily retrieve information in a safe manner?
The Scala community will usually think that yes, that's a good idea, and design the APIs accordingly.
May you expand on the type of systems you are building with Scala? I have previous work experience in a multinational bank that ran Java or C# on everything.
I agree with everything above. At Vonjour we use Scala. From a business standpoint, our only reluctance was that hiring was going to be more difficult. However, we have received higher quality candidates that are eager to learn applying for our positions.
> That the author complains about having types rather than a simple map for keys shows a misunderstanding of what they are there for - the idea is to allow the compiler to prove at run-time what is valid code and what isn't.
There's some evidence from what the author wrote he's aware of the benefits of type systems. The question he raises is whether the developers who wrote Spray modeled the problem domain well by choosing this particular set of types (his opinion is clearly no).
> the author makes a strange comment that H-M 'enabled' Monads, and the comment is written in a way that implies that Scala does not have Monads.
Given that the author immediately follows his "enabled" statement with the idea that monads can be used in a type-free language, I think it's most likely he means that H-M has been the ground where the use of monads has been largely developed/defined, not that monads can't be used in either Scala or even something with a considerably less expressive type system.
> Coming to Scala from experience including C, Java and Haskell, I intially found Scala quite difficult.
I think because it allows you to do OOP and FP, Scala becomes difficult since it is so easy to mix the styles. Similar to C and C++, this is very powerful, but also very dangerous. The main learning curve is programming in a way so you don't shoot yourself in the foot while using its flexibility.
To be honest with you, I use Scala as a better Java. Which means I still code imperatively (and use null instead of None) but with less noise (semi colons etc).
But, esp when working with collections, I take advantage of Scala's features. It's not perfect, but it works wonderfully. I can always revisit/refactor my code again later.
You might be better off using a pre-release snapshot of Java 8 as a better Java. You'll get closures, functional collections, and better type inference. I bet Eclipse and Intellij support it better too.
Java 8 for me is still far from making me move from Scala. Lambda expressions is only a small part of what I like about Scala. For me Scala is a statically typed Ruby / Python / JavaScript that runs on the JVM, and is very Java like.
I would change some things in it, but a language doesn't have to be revolutionary to make me want to use it.
Things I have in Scala that I like and Java 8 won't provide
(many are syntactic sugars and non critical stuff, I know, but I like it, I'm spoiled)
- implicit conversions. some hate it, I love it. It allows much better "pimp my library" mechanism than Ruby's and it's very easy to write extensions to your or 3rd party extensions in a safe and easy manner
- duck typing, e.g. allows to write a "try with resource" without native support for anything that implements "close"
- automatic tuples
- better type inference
- semicolons, hate them
- automatic equals and hashcode for case classes
- case classes
- futures and promises
- by name parameter passing (passing a block of code without running it)
- partial functions, multiple parameter lists
- for comprehensions
- pattern matching
- nested functions
- lazy vals
- everything is an expression
- String interpolation
- multiline string
- default parameters
- named parameters
- pattern matching
- everything is immutable by default
- very string type system
I think that's it. Yes, Scala is infamous as the language that took many many features from other languages and piled it all together, well, fine with me! you say more features that are great in other languages and make people productive? (and are kind of expected, like default parameters etc) I say bring them on and the more the merrier. I can choose which features I want to use out of the way too many features the languages, much better than waiting years for features to be added.
Hater's gonna hate, I'm still going to write Scala until something better comes around. (Nimrod? Kotlin? Ceylon? TypeScript? Dart? perhaps even Go? Don't know... time will tell)
Yeah, I had hopes for Kotlin, but so far they've dropped pattern matching. Still, it's more likely to gain traction as a 'better than Java, but not _too_ much more powerful' language, IMO. For example, methods (and extension methods) can still be used as operators, but have to be valid Java names, so no methods called <:< (I pronounce it as 'angry wizard') allowed.
* You might be better off using a pre-release snapshot of Java 8 as a better Java. You'll get closures, functional collections, and better type inference. I bet Eclipse and Intellij support it better too.*
You lose out on most of the features of Scala, and IntelliJ supports Scala very well.
I'm using Scala because of Akka. An extremely powerful library that does a good job of hiding the complexities while still allowing you to be flexible.
That's a gratuitously category-theoretic explanation, all you need to explain covariance and contravariance is is-a.
An immutable List of Foos is a List of Bars if a Foo is a Bar. A function taking X and returning Y is a function taking A and returning B if A is a X and Y is a B.
It's just answering the question "Can I use type relationships to guarantee that I will have no run-time conversion failures?"
T is covariant (positive) if A ≤: B ⇒ T<A> ≤: T<B>. T is contravariant (negative) if A ≤: B ⇒ T<B> ≤: T<A> (i.e., the other way around). Pretty simple stuff.
I'm always interested to see intelligent criticisms of one of my choice languages. Let's take a look at what he has to say:
Slow build times complaint
> It is essentially impossible to practice TDD in Scala simply due to the time it takes to compile.
Hrmm, that's interesting, because it sure seems like other people are able to do this. I agree, the slow build times are annoying, but let's not exaggerate.
SBT critiques
>That punctuation-strewn build system I was forced to use was just taking advantage of Scala’s ridiculously flexible syntax.
Yeah, I get it, everyone makes fun of SBT's syntax.
Language is complicated
This is where it just kind of descends into whining about how 'hard' the language is. He claims javascript is a "simple" language. Does he just not count the weird edge cases when thinking about complexity?
Type inference complaint
> And this is the real death knell for Scala. Hindley-Milner Type Inference is a fantastic thing.... It’s enabled monads, which you want to be able to understand and then use in a type-free language.
WAT. I don't think those words mean what you think they mean.
>In my mind, Hindley-Milner was always the promise and the pay-off for Scala...I know this is the fault of the JVM’s use of type erasure. I don’t care.
O REALLY? Go on...
Maybe if this guy had cared enough to do a five second google he'd realize that Scala doesn't use hindley-milner type inference.
Bottom line is, I think I have a good understanding of the type of programmer this guy is, and it's exemplified nicely in this quote right here:
>Sure, with another couple hours we would have been able to figure it out… [but] We ended up copying and pasting the same four lines into all our endpoints. A dark moment.
For an intelligent critique of the scala langauge see here:
The "simple language" comment was about CoffeeScript, not Javascript. One of the common complaints about CS is that you absolutely need to know what JS every nontrivial CS contruct compiles to, but he doesn't consider this a big deal because there simply aren't very many of them. Scala, on the other hand, has more features that he considers "magic" than he can easily keep track of.
the sbt point is really outdated; sbt 0.13 only ever requires you to use "foo := bar" (assign bar to foo), though one might choose to use convenience operators such as "foo += bar" (append bar to foo). sbt's syntax has been cleaned up nicely and now it has very clean syntax.
I worked with the article's author. The build system mentioned was not sbt but a custom, in house, thing that was really just a medium sized Scala program that was used to build a number of large C++ programs, libraries and some other things). There were no build scripts but just raw Scala code fragments distributed over the hundreds of directories involved. Overall it was a pretty awful system but it would have been awful in any language given the approach taken (I hated it with a passion).
TDD in Scala is very easy. I do it every day on several large Play! applications. I feel as though the author is doing something crazy, like compiling everything on every test run and always running all the tests.
He states that H-M is not used because of the lack of reified generics, which is completely irrelevant. (Hint: type systems perform analysis at compile time; "reified generics" means having type arguments available at run-time.) H-M is not used because it is not compatible with subtyping or method overloading, which are both critical for Java interop. There is no particular reason that Scala needs to use exactly the H-M system.
What is my biggest gripe theoretical gripe about Scala is that Trait order is important! Because traits can override common function. A class that is e.g. Ball with traits Shiny and Red is NOT the same as e.g. Ball with traits Red and Shiny. Why? Why complicate testing to a point where you need not only test traits for correct behavior, and not just composing of Traits, but even the order in which they are composed? Why?! Why complicate it so much?
Note: It's been a while since I've seen traits, this might have changed for better.
To me Scala is essentially if Java, Haskell and C++ went to a wizard to have a child. The result is a magical mess. I seriously think that Scala has at least twice as many concepts as C++ and same if not greater number of really weird edge cases. I don't want to keep Scala in my mind, no more than I want to keep Necromicon.
As long as your traits are independent, the order does not matter. Anyway, how do you imagine this could be done better? For order to not matter, the linearization could not be possible and we'd end up with something much more complex and ugly like multiple inheritance in C++ with all the diamond inheritance problems, etc.
Don't have an answer right this minute, but I think eschewing/forbidding variables in trait would prevent the most obvious such collisions.
If you can't override variables, you can't silently change the structure to depend on trait order. You'd have to explicitly state order.
PS. Of course if you have several same signature methods that call super, which is generated depending on order, same problem persist. So, forbidding variables and calling super elements should deal with most "magical" interactions.
If you can't call super nor use variables then this takes quite a lot of power from traits. IMHO being able to stack many traits one on another is a nice pattern.
Actually, there's a very elegant solution to the diamond problem. Eiffel does this with a renaming mechanism. Martin Odersky certainly knew about Eiffel's solution when he designed Scala, but my guess is that, he chose the simpler solution of traits, just like most languages, because general multiple inheritance just isn't too useful.
Still, it's a shame that most people interested in programming languages have never heard about Eiffel, or ever read the superb book "Object-Oriented Software Construction" by Eiffel's creator, Bertrand Meyer.
Eiffel has many flaws (the most proeminent being the complete lack of support for functional idioms), but it has very good ideas as well. (Perhaps the most popular influence Eiffel had on other languages is Design by Contract and the uniform access principle, which you see in most "modern" languages.)
I loved Play 1.x(early adopter also) but I have since moved on. I gave Play 2 a solid chance. Scala programmers seem to turn everything into some kind of academic paper.
I've been a critic of Play 2 on a number of occasions on HN but I don't understand the complaint. What is causing you to create URLs with trailing slashes?
What is causing you to create URLs without trailing slashes? 99% of all web frameworks allow for optional trailing slash. Go to any website. A url with or without a trailing slash typically works, it either redirects to no trailing slash or just renders the same page.
What is causing me to create URLs without trailing slashes is the proper use of Play's route-to-URL mapping system. I don't emit trailing slashes because Play doesn't.
I wanted to create pretty urls but I couldn't do it in a simple way because the developers thought that in a path can not be optional parts, like:
/article/1/article-slug and /article/1
So they removed a useful feature. And it was in a 2.x -> 2.x+1 release... Yesterday it worked, today not. I was not happy. :)
My othern concern with scala, what is mentioned in the article, is the operator usage.
How am I supposed to "invent" this <:< notation for adding headers? (dispatch lib)
`val svc = url(object_url) <:< Map("User-Agent" -> "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)")`
or in squeryl, converting a boolean into a "query boolean":
```
val fls = false
fls.~.?
```
Other than these, I like it. When I am coding in JS or PHP I always praise the scala types/ compile time checks. I am almost afraid of dynamic typing since I tried scala. :)
Consider giving TypeScript a try then. It offers optional, structural static typing, that while not nearly as powerful (or sound) as Scala's, is still better than not having it.
And the fact that its completely optional means that its easy to get it out of the way when its not possible to express some constructs with it.
The section on HTTP headers and typing is a little concerning to me. I've been making rust-http recently and (before I was aware of Spray) I felt strongly about the typing. So, I'd like to discuss this. Am I wrong after all? Here clearly is someone that disagrees with me. I think I should probably write up a long blog post on the topic explaining my reasoning and so forth.
rust-http is, at present at least, rejecting the standard practice of stringly typed headers and is using strongly typed headers.
> ... and even types for every ‘known’ HTTP header.
> The known HTTP header part was particularly ridiculous. HTTP headers are defined as simple key/value pairs. You’re supposed to be allowed to add arbitrary headers. You’re not supposed to be constrained by the framework you’re using not having any support for CORS yet.
He has taken a strong position against this strong typing; I take a similarly strong position for such strong typing.
Yes, HTTP headers are defined as simple key/value pairs. But headers are not text; they are data. XML is defined as text. Should we use regular expressions to work with it? (True, it also has the DOM defined. But HTTP headers also have a grammar defined—it just happens to include the admissibility of extension headers.)
HTTP is a serialisation format for messages; messages made up of computer-readable data, not text.
As I also note there, I would not attempt such a scheme in a language like Python (my primary language for some years) because its type system is not well adjusted to something like this; I am certain it would cause many problems and feel it likely it would cause more than it solved. But in a language with a solid type system capable of expressing these things, taking advantage of it should lead to a faster, more correct program.
In the end, I believe strongly typed headers are a good thing to have (it will actually make most code distinctly nicer—e.g. ``response.headers.date = Some(now())`` instead of ``response.headers.set("Date", now().to_http_header())``). The implementation of the scheme in rust-http is certainly not perfect yet; I'm not happy with it at present; I'm expecting to turn the extension headers into a trait object, and I've even considered crazy ideas like allowing users of the library to make their own header collection (request.headers and response.headers) types—that would allow custom headers to be made first-class citizens but could lead to compatibility problems.
Still, I don't want to make something that I believe should be the best HTTP library around and find that people hate to use it. What do you think about this header matter?
IMHO, libraries like this should always have an easy "out", where the default is strongly typed, but the user of the library can explicitly escape the known behavior if need be.
As a (albeit poor example), I once inherited a click tracking system that uses Java Jersey. The standard response object has a .redirect(URI uri) method. Unfortunately, many "URI"s we receive from the world are not actually value, and the java URI object refuses to build URI objects from the string. Fortunately, one can simply call .setHeader(String, String) and be done with it.
At present, in rust-http, invalid values will be dropped; that will be changing so that you can retrieve a bad header value (https://github.com/chris-morgan/rust-http/issues/27). Writing invalid HTTP, on the other hand, is something that I'm in two minds about. You shouldn't be allowed to do it, but it may be necessary somewhere along the way. At present, you can write invalid headers through the use of the extension headers—`response.headers.extension.set(~"Date", ~"invalid")`, for example. I certainly don't want to advertise it broadly, but I'm thinking guaranteeing that that will always work is perhaps the best plan.
You should always allow the user to get the raw HTTP request. Sometimes things just get funky and you need to drop down to that level. Abstraction is nice except when it isn't, if you understand my meaning.
The author isn't wanting to write invalid headers. He's wanting to write perfectly valid headers that the framework he's using didn't allow him to write.
When the framework treats a a valid http header as invalid the framework is probably using the wrong abstraction for http headers.
Spray allows you to define custom (even invalid) headers, all you have to do is subclass HttpHeader. I'm sure the author knew this, but it's not obvious from his criticism.
The way I look at type systems is they are an automatic proof system for programs. So you must ask yourself what are you proving with your type system? I looked at your write up on the github issue and from what I see you are moving some checking into compile time. However, when it comes to "parsing problems" (like: HTTP, XML, command line args, etc...) there isn't much to move. This is because the data doesn't yet exist that the proof operates on. So it really can only check the plumbing after the parsing - which often isn't that much.
In the past when I have used such libraries they have been a pain - especially for loose formats like HTTP headers. Type system come with a cost, you need to carefully consider the burden you are placing on the programmer to see if the benefits out way the cost.
IMO, all the fields need to have a Printable and Readable trait (or whatever Rust's version of those are). If you want to do special things for certain fields to make them easier to work with, I think that's cool too. But if you force people not to treat headers as text, I think you're going to have a problem.
> I have a bug, sure, but an obvious bug that will be fixed very quickly.
People say the same thing about null pointer exceptions, but null pointer exceptions are a huge problem in practice. Every bug is "obvious" in retrospect.
No, this is not the same as a null pointer. Null pointers are typically much more sneaky, this line means the header will not be written and the error is right in your face.
I do understand the desire to prevent these sorts of errors at the language level, but not at the cost of functionality. I don't agree with this one, but I do (for example) appreciate libraries such as the STL which (hopefully) prevent that pointer issue you brought up (and more). The STL doesn't (often) force me to work around silly limitations though.
Does this library provide for creating arbitrary headers in some other fashion? If not, why?
For me, a big benefit is the tooling support. If the API is statically typed, I can easily find the headers I am able to set using my IDE. And for setting the date I don't have to check the http spec for which syntax I have to use for the date.
That's not a bad point, I'm just not sure I am willing to give up functionality for tooling. The end goal here is a program that people can use to get things done, not awesome IDE integration.
I'm not sure what you've done to make you feel like being condescending is something you have earned, but please feel free to share your body of work.
I've worked on very large, complex, mission critical systems my entire career. Medical devices mostly. If you're not catching these sorts of errors early then you aren't modeling and testing your software correctly (or at all). All of the objects in the world aren't going to prevent you from writing bugs and crappy code. OO is no panacea and we've known that for quite some time now. I don't want to use a library which is limiting because it thinks it is doing me a favor.
What an odd response. I haven't done any OO programming in nearly a decade, and I would not consider doing it ever again. I don't know where you got the idea that OO has anything to do with this. I do catch these sorts of errors early on, because they are type errors, and thus the compiler catches them. That is very much the point. The fact that you think you are infallible and can write 100% perfect test coverage, while thinking I am being condescending is pretty hilarious.
Not odd at all; you were being condescending, trying to paint me as someone who isn't as good a programmer as you are. Maybe I'm not, but I've written some very robust systems code in my career, so don't be so quick to write people off.
I don't think I'm infallible (straw man much?), but I do think that dead simple errors such as this would be caught by any amount of actual testing. That said, I wouldn't be against a better design. Why doesn't this library provide a way to add arbitrary headers? Oh, right, that would still involve using a string. Gasp, no, that shouldn't be allowed. We have to protect the poor users of our library. Yeesh.
You can't always protect a programmer from themselves while still allowing the flexibility/power needed to get shit done. I'd rather use the map than some overly architected and frustrating library. I have a problem with abstractions that get in my way.
No, you interpreted it as condescending. Just because I enjoy unbridled optimism does not mean I am condescending.
You are suggesting that you are infallible, as the "dead simple errors" you refer to get out into production systems every single day. More than one serious security hole in rails has been due to very similar problems. You are very much implying that you are a better programmer than the entire rails team. And virtually everyone else, as examples of these kinds of bugs are everywhere.
And finally, crying straw man while presenting a straw man is poor form. If a particular library has a deficiency, that's unfortunate. But it has absolutely nothing to do with type safety. Haskell for example is more type safe, and it has two http client libraries, both of which provide safety while also allowing arbitrary headers (and methods, etc).
Who cares about your super awesome Haskell library? You have meandered our of context. My response was in response to a defense of this particular implementation. If your abstraction sucks then I don't want it as it will cause me more headache than it is worth. That's the point.
EDIT: Eh... looking back at my original comment I don't think I got that across at all. It reads as more of a rant against a typed system in general, which is not what I intended.
Why not use every tool at your disposal that can catch bugs early? Static typing does that. Sure, you can catch bugs later with testing, but why not take advantage of automated tools (i.e. the compiler)? That's one less test you have to write.
The original post was decrying the limitations of a specific library. If you can implement the map in a better way while still allowing the freedom I/we need then fine. If you can't then get out of my way and hand me the map.
I'm with you, in favor of strongly typed headers. Working with strings can be very error-prone; you might not catch typo bugs until your system is in production and handling some rare case for which failure is expensive.
It seems to me that, in the worst case, the downside of your current scheme is an extra field dereference, as in `request.headers.extensions.get("crazyNewField")` instead of `request.headers.get("crazyNewField")`. I think that cost is easily outweighed by the benefits.
You don't have to use types, but if you do then the type system guarantees your checks are exhaustive, which is more effective than manually checking you've covered all the paths.
I really like the spray way. You can add a custom/nonstandard header by using RawHeader(key, value), but most of the time you use e.g. Headers.ContentType(MediaTypes.`application/json`), and it just completely eliminates a class of trivial but annoying bugs.
My main concern is the last sentence of the section you quote. There's tension between headers which are well-known and standardized (either formally or through de-facto wide use), and so are amenable to being properly modelled, and headers which are not well-known or which may not even exist yet. Hence, I think, his comment about CORS.
And I'm not sure there's a good solution. The obvious approach, as you already know, is to separate headers into two groups: one group is "properly" handled, and the other group gets tossed into an "other" bucket of key/value string pairs. But it's going to be awfully tempting over time to have "proper" support for the most common non-RFC2616 headers, especially those which have widely-accepted standards of their own.
But that's a bit messy and much less than ideal, as you've also discovered. And I don't know of another way to approach the problem that still lets you have the stuff you want from the type system, and doesn't cut people off the minute they start using extension headers your library doesn't know about.
And that's without getting into all the completely stupid things it's technically legal to do in an HTTP header, and the even more stupid things that aren't legal but that people do anyway. My usual torture test of an HTTP library these days runs through things like non-ASCII content in header values (legal if properly encoded, and not everything in the wild properly encodes), looking to see how large a value a library will accept, whether it will let me throw newlines into headers, etc. etc.
Strongly typed headers are great, but for the love of God please give us a back door. And I don't mean just a dictionary for every "unknown" header, but we should be able to override every "known" header as well.
I'll give you a real-world example. Mono. HttpWebRequest used to store the Content-Size value as an int32. What about files larger than 4gb? Oops...
That was a big problem for us. Thankfully Mono is open source, we were able to peruse the code and come up with some magic incantations using reflection to work around the fact that the framework libraries would not allow us to set the Content-Size header without going through the int32 property.
Now, normally you would file that as a bug, however, it (A) took years for a version of mono to be released with that fixed this and (B) could easily have been some misunderstanding in the implementation of the HTTP spec that was overlooked. You're implementing a spec right now. Can you guarantee that the your implementation is 100% correct? Can you guarantee that the spec is 100% correct? Can you guarantee that the spec is implemented 100% correct everywhere?
No, you can't.
So, don't limit me. Help me, but do not prevent me from doing what I need to in order to do my job.
The short summary is that Amazon S3 does not behave like a normal web server and expects HTTP path's to be "url encoded". S3 is pretty obviously something you would want to interoperate with. Go's http client (which isn't very strict at all) causes friction here.
By and large, follow Postel’s law on this (http://en.wikipedia.org/wiki/Robustness_principle). As others have also said, though, make it not-too-hard to do things that your type system would otherwise restrict, because if I have to interact with a misbehaving server (including to the point where I have to send what would otherwise be invalid header data), then your strictness would make it too hard to do so.
Although I appreciate this discussion, both the OP and you are off-topic. This is a library design issue, not a language level issue.
If people like OP are dissing a language because they don't like a particular library's API, they have very strange expectations from the language. And if you are worried about this section of users, then I would say in order to make good use of your time, it is best to ignore them.
For all practical purposes, you're never comparing just the core language, but the language+libraries for common tasks (no matter if it ships 'batteries included' or not)+the whole ecosystem and community of library developers.
If it's hard to do X in your language, but easy in other languages - then that's a weakness for your language, despite that 90% of X's will be outside of the language core.
And even 'optional extras' in your language can be weaknesses instead of features - if they are often used by library makers for less readable/maintainable code than the other options.
This tactic seems to betray a certain amount of naivety with regard to how closely most real-world HTTP implementations follow the specifications. (Hint: they don't follow the specifications.)
Remember Postel's law: "Be conservative in what you do, be liberal in what you accept from others."
Unfortunately, you will have to return URLs to your users that are invalid. You will have to parse slightly malformed dates. Your clients will expect to be able to pass through malformed values from bad endpoints and not introduce a point of failure in your library. (Do you know about the "Cneonction: close" trick, for instance? All real-world proxies do all sorts of batshit-crazy HTTP header munging.)
If your library can't accept and pass through arbitrary strings for arbitrary headers, and return them to users, and then accept them back again, then it is unlikely to be successful in any sufficiently complex and robust HTTP service.
1) src/main/scala/com/thingy/actualthingy JUST to get to the root of your code.
2) Recompiling/restarting is slow because liftweb and other frameworks are overly complex.
3) I'm 90% sure it would be possible to create a PRY-like debugging tool that runs your code in interpreted mode and drops you into the REPL at a certain point in your code. And yet, it'll never get built because Scala hackers are stuck in the halcyon java days of 1998.
4) Variable names first, types second = okay, now you're just being different for the sake of being different.
That said, it seems like if you use scala as a more concise java with some handy functional syntax thrown in, you can make something that isn't terrible for future maintainers.
Number 4 because...Pascal. This was actually a huge innovation over Algo's syntax back in...the late 1960s. I think Martin Odersky studied under Niklaus Wirth, so the lineage makes sense; I also think its better than the old early 60s Algo way of defining variables.
I'd say a lot of the critiques are fair but quite exaggerated. I work on a large Scala codebase and yes, the compile times for a fresh start across the codebase are very long, but TDD-type loops are very short, because you're generally waiting for two files (your test target and your test code). Still, the compiler performance in Scala is perhaps my chief criticism, though hardly a show-stopper. As codebases in any language grow, you tend to have increasing challenges in the time it takes to fire up your environment.
The critique about excessive and opaque operator use in libraries is fair, though I think it actually exposes an interesting philosophical issue. Scala is unabashedly written to be a flexible language. This is in opposition to Java, which was written to be a very strict language in terms of expressiveness on the part of the developer (it's perhaps the most strict of the languages I've worked with, hence it being my example). I personally think a lot of criticisms leveled against Java's verbosity and inflexibility are unfair, by virtue of the following: Many incredibly successful and complex open source projects are written in Java. While you could say this stems from Java's enormous popularity, one interesting property of huge Java open-source projects is that I can usually crack open the code and quickly get a sense of how I could contribute to the system without breaking it. While other languages often do a better job of giving me a sense of how the system works, I generally have much trouble with extensibility unless it's Java. This I believe is because Java was designed from the ground up with the goal of limiting individual developer expressivity in favor of imagining large development teams with limited cross communication.
So--I am far less anti-Java than most. But I am a big fan of Scala. Unlike Java, Scala was written to maximize developer expressivity. While writing Java can feel like putting together a legal contract, writing Scala can feel like creating a poem. I'm not making a value judgement in either direction there--I feel that poetry is a good metaphor, because things in Scala tend to fall apart in the reading department. One of the easiest things to do in poetry is to lose the reader--a great poet can put an incredibly complicated multilayered concept onto a small amount of paper--and require a graduate-level understanding from the reader to understand it. Similarly, one can very easily make Scala into an exercise in unpacking
So isn't that a bad thing? Why am I a Scala fan? Going back to my initial praise of Java--Java is so simple and predictable that it's really easy to see how the plumbing works. But because the plumbing must be laid out so meticulously and in every situation, it is often hard to see how things work at a high level. You can't see an architectural sketch in Java, you can only see endless classes in endlessly nested subdirectories. This is a very low level of abstraction, and helps the layperson (such as someone approaching a new open source project) build up an understanding from the base elements. But what's lacking is the high level abstraction.
Outside of programming languages, almost every knowledge discipline has a high level abstraction language--sometimes multiple languages. Usually the abstraction language is opaque to newcomers, and frustratingly so. Examples are the mathematical notations of various disciplines, the jargon-laden meta-language of historical theory/literary criticism, and what is popularly known as 'legalese'. But even less high falutin' fields have similar languages--listening to sports fans talking about what's happening can be quite mystifying to me, given all of the shorthand they're using. Similarly people talking about pop culture in areas I'm not familiar with.
These ubiquitous high level languages usually share two important facets: first, in a few lines of text/speech, you can pack in many books' ...
Great comment. I agree with nearly everything you said, but where I end up is the polar opposite. I can't stand Scala for all the reasons you mentioned.
The poetry thing is really dead on -- when Larry Wall spoke of Perl -- he said he explicitly wanted you to be able to write poetry with it. This led to the write once, read never reputation of Perl... that Scala is quickly stealing.
Scala is on my "will not work with" list of languages/technologies -- which is generally limited to old languages/tools that I have experience with (like Progress 4GL, Mumps, etc), but don't want to touch. It is a maintainability blackhole and generally horrible (to me) to work with, despite being fairly comfortable with the core (1400 or so hours billed).
I've developed and maintained multiple large systems in a team using various languages. I would much rather maintain a system written in Scala than either Java or various scripting languages we've used and the view is shared by the whole team. It's far less verbose than Java and very maintainable compared to other very large systems written in scripting languages.
We simply disagree on this. I would rather use almost anything else except the random DSL wasteland that is Scala. Even Ruby or Python (with the horrible GILs) is preferable.
The groups I worked with made different determinations than your team, but if you guys love it, enjoy. Seriously, if you find a technology your whole team loves, you are KILLING it.
Both companies I worked with have since dropped Scala (after literally hundreds of thousands of dollars spent on the attempts) entirely internally due to maintenance and talent acquisition issues.
That was not my experience with Scala. Every library we used had its own DSL and that made the code really hard to read. Maybe things are different now, but I'll bet that was a lot of people's first experience with Scala. It's what turned me off to the language, even though I did like using the standard Scala library quite a bit.
Edit: It was two years ago so other than Lift and some SQL DSL I don't recall which libraries we were using. I do recall wishing I hadn't taken that job.
Are there a number of slightly different and incomplete variants of LINQ, like there are SQL DSLs in Scala? Because if not, then LINQ is "the right way" of doing this kind of thing. And if I remember correctly, LINQ is also useful outside of the DB domain, for things like filtering arrays and so forth.
I once read an article about how Java programmers can hold a conversation on the topic of upsides and downsides of multiple dependency injection containers while C# programmers only have one available and have nothing to say on this topic. That article concluded that having one "good enough" solution can often be better than having multiple slightly different and incomplete ones, even if each has its own strenghts, and I'd say the same is true when it comes to the C# LINQ vs. Scala SQL DSLs.
The Scala equivalent is called Slick, and it's the only SQL DSL that approaching anything near widespread use. I fail to see how incomplete projects on GitHub which happen to be written in Scala are relevent to this discussion.
Interesting, I'm from Sydney and we are seeing a large increase in Scala developers becoming available. Several large companies have been hiring them by the truck load and the local Scala meetup regularly gets 50-80+ people.
I too suffered a bit from DSL hell, especially some of the more extreme examples like the library "dispatch" where you need a "element lookup table" to figure out which squiggly line to use. But once you have a stable set of dependencies the initial DSL influx subsides and you start to work with a fairly manageable subset of them on a day to day basis.
There are other JVM languages that are far less verbose than Java, without the complexity of Scala, with better compile times, and better compatibility with plain-old Java. For instance, Kotlin.
Kotlin is not much simpler than Scala. It implements some of the Scala features in actually more complex and IMHO less elegant way,(pattern matching, null safety), copies some 1:1 (declaration site variance) and leaves out some of the most powerful ones (implicits, dependent types). I personally don't buy it. I like languages which offer few, but very general and powerful features / abstractions, than languages that concentrate on directly supporting special cases.
It 'looks just like Scala'? It is not even a functional programming language. Let alone that it supports implicits, general operator overloading (operator overloading is very limited in Kotlin), existential types, etc.
In fact Kotlin looks mostly like Java with some additions to make everyone's lives easier (closures, extension methods, data classes).
Kotlin is certainly in the "Java philosophy" camp (alongside Go, Dart), and yet achieves most if not all of Scala's original goals (though, unlike Scala, it is not a superset of Haskell, Lisp, Javascript and Java, so if you want to write Lisp, Haskell and Javascript, and insist on having all three compiled by the same compiler, you should stick with Scala :)). I have high hopes for Kotlin, and can certainly see my future projects being written in a combination of Kotlin and Clojure.
A superset of ... what the? Why do you keep trotting out this garbage thread after thread?
Every language takes influences from others, if that's what you meant. Scala is influenced by Java, C# and Haskell, in that order. Kotlin is influenced by Scala and Java, etc.
The "superset" and "Lisp, Haskell and Javascript in the same compiler" comments are unhinged from the reality of any language I recognise.
I think I read that phrase from you before on nyc. I think it's a misleading catchprase.
For me and I think most other Scala devs Scala is a statically typed FP-OO language. So Haskell doesn't do it justice because Haskells insistence on purity makes it impractical for me in getting stuff done.
And Java doesn't do it justice because Java is held back by its history.
"Superset of" makes it sounds like a weakness and overwrought. In my experience it offers a sweat spot of the best features of static FP and OO.
So what about your mention of Lisp and Javascript? Unless you're deep in some framework you don't need to know about the support for macros and structural typing. I've ignored those two so far because I haven't needed them (yet?). And I haven't felt they were in my way.
So where you say "a superset of Haskell, Lisp, Javascript and Java" I say "the sweet spot of the best features of static FP and OO for the real world. Leveraging the JVM ecosystem".
>So Haskell doesn't do it justice because Haskells insistence on purity makes it impractical for me in getting stuff done
I know this will sound snarky, but I have to ask: have you tried haskell before? I only ever hear that line of reasoning from people who have never used it (and I was once one of them, using that very same reasoning to choose a multi-paradigm language). We bailed on scala for haskell precisely because it is pure and has a better type system.
"Useful for getting stuff done" is a point that Erik Meijer literally has made. F.i. you find him explaining his point of view on side effects and imperative programming here. And how he progressed from "fundamentalist" functional programming to "the real world is imperative & embrace side effects". http://youtu.be/a-RAltgH8tw?t=11m1s
You can't say that Erik Meijer doesn't know Haskell. :-)
The fact that Erik Meijer says that imperative programming is the way to go for the "real world" is deserving of attention, but it doesn't empirically mean "all 'real world' software is better created with the imperative paradigm".
From the sound of it this is his first job in the "real world"? If that's the case, perhaps he just hasn't seen patterns of applying his current functional knowledge in a way thats better than the best practices from the imperative realm.
How do we know after a few years he won't switch (provided he was a fundamentalist functional programmer) back to saying "now that I have a better understanding of 'The real world' I can see patterns applied with the functional paradigm are better than the best practices I've been using from the imperative paradigm."?
I believe this is the reason to keep an ear open for authority figures, but not to take everything they say empirically, especially when it's in contradiction with a position they've held much longer.
Apologies for the rambling, I was just typing out what came to mind.
> The fact that Erik Meijer says that imperative programming is the way to go for the "real world" is deserving of attention, but it doesn't empirically mean "all 'real world' software is better created with the imperative paradigm".
Nor is that even, I think, what I think Meijer favors. Meijir's position, from what I've seen from him in various contexts, seems to be that there are cases in real world software where the most clear expression of intent uses imperative constructs, and its better to use them -- but understand and contain their dangers -- in those cases rather than trying to avoid out of devotion to purity.
> From the sound of it this is his first job in the "real world"?
Well, if you don't count the 13 or so years at Microsoft as being "real world".I don't think he ever was a fundamentalist anything.
> I believe this is the reason to keep an ear open for authority figures, but not to take everything they say empirically
"Empirically"? Are you meaning something like "uncritically"? Because "empirically" doesn't have any meaning that makes sense in this sentence.
>You can't say that Erik Meijer doesn't know Haskell
That's true. But I can say that he is quite happy to tailor his message to his audience, If you listen to what he is saying, he is making the argument for haskell. He is just wording it for the PHP crowd. Haskell does allow side effects, which is entirely the point. But the "unwashed masses" as it were are under the misconception that it does not. So he has to take the "side effects are awesome" sales pitch, and kinda tosses haskell under the bus in the process. Unfortunate, and ironic given that haskell programmers genuinely feel that side effects are awesome, but what can you do?
>though, unlike Scala, it is not a superset of Haskell, Lisp, Javascript and Java
If you think scala is a superset of those, then you either really don't know scala at all, or you have an incredibly low opinion of all the languages you listed.
I was expecting Groovy, which is indeed less verbose than Java, less complex than Scala, and has excellent compatibility with Java. I don't know about compile times.
The main downside of Groovy is: it's not as fast. And of course the programming paradigm is less revolutionary and more pragmatic, though that could also be a big upside.
Indeed, DEEP in the east coast systems. But, it was great for me, it was literally name my own price consulting (lawyer rates) with multi-month contracts. I would guess it still is a name your own price market if you have the stomach for it. Travel and horrible tech.
I was in an odd position of having picked up 4GL and MUMPS via odd random ways when I was 19/20 -- so when everyone who used to maintain those systems vanished, I was around to step in and bill like crazy for helping them port OFF those systems onto more modern tech. Every port a MUMPS app to Erlang... I have!
Not really, I was lucky enough to have mentor who literally just let me screw around with them. I had hundreds of real hours programming random stuff on both, as well as fixing real world problems with the safety of someone double checking. So I was very comfortable and I mostly used reference manuals for quick look-ups.
These systems are VERY different that what you are most likely used too, so having face time with them is really important.
I had a brief but fascinating encounter with MUMPS back in the late 80's on some ancient Data General Nova/Eclipse kit. I kinda wish I'd persevered, if only for minting cash for the bank account.
You never work with scripting languages? (i.e., why is there no Python, Ruby or Javascript in your lists? or maybe I do'nt know Haxe, does that replace them?)
I'm not them, but I have no scripting language in my list either. There is simply no need for one. For small sysadmin scripting, sh is nicer than a scripting language. For anything bigger than ~50 lines, I use haskell.
Most of the stuff I work on is highly concurrent. GILs are the devil. Almost all the joy and ease you from GIL languages is lost as you try to go concurrent and have to use (in python for example) multiprocess and gevent ... then you start getting caught on the rough edges and poor ideas in those tools... and everything falls apart.
GIL isn't a language feature, it's an implementation feature — in Ruby, at least, this is a significant difference because there a major implementations (Jruby, most notably) without it even though it is a feature of the MRI implementation.
GIL is all evil. If your are dealing with CPU bound concurrency yes, GIL is there to take the fun away. But if your problem is most about IO concurrency (downloading from multiple sockets for ex) GIL is no problem. I get very nice speedup from Python's threads with a silly web crawler I wrote.
Another option is to use Cython. You can declare a function "nogil", but then you can't call any native Python functions within it. It's good enough for some purposes, but not all.
I'm curious as to whether you have shipped or have thought about shipping code in Haskell and why or why not. Rust I'm assuming is too new for that to be an option.
Hey, this is one of the best comments I've ever read on HN. You should consider adapting this and some of your other comments into independent blog posts.
Is 'legalese' really a high-level language? It seems to contain a ton of boilerplate. Signal-to-noise ratio is quite low in reality. It could much more succinctly be encoded in a formal language.
Also, I think you exaggerate the 'Scala is bad because DSLs' point. There are indeed a lot of libraries which overuse symbols but you are not obligated to use them. I have found the Scala I've written and read personally to be both concise and readable.
And, Scala isn't the first or the last to 'reach for the expressivity goal'. See: Haskell, Scheme, F#, & ML.
I think he meant the language that lawyers might use amongst themselves. Legalese is actually fairly low level. It's like a fully type annotated version of English that redefines all library functions each time.
Languages like Ruby and Python allow for expressive, high-level customization, metaprogramming, and DSL creation. However, especially in the latter, the potential chaos is curbed by a strong culture and encouragement of self restraint, readability, and simplicity. From the sound of it, this is not so true for Scala.
Once you start dwelling in the intricacies of a very complex type system, it becomes quite difficult to keep things easy to understand.
There's this joke about how a Haskell programmer's style on a hello world programme evolves with experience, starting from a very readable, sort of down to earth implementation, and turning out in its last iteration into a complex "mess" of abstract concepts, for sensibly the same result.
It's always possible to keep things simple, even in Scala, and the opposite is also true with a language known as simple, Java, because the type system happens to be quite powerful actually. People are tempted to make things complicated also because there is this prevalent programming style in the community.
If you take it too seriously, it's indeed not very good. I personally take it as a compliment for Haskellers: it means that people from the Haskell (and fp in general)community do think at a higher level than the average programmer, so much that it becomes for them difficult not to.
The FP model gives good tools to enable that, and encourage people to think that way.
I may also be biased because I feel more confortable thinking that way. Certainly programmers excelling at imperative programming might disagree, but I don't think that the latest trends of "functionalizing" Java, C++ or PHP are coincidental. Javascript opened the way by bringing back that paradigm to a larger audience, and these languages, which already have FP concepts available, but not in a very usable way, are now incorporating them to the core. That's a good thing.
Regarding the original topic, Scala is very much an experiental language in my opinion (because of the concepts it involves; the implementation is pretty good), so maybe there's a little bit of thruth in the article in that regard. Perhaps that's the "flaw" of academic languages. Also the comparison with Java is quite pertinent, Java being a language designed from the ground up for engineering: the grammar is fairly simple, which provided a somewhat good compromise between high readability (because of its similarities with C) and easiness at machine processing (not as easy as lisps dialect though).
I'm really curious of what "sound" you're talking about.
I've been working with Scala full-time for the past 2 years. Prior to that I worked with Perl, Python and Ruby and I still work with these languages for quick scripting or if the codebase demands it.
Scala code-bases tend to be based to a higher degree on good engineering practices. Scala itself is a much more static language than a language like Java, hence it gives you plenty of compile-time safety, with its static type system being one that helps you, instead of staying in your way. Even a tricky feature (now market as experimental SIP-18 and so they have to be explicitly enabled), like implicit conversions, is far more safer than the monkey patching that goes on in Ruby/Python, as it's lexically scoped, doesn't modify anything and the compiler throws errors if there are conflicts.
Again, in my experience, the documentation in Scala land is very good. The standard library has a really good API documentation, also checkout the documentation project at http://docs.scala-lang.org/ plus there are several very good books available; then there are the libraries in Scala's ecosystem, like Play2, or Akka, or Slick for example that do have good documentation. The online documentation for Play2 does not match the online documentation for Ruby on Rails or Django, but it's newer and it's improving and I remember a time when Rails was several years old and lacked online documentation. I did find undocumented features in Play2's online documentation, but nothing that couldn't be solved with a question on its mailing list. These are open-source libraries, with strong communities that communicate a lot on mailing lists, you know.
The great thing about Scala is that you can also use any Java library you want and wrapping Java libraries in Scala-ish interfaces is actually easy and a great learning experience. I wished you'd be more explicit about this point, because for me I don't feel like there is a lack of documentation.
> 2. Breaking backwards compatibility
This is a point that comes up a lot, but I don't think it's that important for people actually using Scala. Scala is a compiled language, the libraries get distributed / deployed as compiled bytecode packaged up as Jars. This means that breaking compatibility is really easy, as all you have to do is to change an interface, like adding, removing or changing the signature of a method and boom, all code that depends on that interface needs to be recompiled, even for code that's not using the method in question. Dynamic languages that get interpreted or compiled on-the-fly, like Python or Ruby, are distributed as source-code. So by their nature don't have this disability.
The alternative to breaking backwards compatibility in Scala is to freeze the standard library. Personally that's not a compromise I want, because for this very reason Java's standard library is full of idiosyncrasies, broken interfaces, broken behaviour and various other artefacts going back to Java 1.0, that were never fixed in order to preserve backwards compatibility.
Scala has improved a lot though, compared to the 2.8 days. Nowadays you've got a guarantee that minor versions aren't breaking backwards compatibility. Code compiled with Scala 2.10.0 is guaranteed to be compatible with Scala 2.10.3 at least. The next version free to break compatibility with 2.10 is Scala 2.11. The tooling in Scala's ecosystem, like SBT, is also friendly to supporting multiple versions. To compile, test and deploy versions for multiple Scala versions is often just a configuration change, assuming you don't use APIs that aren't available in older Scala versions, in which case the back-ports are hard to accomplish in any language.
> 3. Opaque error messages
That's in the eye of the beholder. Sometimes the error messages are not so good, especially when triggered by the new macro support in Scala 2.10, but you know, those macros are experimental and improving by leaps and bounds. 90% of the time I have no problem understanding the given error messages and many times you get really helpful errors or warnings about code that you think it's correct, but isn't, like when pattern-matching on an ADT and missing a case. And I prefer opaque compile-time error messages to subtle or non-deterministic runtime error messages. In Python I used to suffer from null pointer exceptions all the time. In Scala null pointer exceptions are very rare.
> 4. Encourages ad-hoc syntax that makes sense to one person (or team) but does not to the next -- maintenance nightmare.
This is a thing that gets repeated by people that haven't used Scala, either personally or in ...
Thank you for taking the time to reply in such detail. I can see that you are a committed Scala dev and what I write below will probably not make a difference to you. However, for anybody else:
I think what I want to say is, Scala is not a mature platform. I believe the language was originally conceived to address the deficiencies of the JAVA language while retaining the versatility of the JVM as a platform.
If you look at the history of JAVA, it was a 'halfway successful attempt to drag C++ programmers towards Lisp'. Clearly this did not work well as it was not a well reasoned effort (syntax, semantics and so on) and went further downhill from the introduction of Generics in 1.5. Scala incorporates all the features of JAVA, adds halfway-to-Haskell-FP, OO-FP, XML-DSLs, some other very funky concepts stretching Generics and then...Macros...and probably stuff from JAVA 8. I humbly submit that this mixture is too much for a reasonable brain to handle. Also in the mix goes the backwards compatibility breakages. How many concepts can you cram into a semantic that in itself is not sound? Is there a standard for the language? Can I implement core Scala in C?
Scala improved a lot from previous proves that point that it is still "improving" i.e. not a mature platform as yet.
Functional programming concepts are not a problem for myself (and I believe any other reasonable programmer) it is the sensory overload of fitting it all into a model: all the language rules that you need to juggle to read a 15 line block of code that can jump between Scala, JAVA, DSL, Generics, operator overloading, etc.
Code written in more powerful languages feels like being harder to read, simply because each line of code does more...hmmm, is this a good thing? Because I have some Perl that you might wanna look at. Succinctness is power, not sensory and mental overload.
If I want the power of OO/FP/DSLs/MACROS all in one bundle, I would prefer a reasonable modern Lisp: coherence and maturity being the deciding factor in that choice.
> Scala incorporates all the features of JAVA, adds halfway-to-Haskell-FP, OO-FP, XML-DSLs, some other very funky concepts stretching Generics and then...Macros...and probably stuff from JAVA 8. I humbly submit that this mixture is too much for a reasonable brain to handle. Also in the mix goes the backwards compatibility breakages.
Most of the core assumptions here, on which you base your opinion, are not correct.
For instance, Scala removes tons of crazy stuff which plagues Java.
I'm also not sure how one can add Scala's first-class OOP-FP integration as a minus. Have a look at all the other languages which only managed to do that in a lot more terrible way (F#, Java).
Generics as well. Why is the fact that scalac doesn't try and throw obstacles at you when programming with Generics bad? (Have a look at Java or C#, where tons of reasonable code is rejected by the compiler, because those compiler devs were too lazy to implement things properly.)
Same with macros. Have a look at the state of art in Java. It's a terrible mess with various black magic tools and invocations combined with poor IDE and tooling support.
If you can handle Java, I don't see an issue with Scala. Most of the stuff in Java is done in a better, more consistent and better designed way.
> How many concepts can you cram into a semantic that in itself is not sound?
I'm not seeing that at all. Care to explain?
> Scala improved a lot from previous proves that point that it is still "improving" i.e. not a mature platform as yet.
So Java is not mature, too? They are painfully adding mediocre lambda support right now. I'd call a language which was designed with lambdas in mind from the beginning and shipped with them since in 2005 more mature. The language in question is Scala.
> all the language rules that you need to juggle to read a 15 line block of code that can jump between Scala, JAVA, DSL, Generics, operator overloading, etc.
I have never seen that in practice. I often wished code written in other languages would adhere to the standards of code written in Scala. That would make things a lot more readable, maintainable and understandable.
> Is there a standard for the language?
Yes, there is.
> Can I implement core Scala in C?
Yes, why not?
> If I want the power of OO/FP/DSLs/MACROS all in one bundle, I would prefer a reasonable modern Lisp: coherence and maturity being the deciding factor in that choice.
> Maybe Clojure?
Too bad, they are currently trying to add a half-baked static type-system to core. Again, I think a language which shipped with such basic things in mind since 2003 is a lot more mature.
> Most of the core assumptions here, on which you base your opinion, are not correct.
Which ones are not correct? What is the core philosophy of Scala?
>For instance, Scala removes tons of crazy stuff which plagues Java.
If they are removed, how can you claim efficient interop between the two? They are not removed, they are hidden/masked.
> I'm also not sure how one can add Scala's first-class OOP-FP integration as a minus. Have a look at all the other languages which only managed to do that in a lot more terrible way (F#, Java).
Anything the brings C++ inside JAVA is a minus.
>Generics as well. Why is the fact that scalac doesn't try and throw obstacles at you when programming with Generics bad? (Have a look at Java or C#, where tons of reasonable code is rejected by the compiler, because those compiler devs were too lazy to implement things properly.)
Java does not throw "obstacles" its just that the thing was not designed to handle Generics efficiently in the first place. The compiler rejects it because it is not in the spec.
>Same with macros. Have a look at the state of art in Java. It's a terrible mess with various black magic tools and invocations combined with poor IDE and tooling support.
See above, the core language spec does not have any macro facility. So what state of the art are you talking about? If you try to shoehorn it in, of course the result is black magic and poor support. And I am not too sure that macros are a 100% necessity -- Paul Graham advises sparing use of macros in your code. And he is talking about LISP code -- something that has the facility built right in.
>If you can handle Java, I don't see an issue with Scala. Most of the stuff in Java is done in a better, more consistent and better designed way.
For me, consistency means the ability to hold a reasonable model in my head. Java + Generics + OO-FP + Macros + god knows what else is not a reasonable model. Do not mistake complexity for power.
>I'm not seeing that at all. Care to explain?
Sure. Take Java syntax: If something is not designed to have a feature why do you want to try to shoehorn complex features in it? Clojure went the other way and completely changed the syntax, not mangling existing Java syntax.
Apply that to anything: the syntax, the compiler, the model, whatever.
>So Java is not mature, too? They are painfully adding mediocre lambda support right now. I'd call a language which was designed with lambdas in mind from the beginning and shipped with them since in 2005 more mature. The language in question is Scala.
I never said Java is not mature. In fact, it bends over backwards to accommodate code written in previous versions. If you want a language with lamdas built in (as an example of one feature) why not choose something that has been in existence for over 30 years, has tons of problems solved in it, was a result of original research first and commercialization later, has had more man hours thrown at its problems and implementation than Scala, etc? Why re-invent the wheel? Why not find a way of greasing the wheel better and applying a nice shine on it to make it attractive to modern programmers?
>I have never seen that in practice. I often wished code written in other languages would adhere to the standards of code written in Scala. That would make things a lot more readable, maintainable and understandable.
So all the people complaining about Scala library code readability are whiners? All code written in Scala is a lot more readable, maintainable and understandable?
Can you please point me to where the Scala specification is? It would have to be stand alone to implement in C, not built on something else. Genuine question. If there is a spec to the language (implying design and thought), why does the language keep on changing and breaking previous versions?
>Too bad, they are currently trying to add a half-baked static type-system to core. Again, I think a language which shipped w...
Scala is pulling out of that phase. Scalaz 7 removes a lot of the less-readable operators (e.g. you now have to write "Kleisli" rather than "☆"). The Requests HTTP library, long mocked for its periodic table of operators, has fallen out of favour (I'm not sure it's even maintained any more).
I can't speak for SBT because I don't use it, but Spray is probably the nicest library for defining HTTP APIs I've ever used, in any language. As for type inference, yes it's imperfect, and maybe disappointing for someone used to Haskell, but coming from Python I found the set of type annotations I needed to add to make my Scala compile was a subset of the ones I wanted to document anyway.
Scala doesn't make a distinction between operators and methods, and Java has always supported unicode in method names, so they have to be possible for compatibility if nothing else. I think if used carefully, with discipline, they can make code more readable and ultimately more maintainable - e.g. for doing set algebra it's nice to be able to have ∪ and ∩ methods. But yes, if you want to shoot yourself in the foot with them it's very easy.
I showed an example of using Unicode operators in a presentation I gave to the Atlanta group back in 2010. It doesn't say it in the slide, but when I gave the talk, I explained that while it sounds like a neat idea, you should probably avoid doing this. You can see the slide here, where I used a Delta as an operator slideshare.net/slideshow/embed_code/2923973?startSlide=9
> But because the plumbing must be laid out so meticulously and in every situation, it is often hard to see how things work at a high level. You can't see an architectural sketch in Java, you can only see endless classes in endlessly nested subdirectories. This is a very low level of abstraction, and helps the layperson (such as someone approaching a new open source project) build up an understanding from the base elements. But what's lacking is the high level abstraction.
I agree that it becomes tricky to get an overview of the whole project in C/Java/etc, but I very much disagree that it actually becomes easy to get that high level overview in Scala/Ruby/etc. As soon as the project becomes 'interestingly large' and full of the corner cases that comes with interacting with reality, all languages fall down here. Regardless of the level of the language, you are still communicating with a machine. I'd guess that for a mathematician who has spent most of their lives looking at equations and little time talking to people, a mathematical functional language may seem easier to read than a novel - but for most people this isn't the case.
The best way I've seen to handle this regardless of language is to have the high level overview outside of the code in a human form document describing the reason for components and not just what they are.
This is also why I prefer simpler languages (like Java or C, as you say) - they are very good at specifying exactly what is going on with little room for creativity to confuse things. We use legal contracts for a reason - imagine if our laws were written in poetry? Writing a computer program is much closer to a law than a poem as you need to limit ambiguity as much as possible and specify as many corner cases as possible to prevent undefined behavior. Plus being at a lower level means optimization strategies are easier to see.
There's a reason C/Java/C#/etc are still the most popular languages, imo. The only real outlier being Javascript which gets its popularity from being the only option for the browser.
> The only real outlier being Javascript which gets its popularity from being the only option for the browser.
This is probably the reason for Javascript's popularity, but if you ignore some bad language design, Javascript is a very simple language with a very small number of concepts that you need to understand to start getting work done in it. Even Python (which I think is the simplest of the widely used dynamic languages) has a larger number of concepts that you need to understand than Javascript.
So I don't think Javascript it's an outlier according to your theory, it's very much a simple language, the only remarking features compared to C/Java/C#/etc are the fact that it's dynamic and that some corners of it are badly designed, plus exceptionally badly designed API if you're doing anything in the browser that's not abstracted by a platform library.
That doesn't qualify as simple in my book though. Javascript has fewer concepts that programmers need to keep in their heads, but they are horribly inconsistent and quirky. Python, on the other hand, is consistently designed so that there are very few cases where you get hit with unexpected behavior.
Well, to be fair, most unexpected behaviour in js comes from people not knowing the language, or people expecting js to behave like other languages. I do agree though, that js does have its share of design quirks.
Well yes. But in that case Haskell is full of unexpected behaviour for someone completely new to functional programming, as C++ is to someone used to Lisp.
>> This is probably the reason for Javascript's popularity, but if you ignore some bad language design, Javascript is a very simple language with a very small number of concepts that you need to understand to start getting work done in it
I hear this a lot. JavaScript is great unless you [insert example why JavaScript isn't great]. You could easily turn that statement around: JavaScript sucks, unless you don't [insert example why JavaScript sucks]. It's an empty statement that could apply to almost any development language no matter how objectively 'good' or 'bad' it is.
I don't know Scala, but judging from the (interesting) article it appears that Scala can be perceived as a bad language because it allows you to write obfuscated, hard to read code that hides many details of what's going on in the program. This can be both a good and a bad quality, depending on the kind of program, and the kind of developer. Personally I like languages that aren't too opinionated or restrictive, so I might like Scala. Compare this to JavaScript, which is a bad language for the simple fact that it's downright dangerous to program in looking at all the idiotic, arbitrary corner cases you have to avoid.
You could have a philosophical discussion about the merits of the design choices in Scala, I don't think you could say the same about JavaScript though, it really is popular only by accident.
>>It's an empty statement that could apply to almost any development language no matter how objectively 'good' or 'bad' it is.
No, it isn't really contentless.
All really complex systems will have ... well, less than perfect parts. That goes for programming languages in (at least) a subset of their use cases.
You can either live in denial of "cruft" when choosing programming language or accept that you need to enforce a standard of best practices in your group.
Then you evaluate languages with how they works if the best practices are followed. JavaScript's "good parts" -- and bad -- are well documented and discussed, most everyone knows about this subject.
The overhead of designing/teaching and following those "best practices" needs to be factored into the equation too, of course. It might e.g. be too much of a pain for the std library of PHP (example chosen because I don't know PHP enough to have an opinion.)
When I finally picked up a book on Scala, I rejoiced when I read the chapter on parallelization with Actors and especially how they passed case classes around and automatically extracted data from them in their built-in switch statements. That stuff was fantastic!, concise, expressive and beautiful! Hallelujah!
The next chapter delved deeper into the typing system, and I recoiled in horror.
I still want to do Scala some day just to use their actor messaging, but there really is a very strict limit to how far a sane person can look into Scala. At some point, the Abyss looks into you, and if you're not careful, you'll also start building crazy DSLs with incomprehensible operators based on Type Declarations Man Was Not Meant To Know, just to maintain rigid type safety in some situation nobody really cares about.
Once again, I will sing praises of C#. Some of the libraries are terrible, and it's Microsoft... but seriously, it fits the perfect happy medium between Java's clumsiness and Scala's everything-plus-the-kitchen-sink syntax.
Yet C# way too short from Java ecosystems (JVM, JMX, highly-concurrent system, agent, access to internal VM, better build+dependency+scm, tooling, overall).
So what would you pull out of Scala's syntax? The language definition itself isn't all that big. It covers a fair amount of ground, of course. I don't see anything there I'd be happy to see go away. If it goes away, I just end up having to implement it myself...
Very well worded. But... yes there always has to be a but. You can make the same argument about any software development, even within the same language.
I worked on a large C++ project. Most code was written in a very concrete way. This lead to reams of boilerplate code which bothered me a lot. I thought it was difficult to grasp because there was so much code and there was no explanation of concepts. To me concepts are important. Instead I wrote high level but quite abstract code, but with good documentation of concepts I used.
Sadly I noticed people had big problems understanding my code. I tried to analyze why. My best explanation would be that they were not interested in software architecture like me so they could not recognize concepts and patterns as easily. Furthermore they were not used to reading documentation about concepts. They just wanted to look at the code right away. That is what they were used to. But that was hard, because my code was quite abstract.
I have no idea what the solution to this contradiction is.
Your main premise (expressive power vs readability) is wrong.
Take clojure. Both very expressive and very readable.
The problem of Scala is not that it is oh so awesome and expressive. It is in a failed attempt to marry two very complex worlds: OO and FP. Of course the complexity of language explodes on unsuspecting developers.
Scala is a cautionary tale for every language creator out there. Chose carefully what you pack into your language.
There's absolutely no need to create a monstrosity like scala in order to reduce boilerplate. Even such complex language as haskell is much simpler and more readable than scala.
That's the reason both OO and FP camps reject scala. It is OVERENGINEERED.
An often overlooked fact is that a lot complexity in the Java world is in the frameworks. You can express many things directly in Scala, for which you would use a Java framework a bunch of annotations (without compile time semantics).
I agree with the parent that the author should investigate Go, but add that the author will get all of those benefits plus a dependency management headache.
Agreed; I like a lot of what I see in Go (though admittedly I liked it about as much when I saw it before Go was released) but the hype is getting to the point where it's impossible to take the general Go advocacy on HN seriously.
I'm starting to wonder when, when I mention C++, I'm going to be told that Go will fix all my problems. (Rust might; Go won't.)
If you hadn't mentioned Go, you could have described Java with these bullet points (with the exception of the last). Why throw away all the proven libraries, extremely good garbage collector, IDEs, intrumentation? Java is a perfectly fine language and if you think it is too verbose, there are good other options such as Kotlin, Groovy (which offers static typing nowadays), Ceylon etc.
I tried Go for the same reasons. It looked to me like a statically typed Java, but in practice it was not the best experience. The Code is not more expressive than Java, but you lose all the good libs and tools from Java. Most annoying was the in ability to create concise mocks, because you cannot implement interfaces at runtime with Go.
You forgot to mention go-routines. I don't think I could survive another day without hearing about how amazing they are and will completely reinvent concurrency as we know it.
People think I am pining for go too, for similar reasons. Yet I tried very hard to like go, and was unable to put up with such a primitive language just for the nice tooling. Not everything is a "you just need to use go" in disguise.
Several years ago I picked up Odersky's book. I got a few hundred pages in, considered the types of problems I had encountered in my career so far, and decided life is too short to be spending my time learning some hyper-complex programming language that seemed, like C++, to seem unable to say "no" to introducing complexity where it would provide minimal upside in Getting Shit Done.
Instead, I learned Clojure. I use Ruby, the epitome of comfortable languages, for most things, and when the hard problems come up, I use clojure. My next major scientific computing problem, rare as they are, will be in Julia instead of Matlab for prototyping and java for production. Scala seems to be the hard language for easy problems. No thanks.
Unlike you I finished reading the Odersky book and am very easily "Getting Shit Done" much faster than I ever did in Ruby. It did take effort to learn the language, but it was worth it. Having apps running an order of magnitude faster with better response times is just icing on the cake. Perhaps consider getting a gentler introduction to the language, the Odersky book is rather long and goes into excessive detail about obscure corners of the language you will seldom ever see in a production system.
I've been in enough code reviews of Scala that did simple things like string processing that inevitably got sidetracked into a navel gazing discussion about type theory, pattern matching, and functional programming to not go near the language again anytime soon. You simply couldn't understand the code without understanding tons of incidental complexity about the language.
The Clojure community has its navel gazing of course, but every time I've been exposed to some crazy idea in that community it was always through the lens of providing real leverage for real problems. Most of the time when I've dealt with people trying to explain concepts to me for Scala code, I've walked away wondering what the point of it all was (beyond the fun Computer Science.)
Maybe you should first learn the language? It would save your time, really. You must know the language to understand programs in that language. Simple as that.
If you don't want to learn FP or you don't value type-safety, Scala is simply not for you.
Scala reminds me of C++ too, but it's impressive that, in a mere 10 years, Scala has achieved all the multi-paradigm incoherence it took C++ 30 years and tortuous backwards compatibility constraints to attain.
Actually, I spent some time over the weekend trying to get familiar with Scala by using it to solve some Project Euler problems, and it was pretty entertaining. Still, the language's bias towards there being more than one way to do anything does worry me; it does seem that the kind of mutually incomprehensible code bases the OP talks about are likely. I would assume that, like C++, you need a strong style guide for a Scala project laying down which parts of the language you are going to use. Does anyone have any recommendations for guides on writing comprehensible, maintainable Scala?
Multi-paradigm incoherence? There is a huge difference between throwing multiple features/paradigms into one language (as C++ does) and integrating them so that they are orthogonal and don't get into your way (as Scala does). The integration part is the hardest thing and Scala designers did the great job there, assuming the constraints that were given.
Scala does have some rough edges but they are not the kind of C++ ones, and even the complexity of the most powerful features (implicits) is very controllable.
Seriously - which features would you like to remove from Scala? I'm really curious because I don't find any redundant ones. All are pretty complementary and very useful.
I'm not sure I'd remove any, but there is a huge incoherence in what is and is not "idiomatic" scala.
The most obvious example that comes to mind is whether you should use mix in traits or type classes for api design. Another one is the "magic-ness" of map/flatmap/filter for for comprehensions but no way to extend that for Functor/Monad/Monoid type classes.
Finally, the Scala community is a huge advocate of Algebraic Data Types yet don't support Disjoint types making any sufficiently complex system cumbersome to model as an ADT.
Thanks, that's really useful. It answers a lot of the irritating little questions that Scala's flexible syntax gives you, like whether or not to use dots for method invocation. I see that Twitter has a document on the best ways to write Scala, which looks interesting: http://twitter.github.io/effectivescala/
Because of Clojure's dynamic typing and idiomatic use of lots of nested expressions it turns out to be a read-only language for me.
Scala seems to have a huge image problem. I think part of the problem is that Odersky and crew have never written the treatise on how to use Scala's OO and FP effectively. I'm surprised that Typesafe didn't come up with their own web framework instead of using Play.
One lesson to be learned is that these days you need good IDE integration and fast compiles (incremental) for rapid development. But Scala IDE support has come a long ways in the past year or so. The Eclipse Scala worksheets is awesome. I like it better than a standard REPL. Intellij support is still going strong too.
I tried learning Clojure, I really did, and I have to agree, the syntax is simpler, but I can't really read Clojure or code in Clojure the way I do in Scala, I don't know why.
Whenever I read articles about Scala, I keep finding it amusing, prehaps this is because I had experience with Java, but for me Scala is a life saver, can't go back to Java after this. And I won't go back to Ruby, Python or JavaScript. So I can't really understand what these articles try to achieve, it's like the "don't buy bitcoin" articles, not sure what is the goal. If you don't like Scala, thanks for sharing, but I don't see how it affects me, I will still continue using it as my go to language until I find something better (there are contenders, Kotlin, Ceylon, Dart, TypeScript, and my favorite now - Nimrod, but there is still a big gap for me to fully switch)
So for someone like me who wants a statically typed language (there goes Ruby, Python JavaScript, Clojure), who thinks Haskell is too academic to be really productive (I have to think too much to get things done with it) and who don't get what is all the rage about Go (perhaps because I'm not a system programmer, in any case I still don't get it, sorry)
This leaves me with no other options (except C#, which I would probably use if it was really portable)
Scala is not perfect, but I feel more productive with it than with any other language, if anyone who never used Scala will decide not to even try it because of this article, I wish them luck, but I doubt this will be the case. for those who use it, they will still continue.
So I really don't think I understand what is the point of such an article. Try the language for yourself, if you like it use it, if not, and you have a choice, don't.
p.s. for all those poor bastards who are forced to use Java at work, Scala is by far a gift from the Gods, so it helps to keep things in proportions, one man's source for a rant article, is other's source of means to finish work at 5pm and go back to the SO and kids. (they would go back at 1pm but their Sun Certified Java EE team lead brain will explode if they will use Clojure, with Scala your EJBs or Spring code can still look recognizable, perhaps a bit more pretty)
p.s. did I forgot to say I love Scala?
This times 1000. I have been using Scala for the past 3 months in a play framework app that serves json. Today I had to write some quick Java for an Android client, and was quickly reminded how much freedom Scala's expressiveness gives you vs Java old cruft.
I mistakenly wrote a Java anonymous inner class that called a closed over variable from the outer scope like one would do with Scala closures. Of course the Java compiler threw an error because I didn't mark the variable as final.
When programing in Scala, one never has to deal with such low level rigidness. It just let's you get shit done.
Well, be careful with those closures. Scala's compiler won't (yet) throw an error if you close over a variable from the outer scope while operating on a Future.
The Scala team does have a plan to fix this though. Of course, if you aren't operating asynchronously or you're only closing over immutable values it doesn't matter anyways.
I feel the opposite regarding Clojure and Scala -- Clojure just makes sense to me, whereas Scala gives me a headache.
As an aside, insofar as you have some sort of willingness toward C#, you should check out F#, which is functional with really nice type inference and none of the syntactic woes that I have come to associate with Scala. (Not sure how portable it is, I have heard stories of people using it with Mono, but I haven't tried it myself.)
You might want to check back on Haskell again sometime in the future. It has been my experience that the number of Haskellers writing productive "real world" code is increasing and as a result the paths to do those things are becoming easier.
Though, this could just be me getting more comfortable with the language, knowing where to look, or a combination thereof.
So I am curious what npm gives you that sbt doesn't. I have heard it a few times how much better npm is but i haven't seen anything it does that sbt doesn't
>And then you realize that you don't really need Scala-ing if you can do the same stuff in Java or any other strongly typed language.
That's the turing completeness fallacy. Why not just write everything in C? And java's types are inadequate for doing really generic methods - how would you go about writing scalaz's "sequence" in java?
Question - the job/hiring post on hen for November has many positions for clojure and one definitively for Scala. Here, I see references to investment banks using scala.
Has scala become a readable alternative to java, while most of the future focus is on clojure? Does anyone know how real life performance compares between both.
From my viewpoint, scala is in use at several banks and Twitter - clojure doesn't really have a big name advocate behind it. From a startup standpoint, isn't talent/hiring an issue?
Real life performance generally favors Scala over Clojure, but by a relatively small factor (2x). This is mostly due to the clojure implementation's use of reflection to achieve dynamism. Dynamism? You know what I mean. You can make this up with some really clever tools for parallelism though, if your problem fits.
This is totally bogus. Clojure will only use reflection if calling into Java interop with ambiguous types and even those cases can be addressed with type hints (if they even matter).
There are some big places using clojure - the Daily Mail uses clojure heavily for it's website, as do SoundCloud; also, like Scala, it's used internally at some financial institutions - CitiBank have some clojure, and we've been using clojure at IOOF (an Australian superannuation company).
Performance is probably the last thing you need to care about when choosing a programming language for most businesses - unless you are doing hard-core analytics or handling huge scale, you just won't hit the sort of performance problems that are solved by a faster programming language (as opposed to a faster algorithm or architecture).
It really frustrates me that people _still_ put such weight on low level performance. In 1997 I had people saying "don't use Java, it's performance is far worse than C++". It was mostly untrue for business problems then - and computers are many orders of magnitude faster now.
Some other examples are Prismatic, Runa (recently bought by Staples), Climate Corporation (recently bought by Monsanto), Twitter (via acquisition of Backtype), etc. And there are a number of other big name companies very quietly using it to just get stuff done.
I think the real world popularity of scala is significantly higher than that of clojure (e.g. TIOBE rankings). I don't think there is any more "future focus" on clojure - scala is still making big new releases all the time, and IMO it will be easier for scala to gain clojure's flexibility and compile performance than for clojure to gain scala's safety and runtime performance.
TIOBE is garbage but I would not dispute that Scala use is higher today. However, Scala and Clojure use both continue to rise.
Well-written Scala and Clojure can provide comparable (ie Java level) performance.
Clojure has tools (like core.typed and Prismatic's schema library) to optionally provide you with static typing where you want it, without the burden where you don't need it.
Clojure does regular releases every year (that continue to be high quality and maintain backwards compatibility) and now has paid developers and support that will continue to accelerate progress. Because of the flexibility of the language, a great deal can be done outside the language in libraries (such as the entirely new concurrency paradigm in core.async).
> This issue reached its pinnacle for us when we were unable to figure out how to replicate the magic response composition syntax used by Spray to abstract away the addition of CORS headers to HTTP responses.
I'd just put any kind of application, whether built in Scala, node.js or Go or ruby on rails behind a nginx proxy and use that for setting the headers. That simplifies a lot of things. I hope your HTTP headers aren't really so dynamic that you need to build software that changes them so much, especially not for a RESTful application.
323 comments
[ 4.0 ms ] story [ 286 ms ] threadEclipse allows very fast compilation times, but when I tried sbt, I gave up because I CAN'T wait for compilation: we're in 2013, I'm using a quad core at 3.4GHz, 12GB of RAM and SSD, so I'm not ready to wait. Eclipse allows fast incremental compilation.
Scala's type system is very rich. I don't know if there exists any type that can't be expressed in Scala. Since I don't know if such a type exists, I don't miss it. But that's probably too much, and in the end, idiomatic Scala emerges: some libraries use the type system in an idiomatic way. It's working, but understanding method signatures turns into a nightmare. Then you must learn the arcane of Scala to understand how the library works.
However, if YOUR Scala is simple enough, then the language can be cool, cooler than Java, and productive. Can be mixed with Java, runs fine for J2EE...
Scala has a very rich type system, but let us not get ahead of ourselves--Scala, being non-dependently typed, cannot type many useful programs.
For an example of a useful dependent type, consider giving division the type Number -> {x : Number | x != 0} -> Number. Giving division the type Number -> Number -> Number is similar to how older Javas would type List<String> as List and require all get operations to cast from Object--in both cases, the type system is unable to guarantee that your program won't crash.
If you want a glimpse of the state of the art of programming with dependent types, try Agda[0].
[0]: http://wiki.portal.chalmers.se/agda/pmwiki.php
For example if my function returns a Vector[A, N] (a vector of A's with size N), and I try to pass it's return value to a function that expects a of type Vector[A, 2] my code will not compile. This is because there is no way one can prove forall A N. Vector[A, N] satisfies Vector[A, 2].
Which seems weak since smart developers should do that anyway, but (a) there's still some divide between "should" and "it's impossible" and (b) this is just the tip of the iceberg about what dependent types offer anyway.
Check out https://en.wikipedia.org/wiki/Agda_(programming_language)
Kinda. Let's be honest: in production this often turns into a pain in the ass. There's some value in dependent typing, but providing evidence that concatenating UTF-8 strings is associative is not one of them.
I do agree with you that there are times when 'full' type checking is inappropriate. Typing is a spectrum, and it's a bit of an art to decide how detailed of guarantees to give for your API.
However, I wonder how much actual utility they can provide, seeing as (1) dependent typing is generally acknowledged to be rather difficult (and that's a statement coming from those who generally tend to already be good at a language like Haskell), and then also (2) the fact that a great deal of real-world applications, such as FFI, accepting data over a wire, dealing with exceptions and faulty input, etc, mean that no matter how bullet-proof the code you write is, you'll still have to account for all of the ugliness which the world can throw at you, which means unit testing, exception handling and other things which seem to undermine - to a degree - the strengths of strong typing in the first place.
Or am I exaggerating things? I've written a lot in Haskell and enjoy it a great deal, but at work I use Python and JavaScript, and honestly, although there are some things that would be streamlined away by a strong typing system, particularly in the development cycle, there are still a ton of ugly, mundane real-world things that would still need to be dealt with in much the same way if they were written in Haskell. I would still love to have the opportunity to write in Haskell (or Agda or Idris, etc) at work, but I'm not sure how much trouble it would save me from at the end of the day. Would it? And would the additional mental hurdles of dependent typing add real tangible benefits on top of this?
object Positive { def unapply(x: Int): Option[Int] = if (x>0) Some(x) else None }
val onlyPositive: PartialFunction[Int, String] = { case Positive(x) => s"check out this positive number: $x" }
This would throw a MatchError for non-positive Ints, but you can also handle the failure case like so:
def onlyPositive(n: Int) = n match { case Positive(x) => s"check out this positive number: $x" case _ => s"not a positive number: $n" }
This is a quick example, but in practice the lack of dependent types is not a huge handicap.
We all want more powerful tools and infinite expression but at what point are we bikeshedding languages instead of building transparently clear solutions?
Scala seems to be solving problems i dont have.
As a long-time Java dev myself, Scala is solving problems you don't even realise you have, because you don't know to look for them.
Powerful types, immutable state and FP make a world of difference for writing clear solutions, with better abstractions, less code, less bugs and less bullshit than the horrendous status quo of corporate Java development.
It may take some getting used to syntax and design wise, but being able to code things up in 1/10 the size of other languages completely blows away the disadvantages of Scala.
that's still a thing? i thought i was just being dumb back in the day.
I have much more faith in the JVM but would like to see it provide a step beyond Rails rather than catching up. Play is nice because it is trying to accomplish this with Akka, though yes I see there are other issues. As mentioned in another comment, I'm kindof just wishing there was a cool Clojure framework. Maybe I will try one even there is not so much of a consensus as there are around these other emerging JVM frameworks...
Think Sinatra instead of Rails.
buuuut as retrogradeorbit points out.... the clojure macro system is powerful, so maybe it lends itself better to this type of setup
It's also a pleasure to program in Groovy.
Though my tip though for the long term replacement of javac is Scala. I'm very impressed with it! I can honestly say if someone had shown me the Programming in Scala book by by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy. So why Scala? Scala is statically typed and compiles down to the same fast bytecode as Java so its usually about as fast as Java (sometimes a little faster sometimes a little slower). e.g. compare how well Scala does in some benchmarks with groovy or jruby. Or this. Note speed isn't everything - there are times when you might want to trade code thats 10x slower for more productivity and conciseness; but for a long term replacement for javac speed is important.
His dissatisfaction with Groovy concerned more than just its speed, and originated much earlier, see his very last Groovy mailing list posting [2] in Dec 2005 just before he left the Groovy development team:
The MOP and introspection APIs do NOT solve the horribly broken name resolution rules in the current RI of Groovy [...] I see no argument yet for why we have to throw away decades of language research and development with respect to name resolution across the language as a whole [...] It just feels totally wrong to break Closures across the entire language just because of some use cases for Markup.
Groovy is sloooooooow, its recent static typing is buggugguggy and not even used by Grails or Gradle, and its closures are broken. Its "recent surge in popularity" was also probably based on deception [3]:
Groovy, which turned up in the [Tiobe] 18th spot last month [October 2013], slid back down to a number 32 ranking [Nov 2013]. "After a long discussion with one of the Tiobe index readers, it turned out that the data that is produced by one of the Chinese sites that we track is interpreted incorrectly by our algorithms. So this was a bug," Janssen said. "After we had fixed this bug, Groovy lost much of its ratings." The ratings slip takes Groovy from a 0.658 percent rating last month to 0.393 percent this month.
This has happened before. In April 2011, Groovy fell from #25 to #65 on Tiobe in a single month after they increased the number of search engines they monitor. Groovy had begun its short-lived rise just after December 2010 when Groovy tech lead Jochen Theodorou "volunteered" his services to Tiobe to help them improve their algorithms.
[1] http://macstrac.blogspot.com/2009/04/scala-as-long-term-repl...
[2] http://groovy.329449.n5.nabble.com/Paris-write-up-tt395560.h...
[3] http://www.infoworld.com/t/application-development/c-pulls-a...
In Java's OO paradigm, instance variables are inherently defined separately from their initialization, making it quite difficult to make sure they're always used when initialized, properly.
The nullability stuff bites me over and over :(
Forgetting to use .start() on a thread is a stupid runtime error, instead of using some design where it isn't possible to forget .start() or at least get a compile-time error.
I am also using a lot of C in parallel, and with the C preprocessor, I am finding that C is often more expressive and nicer to use than Java!
Everything takes ridiculous amounts of code.
For example, in Haskell, I can write:
To get a thread-pool of 10 threads looping around my code, and put their thread ids in a variable.In Java, this requires so much effort!
Not to mention the utter lack of sum types and pattern-matching, making tons of Java code that looks like:
arrrg!Android uses named integers rather than enums, due to some issue with Java enums.. And the switch would only help a bit, the main problem is needing to correctly interpret the associated payload according to the message type. That's what sum types give you, which Java doesn't properly have.
They could be emulated with visitor pattern, if one is masochistic...
I think in truth, though, if there were a web framework in Clojure as well received as Play I would be bounding down that path instead. Clojure seems to be where a lot of the JVM interested is heading yet we're not there yet for some reason.
My belief though is that there is some peace of mind that comes from the idea of what you might call "page composition" -- that this piece of data sits in this template, that it rides on top of this simple model, that it is in ORM from database. There is a huge amount of linearity and convention throughout the stack and because of the dynamic nature of Ruby lots of gems can be sprinkled throughout without one really understanding what they do.
Now, I'm certain this level of abstraction and functional/mixin kindof stuff can be achieved in a Clojure framework but I think it is generally perceived as being a bit more non-linear and DIY (libraries not necessarily playing nicely together). As in "yes I can get all of these pieces together but then if down the line I have to change this piece, how will I accomplish it without breaking everything". Essentially, I think the perception of OO is more alluring in terms of project cohesion, whereas functional programming is seen more of a supposedly incorrect assumption that an HTML document is simply an assembled mass of text.
I'm really just trying to convey that RoR and the like seem to be making a COMPLETE ("in a few lines I can do anything short of my business's custom domain logic") framework out of the box and perhaps there is some stigma attached to the nature of Lisp that makes it seem as though framework developers are not striving to cross these bridges and there is less of a community to keep them in check.
Eh, I wish that made more sense but this is a lot of conjecture based on perceptions -- it's clear that a lot of these communities emerge from hype & reactionary values moreso than anything else. People wanted to shift away from PHP and be more productive without getting radically far away conceptually. I just got dizzy thinking about this lol... but yeah I think Java developers are a bit more open-minded when it comes to application development, seeing things more matter-of-factly than the languages with only MVC/Model2 kind of frameworks. I think if an attractively-packaged Clojure library were to emerge and get the right publicity (sad but thats how the web dev world is...) it could steal the hearts of many Java devs.
In my limited experience with Clojure it seems fun AND powerful. Yes there is a learning curve but that is to take it above and beyond. The simple functionality of most web apps could probably be achieved without writing anything too mind-bending.
Please do respond even if that response involves completely ignoring my rambling... I'm very curious to understand the Clojure community better :)
"Clojurists looking for a standard way to build internet applications will love Pedestal. Rather than composing art out of found objects, they will now be able to mold a single, consistent form to match their vision.
Pedestal may also appeal to developers who have been nervously approaching a functional language but who haven't yet mustered the courage to ask it out on a date. It provides a sterling example of how to use the Clojure ecosystem to its best advantage, reducing the friction usually associated with a language switch."
Objects call objects across the system and change the state of each other without care. Making a trivial change involves unrolling this web every time.
And that's why I think you have this backwards:
`require`ing a Ruby gem is as non-linear as you can get. It's global with no entry-point. A gem's presence and effects are not obvious. They're often configured with some mutation like: Meanwhile, it's obvious when a namespace of Clojure functions is included. And since they're just functions, they're trivial to compose. Completely different experience from what I was used to in Ruby.I feel you whole-heartedly about the tangled web of OO. That's why I ultimately chose to leave Rails & start pursuing JVM languages. JVM languages seem to be daunting to Rails/Django folks because of all the "boilerplate, syntax, complexity" but I've found that a lot of the tools are so mature that it is not really such a burden. So yes, as an aspiring programmer who wants to have a reach beyond CRUD, the mystery of Rails & it's "fugly" libs eventually turned me off. Aside from things breaking/slowingdown with every version and needing excessive optimization not to accumulate at the interpreter, I came to the realization that the extra time that would be needed to understand more technologies for the different layers of the application (with Java.... Spring/Hibernate/etc.) there is a gain in that well... you actually understand what is going on rather than this tangled mess. I often had to re-factor code in Rails to kindof fit awkwardly between gems. From studying Javascript I learned a lot about asynchronous/aspect-oriented programming and am pleased to see that these concurrency issues are fundamental to most work that is happening on the JVM. I thought Scala/Play was a healthy medium between these two worlds but I'm starting to understand that maybe one needn't compromise.
I don't really know that I miss anything. The things I might've thought I'd miss are the things that ended up souring the taste of Rails.
Having to come up with my own abstractions or recreate familiar conventions or set up a database were areas where I had to cut my teeth, but I also had to cut my teeth on Rails when I was learning it.
Rather than missing anything from Rails, I find myself using Rails' conventions as a loose model and then simplifying it. For example, my "templates" are now just functions that render html. My "layouts" are just functions that get applied to templates. I don't need to read Rails' template rendering guide to come up with a hack. Instead, modifying my templating system is trivial and obvious.
Would be interesting to see a blog post demo'ing your workflow.
There's nothing so terrible about that per se--it's a great way to learn--but it can feel like a high friction workflow compared to Rails, especially getting started. I think it's primarily a function of community size and library maturity, but there's a cultural element as well. Rails has more of a beginner-friendliness-is-good mindset (even when library internals are fugly), while in Clojure the focus is more on the strength of the functionality and less on easily grokkable apis (though there are notable exceptions).
The Luminus micro-framework (http://www.luminusweb.net/) is a great choice providing a starting structure around existing libraries. Caribou (http://let-caribou.in/) is a more full-featured framework for building web apps. Pedestal (http://pedestal.io/) provides heavy-duty tools for creating data-heavy single-page apps.
And there's a new book on the way about Clojure web dev http://pragprog.com/book/dswdcloj/web-development-with-cloju....
Coming to Scala from experience including C, Java and Haskell, I intially found Scala quite difficult. It is true that there are some things in Scala that are not obvious to newcomers, and that are difficult to discover for yourself - such as the use of Implicits, and the strange precedence and binding rules for operator syntax.
That said, it doesn't take long to learn, and once you do, it all makes sense. There are other great languages out there (I'd say Haskell is one), but compared to for example Java, or one of the dynamically typed languages, Scala is superb.
Types, whilst not having the full H-M inference, are brilliant. That the author complains about having types rather than a simple map for keys shows a misunderstanding of what they are there for - the idea is to allow the compiler to prove at run-time what is valid code and what isn't. He comments that tests run too slowly in Scala (they don't - for our production systems building in SBT, a typical test run is significantly less than 10 seconds) but a lot of the time I don't even need to go that far - my IDE already highlights errors in the code as I type, where I have passed in incorrect or insufficient data.
Also, the author makes a strange comment that H-M 'enabled' Monads, and the comment is written in a way that implies that Scala does not have Monads. This is incorrect. Scala has monads, and the Scalaz library has huge support for Monadic programming. We use Monads and Applicative Functors (a close relative) daily to build high level abstractions, and we couldn't live without them. In Scala we say flatMap rather than bind (or >>=), but we mean the same thing. Although thanks to the same flexible method naming that the author complains about, you can in fact say >>= if you wish.
If you've only got a couple of days to use a language, and you're using it for a tiny project, then Scala is not for you. If want to learn a language that can make you vastly more productive whilst at the same time making your code safer and more robust, Scala is a very effective candidate. It's not the only candidate, but you should at least consider it.
I'll give an example of the power of Scala's type system. When I first convinced one of our founders to give Scala a try, he used it to write the first pass of our analytics service. He'd never written Scala before but once it compiled, it ran correctly on the first try, that's the power of its type system.
I mean mistakes can happen and if the type system can catch it for free, so to speak, that is great. I'm not about to argue that it is completely useless. But in terms of probabilities of what kind of bugs might be introduced, type errors seem to be on the low end.
To infer that Scala's type system is powerful enough to catch the more common types of mistakes programmers make, that is quite an impressive claim. I am curious to know more.
A more complicated example. In one scala system I worked on we had a master/slave postgres db system. We were replacing a legacy RoR system with a Scala system, and in the RoR system there were all sorts of data inconsistency errors caused by people writing to master and reading from the slaves before replication occurred.
In the Scala system which replaced it, we set up a monadic action system. A function which hit the database would have a type signature either PReader[T] or PWriter[T] - this was the only way to access a java.sql.Connection short of manually calling jdbc. Combining the two forms yields a PWriter:
The whole operation runs in a single transaction against the correct database, and any attempt to do the wrong thing is a compile error.(Though of course there is an escape hatch, you can use RawHeader(name, value) if you need to).
However, that is not really what's going on... though Scala type system, even without dependent types, is strictly more powerful that Java's, it really comes down to the ease of use: Scala programmers tend to use types liberally (which was one of the criticisms of the article), and that is part of the "magic".
Part of this is how easy it is to define a type: it can be as short as a single line. So you'll see way less String types in Scala, for instance, or "one type to do it all" like the article wanted for HTTP. Instead, you get many types, in which invalid states are not possible and, therefore, getting the types right is enough to ensure there are no invalid states.
Likewise, the partial type inference offered by Scala makes it possible to not worry about all these types: the compiler knows what type you got, and knows whether it can be used the way you are using it, so you don't have to keep looking up types to get things accomplished, but still get to have the types.
Another part is that Scala support higher order types, something not supported by Java, which makes them more useful. That's what allows monads & companions come in and make an appearance -- it's not that you can't write a monad in Java, it's just that you can't abstract over them.
The final part is emphasis on immutability. When you stick to immutable objects representing valid states, the space for errors not caught by the type system is greatly reduced.
Let's get back to the headers, then. First, yes, you are allowed to add arbitrary headers (which is supported by Spray through RawHeader, something it took me 30 seconds to find out, even though I have never used Spray and have little familiarity with it), but section 14 of RFC 2616 has a nice list of standard headers and the rules they are expected to abide by, so let's have them.
And if you have a header, and it is a X-Forwarded-For, isn't it reasonable to expect the value to be a valid remote address? It is supposed to be a valid remote address, after all. So, if you ask for this header, should you simply get a string that may or may not be actually valid, or should the type system give you an Option that may contain Some valid header, or None, therefore ensuring that you don't just assume you are getting the right thing? And if you get something and retrieve the value, is it preferable to just get a string, that might lead to some ad hoc parsing of the address, or some actual type where you can easily retrieve information in a safe manner?
The Scala community will usually think that yes, that's a good idea, and design the APIs accordingly.
There's some evidence from what the author wrote he's aware of the benefits of type systems. The question he raises is whether the developers who wrote Spray modeled the problem domain well by choosing this particular set of types (his opinion is clearly no).
> the author makes a strange comment that H-M 'enabled' Monads, and the comment is written in a way that implies that Scala does not have Monads.
Given that the author immediately follows his "enabled" statement with the idea that monads can be used in a type-free language, I think it's most likely he means that H-M has been the ground where the use of monads has been largely developed/defined, not that monads can't be used in either Scala or even something with a considerably less expressive type system.
I think because it allows you to do OOP and FP, Scala becomes difficult since it is so easy to mix the styles. Similar to C and C++, this is very powerful, but also very dangerous. The main learning curve is programming in a way so you don't shoot yourself in the foot while using its flexibility.
But, esp when working with collections, I take advantage of Scala's features. It's not perfect, but it works wonderfully. I can always revisit/refactor my code again later.
Here are a couple examples:
myVar match {
}myVar.getOrElse("else")
In both of these cases, we eliminated the possibility of a NPE through the use of a language feature. :)
(edited for formatting)
I think he's aware of that - he said he's using Scala as a better Java, what would Java be without the odd NPE?
Things I have in Scala that I like and Java 8 won't provide (many are syntactic sugars and non critical stuff, I know, but I like it, I'm spoiled)
- implicit conversions. some hate it, I love it. It allows much better "pimp my library" mechanism than Ruby's and it's very easy to write extensions to your or 3rd party extensions in a safe and easy manner
- duck typing, e.g. allows to write a "try with resource" without native support for anything that implements "close"
- automatic tuples
- better type inference
- semicolons, hate them
- automatic equals and hashcode for case classes
- case classes
- futures and promises
- by name parameter passing (passing a block of code without running it)
- partial functions, multiple parameter lists
- for comprehensions
- pattern matching
- nested functions
- lazy vals
- everything is an expression
- String interpolation
- multiline string
- default parameters
- named parameters
- pattern matching
- everything is immutable by default
- very string type system
I think that's it. Yes, Scala is infamous as the language that took many many features from other languages and piled it all together, well, fine with me! you say more features that are great in other languages and make people productive? (and are kind of expected, like default parameters etc) I say bring them on and the more the merrier. I can choose which features I want to use out of the way too many features the languages, much better than waiting years for features to be added. Hater's gonna hate, I'm still going to write Scala until something better comes around. (Nimrod? Kotlin? Ceylon? TypeScript? Dart? perhaps even Go? Don't know... time will tell)
You lose out on most of the features of Scala, and IntelliJ supports Scala very well.
I should say one thing however:
I'm using Scala because of Akka. An extremely powerful library that does a good job of hiding the complexities while still allowing you to be flexible.
An immutable List of Foos is a List of Bars if a Foo is a Bar. A function taking X and returning Y is a function taking A and returning B if A is a X and Y is a B.
It's just answering the question "Can I use type relationships to guarantee that I will have no run-time conversion failures?"
+ (covariant): the type can be cast to some broader (more general) type
- (contravariant): the type can be cast to some narrower (more concrete) type
Slow build times complaint
> It is essentially impossible to practice TDD in Scala simply due to the time it takes to compile.
Hrmm, that's interesting, because it sure seems like other people are able to do this. I agree, the slow build times are annoying, but let's not exaggerate.
SBT critiques
>That punctuation-strewn build system I was forced to use was just taking advantage of Scala’s ridiculously flexible syntax.
Yeah, I get it, everyone makes fun of SBT's syntax.
Language is complicated
This is where it just kind of descends into whining about how 'hard' the language is. He claims javascript is a "simple" language. Does he just not count the weird edge cases when thinking about complexity?
Type inference complaint
> And this is the real death knell for Scala. Hindley-Milner Type Inference is a fantastic thing.... It’s enabled monads, which you want to be able to understand and then use in a type-free language.
WAT. I don't think those words mean what you think they mean.
>In my mind, Hindley-Milner was always the promise and the pay-off for Scala...I know this is the fault of the JVM’s use of type erasure. I don’t care.
O REALLY? Go on...
Maybe if this guy had cared enough to do a five second google he'd realize that Scala doesn't use hindley-milner type inference.
Bottom line is, I think I have a good understanding of the type of programmer this guy is, and it's exemplified nicely in this quote right here:
>Sure, with another couple hours we would have been able to figure it out… [but] We ended up copying and pasting the same four lines into all our endpoints. A dark moment.
For an intelligent critique of the scala langauge see here:
http://www.reddit.com/r/haskell/comments/1pjjy5/odersky_the_...
That's his point. Scala doesn't use HM and it needs to. He says the reason it doesn't is because of the JVM, which seems misguided.
Note: It's been a while since I've seen traits, this might have changed for better.
To me Scala is essentially if Java, Haskell and C++ went to a wizard to have a child. The result is a magical mess. I seriously think that Scala has at least twice as many concepts as C++ and same if not greater number of really weird edge cases. I don't want to keep Scala in my mind, no more than I want to keep Necromicon.
If you can't override variables, you can't silently change the structure to depend on trait order. You'd have to explicitly state order.
PS. Of course if you have several same signature methods that call super, which is generated depending on order, same problem persist. So, forbidding variables and calling super elements should deal with most "magical" interactions.
Still, it's a shame that most people interested in programming languages have never heard about Eiffel, or ever read the superb book "Object-Oriented Software Construction" by Eiffel's creator, Bertrand Meyer. Eiffel has many flaws (the most proeminent being the complete lack of support for functional idioms), but it has very good ideas as well. (Perhaps the most popular influence Eiffel had on other languages is Design by Contract and the uniform access principle, which you see in most "modern" languages.)
http://play.lighthouseapp.com/projects/82401/tickets/98
I loved Play 1.x(early adopter also) but I have since moved on. I gave Play 2 a solid chance. Scala programmers seem to turn everything into some kind of academic paper.
I wanted to create pretty urls but I couldn't do it in a simple way because the developers thought that in a path can not be optional parts, like: /article/1/article-slug and /article/1
So they removed a useful feature. And it was in a 2.x -> 2.x+1 release... Yesterday it worked, today not. I was not happy. :)
http://stackoverflow.com/questions/14980952/routes-with-opti...
My othern concern with scala, what is mentioned in the article, is the operator usage.
How am I supposed to "invent" this <:< notation for adding headers? (dispatch lib) `val svc = url(object_url) <:< Map("User-Agent" -> "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)")` or in squeryl, converting a boolean into a "query boolean": ``` val fls = false fls.~.? ```
Other than these, I like it. When I am coding in JS or PHP I always praise the scala types/ compile time checks. I am almost afraid of dynamic typing since I tried scala. :)
And the fact that its completely optional means that its easy to get it out of the way when its not possible to express some constructs with it.
rust-http is, at present at least, rejecting the standard practice of stringly typed headers and is using strongly typed headers.
> ... and even types for every ‘known’ HTTP header.
> The known HTTP header part was particularly ridiculous. HTTP headers are defined as simple key/value pairs. You’re supposed to be allowed to add arbitrary headers. You’re not supposed to be constrained by the framework you’re using not having any support for CORS yet.
He has taken a strong position against this strong typing; I take a similarly strong position for such strong typing.
Yes, HTTP headers are defined as simple key/value pairs. But headers are not text; they are data. XML is defined as text. Should we use regular expressions to work with it? (True, it also has the DOM defined. But HTTP headers also have a grammar defined—it just happens to include the admissibility of extension headers.)
HTTP is a serialisation format for messages; messages made up of computer-readable data, not text.
I wrote a handful of paragraphs about this subject at https://github.com/chris-morgan/rust-http/issues/1 where using a map instead of typed headers was suggested.
As I also note there, I would not attempt such a scheme in a language like Python (my primary language for some years) because its type system is not well adjusted to something like this; I am certain it would cause many problems and feel it likely it would cause more than it solved. But in a language with a solid type system capable of expressing these things, taking advantage of it should lead to a faster, more correct program.
In the end, I believe strongly typed headers are a good thing to have (it will actually make most code distinctly nicer—e.g. ``response.headers.date = Some(now())`` instead of ``response.headers.set("Date", now().to_http_header())``). The implementation of the scheme in rust-http is certainly not perfect yet; I'm not happy with it at present; I'm expecting to turn the extension headers into a trait object, and I've even considered crazy ideas like allowing users of the library to make their own header collection (request.headers and response.headers) types—that would allow custom headers to be made first-class citizens but could lead to compatibility problems.
Still, I don't want to make something that I believe should be the best HTTP library around and find that people hate to use it. What do you think about this header matter?
As a (albeit poor example), I once inherited a click tracking system that uses Java Jersey. The standard response object has a .redirect(URI uri) method. Unfortunately, many "URI"s we receive from the world are not actually value, and the java URI object refuses to build URI objects from the string. Fortunately, one can simply call .setHeader(String, String) and be done with it.
When the framework treats a a valid http header as invalid the framework is probably using the wrong abstraction for http headers.
In the past when I have used such libraries they have been a pain - especially for loose formats like HTTP headers. Type system come with a cost, you need to carefully consider the burden you are placing on the programmer to see if the benefits out way the cost.
You can be both . . .
IMO, all the fields need to have a Printable and Readable trait (or whatever Rust's version of those are). If you want to do special things for certain fields to make them easier to work with, I think that's cool too. But if you force people not to treat headers as text, I think you're going to have a problem.
People say the same thing about null pointer exceptions, but null pointer exceptions are a huge problem in practice. Every bug is "obvious" in retrospect.
I do understand the desire to prevent these sorts of errors at the language level, but not at the cost of functionality. I don't agree with this one, but I do (for example) appreciate libraries such as the STL which (hopefully) prevent that pointer issue you brought up (and more). The STL doesn't (often) force me to work around silly limitations though.
Does this library provide for creating arbitrary headers in some other fashion? If not, why?
I love that there are people who say things like this totally seriously.
I've worked on very large, complex, mission critical systems my entire career. Medical devices mostly. If you're not catching these sorts of errors early then you aren't modeling and testing your software correctly (or at all). All of the objects in the world aren't going to prevent you from writing bugs and crappy code. OO is no panacea and we've known that for quite some time now. I don't want to use a library which is limiting because it thinks it is doing me a favor.
I don't think I'm infallible (straw man much?), but I do think that dead simple errors such as this would be caught by any amount of actual testing. That said, I wouldn't be against a better design. Why doesn't this library provide a way to add arbitrary headers? Oh, right, that would still involve using a string. Gasp, no, that shouldn't be allowed. We have to protect the poor users of our library. Yeesh.
You can't always protect a programmer from themselves while still allowing the flexibility/power needed to get shit done. I'd rather use the map than some overly architected and frustrating library. I have a problem with abstractions that get in my way.
You are suggesting that you are infallible, as the "dead simple errors" you refer to get out into production systems every single day. More than one serious security hole in rails has been due to very similar problems. You are very much implying that you are a better programmer than the entire rails team. And virtually everyone else, as examples of these kinds of bugs are everywhere.
And finally, crying straw man while presenting a straw man is poor form. If a particular library has a deficiency, that's unfortunate. But it has absolutely nothing to do with type safety. Haskell for example is more type safe, and it has two http client libraries, both of which provide safety while also allowing arbitrary headers (and methods, etc).
EDIT: Eh... looking back at my original comment I don't think I got that across at all. It reads as more of a rant against a typed system in general, which is not what I intended.
It seems to me that, in the worst case, the downside of your current scheme is an extra field dereference, as in `request.headers.extensions.get("crazyNewField")` instead of `request.headers.get("crazyNewField")`. I think that cost is easily outweighed by the benefits.
Why not add a weak checking for k-v strings? Something like during compile time:
You don't have to use types to check this.I really like the spray way. You can add a custom/nonstandard header by using RawHeader(key, value), but most of the time you use e.g. Headers.ContentType(MediaTypes.`application/json`), and it just completely eliminates a class of trivial but annoying bugs.
And I'm not sure there's a good solution. The obvious approach, as you already know, is to separate headers into two groups: one group is "properly" handled, and the other group gets tossed into an "other" bucket of key/value string pairs. But it's going to be awfully tempting over time to have "proper" support for the most common non-RFC2616 headers, especially those which have widely-accepted standards of their own.
But that's a bit messy and much less than ideal, as you've also discovered. And I don't know of another way to approach the problem that still lets you have the stuff you want from the type system, and doesn't cut people off the minute they start using extension headers your library doesn't know about.
And that's without getting into all the completely stupid things it's technically legal to do in an HTTP header, and the even more stupid things that aren't legal but that people do anyway. My usual torture test of an HTTP library these days runs through things like non-ASCII content in header values (legal if properly encoded, and not everything in the wild properly encodes), looking to see how large a value a library will accept, whether it will let me throw newlines into headers, etc. etc.
I'll give you a real-world example. Mono. HttpWebRequest used to store the Content-Size value as an int32. What about files larger than 4gb? Oops...
That was a big problem for us. Thankfully Mono is open source, we were able to peruse the code and come up with some magic incantations using reflection to work around the fact that the framework libraries would not allow us to set the Content-Size header without going through the int32 property.
Now, normally you would file that as a bug, however, it (A) took years for a version of mono to be released with that fixed this and (B) could easily have been some misunderstanding in the implementation of the HTTP spec that was overlooked. You're implementing a spec right now. Can you guarantee that the your implementation is 100% correct? Can you guarantee that the spec is 100% correct? Can you guarantee that the spec is implemented 100% correct everywhere?
No, you can't.
So, don't limit me. Help me, but do not prevent me from doing what I need to in order to do my job.
https://groups.google.com/forum/#!searchin/golang-nuts/s3/go...
The short summary is that Amazon S3 does not behave like a normal web server and expects HTTP path's to be "url encoded". S3 is pretty obviously something you would want to interoperate with. Go's http client (which isn't very strict at all) causes friction here.
If people like OP are dissing a language because they don't like a particular library's API, they have very strange expectations from the language. And if you are worried about this section of users, then I would say in order to make good use of your time, it is best to ignore them.
If it's hard to do X in your language, but easy in other languages - then that's a weakness for your language, despite that 90% of X's will be outside of the language core.
And even 'optional extras' in your language can be weaknesses instead of features - if they are often used by library makers for less readable/maintainable code than the other options.
Remember Postel's law: "Be conservative in what you do, be liberal in what you accept from others."
Unfortunately, you will have to return URLs to your users that are invalid. You will have to parse slightly malformed dates. Your clients will expect to be able to pass through malformed values from bad endpoints and not introduce a point of failure in your library. (Do you know about the "Cneonction: close" trick, for instance? All real-world proxies do all sorts of batshit-crazy HTTP header munging.)
If your library can't accept and pass through arbitrary strings for arbitrary headers, and return them to users, and then accept them back again, then it is unlikely to be successful in any sufficiently complex and robust HTTP service.
1) src/main/scala/com/thingy/actualthingy JUST to get to the root of your code. 2) Recompiling/restarting is slow because liftweb and other frameworks are overly complex. 3) I'm 90% sure it would be possible to create a PRY-like debugging tool that runs your code in interpreted mode and drops you into the REPL at a certain point in your code. And yet, it'll never get built because Scala hackers are stuck in the halcyon java days of 1998. 4) Variable names first, types second = okay, now you're just being different for the sake of being different.
That said, it seems like if you use scala as a more concise java with some handy functional syntax thrown in, you can make something that isn't terrible for future maintainers.
2) Compiling Scala is slower than Java (sometimes much slower) but that's not the frameworks' fault. scalac is just slow, though getting better.
3) This does exist. In fact, it's built into the language. You can also use "sbt console" to load a REPL with your entire project in the classpath.
4) As the other reply said, type annotations aren't required. In that light, Scala's syntax for type annotations makes sense.
Sounds like Kotlin.
The critique about excessive and opaque operator use in libraries is fair, though I think it actually exposes an interesting philosophical issue. Scala is unabashedly written to be a flexible language. This is in opposition to Java, which was written to be a very strict language in terms of expressiveness on the part of the developer (it's perhaps the most strict of the languages I've worked with, hence it being my example). I personally think a lot of criticisms leveled against Java's verbosity and inflexibility are unfair, by virtue of the following: Many incredibly successful and complex open source projects are written in Java. While you could say this stems from Java's enormous popularity, one interesting property of huge Java open-source projects is that I can usually crack open the code and quickly get a sense of how I could contribute to the system without breaking it. While other languages often do a better job of giving me a sense of how the system works, I generally have much trouble with extensibility unless it's Java. This I believe is because Java was designed from the ground up with the goal of limiting individual developer expressivity in favor of imagining large development teams with limited cross communication.
So--I am far less anti-Java than most. But I am a big fan of Scala. Unlike Java, Scala was written to maximize developer expressivity. While writing Java can feel like putting together a legal contract, writing Scala can feel like creating a poem. I'm not making a value judgement in either direction there--I feel that poetry is a good metaphor, because things in Scala tend to fall apart in the reading department. One of the easiest things to do in poetry is to lose the reader--a great poet can put an incredibly complicated multilayered concept onto a small amount of paper--and require a graduate-level understanding from the reader to understand it. Similarly, one can very easily make Scala into an exercise in unpacking
So isn't that a bad thing? Why am I a Scala fan? Going back to my initial praise of Java--Java is so simple and predictable that it's really easy to see how the plumbing works. But because the plumbing must be laid out so meticulously and in every situation, it is often hard to see how things work at a high level. You can't see an architectural sketch in Java, you can only see endless classes in endlessly nested subdirectories. This is a very low level of abstraction, and helps the layperson (such as someone approaching a new open source project) build up an understanding from the base elements. But what's lacking is the high level abstraction.
Outside of programming languages, almost every knowledge discipline has a high level abstraction language--sometimes multiple languages. Usually the abstraction language is opaque to newcomers, and frustratingly so. Examples are the mathematical notations of various disciplines, the jargon-laden meta-language of historical theory/literary criticism, and what is popularly known as 'legalese'. But even less high falutin' fields have similar languages--listening to sports fans talking about what's happening can be quite mystifying to me, given all of the shorthand they're using. Similarly people talking about pop culture in areas I'm not familiar with.
These ubiquitous high level languages usually share two important facets: first, in a few lines of text/speech, you can pack in many books' ...
The poetry thing is really dead on -- when Larry Wall spoke of Perl -- he said he explicitly wanted you to be able to write poetry with it. This led to the write once, read never reputation of Perl... that Scala is quickly stealing.
Scala is on my "will not work with" list of languages/technologies -- which is generally limited to old languages/tools that I have experience with (like Progress 4GL, Mumps, etc), but don't want to touch. It is a maintainability blackhole and generally horrible (to me) to work with, despite being fairly comfortable with the core (1400 or so hours billed).
The groups I worked with made different determinations than your team, but if you guys love it, enjoy. Seriously, if you find a technology your whole team loves, you are KILLING it.
Both companies I worked with have since dropped Scala (after literally hundreds of thousands of dollars spent on the attempts) entirely internally due to maintenance and talent acquisition issues.
In my experience very little Scala code uses DSLs. Learning Scala isn't that tricky for anyone who knows Java, which is a pretty big pool.
Edit: It was two years ago so other than Lift and some SQL DSL I don't recall which libraries we were using. I do recall wishing I hadn't taken that job.
I once read an article about how Java programmers can hold a conversation on the topic of upsides and downsides of multiple dependency injection containers while C# programmers only have one available and have nothing to say on this topic. That article concluded that having one "good enough" solution can often be better than having multiple slightly different and incomplete ones, even if each has its own strenghts, and I'd say the same is true when it comes to the C# LINQ vs. Scala SQL DSLs.
The Scala equivalent is called Slick, and it's the only SQL DSL that approaching anything near widespread use. I fail to see how incomplete projects on GitHub which happen to be written in Scala are relevent to this discussion.
You are probably referring to "LINQ to SQL" which is different and significantly less popular technology than LINQ.
I too suffered a bit from DSL hell, especially some of the more extreme examples like the library "dispatch" where you need a "element lookup table" to figure out which squiggly line to use. But once you have a stable set of dependencies the initial DSL influx subsides and you start to work with a fairly manageable subset of them on a day to day basis.
Hundreds of thousands of dollars is on the order of, what, 1 engineer-year?
For example, Lisp has a simple syntax, but most people would consider infix math notation easier, although more complex.
In fact Kotlin looks mostly like Java with some additions to make everyone's lives easier (closures, extension methods, data classes).
Every language takes influences from others, if that's what you meant. Scala is influenced by Java, C# and Haskell, in that order. Kotlin is influenced by Scala and Java, etc.
The "superset" and "Lisp, Haskell and Javascript in the same compiler" comments are unhinged from the reality of any language I recognise.
For me and I think most other Scala devs Scala is a statically typed FP-OO language. So Haskell doesn't do it justice because Haskells insistence on purity makes it impractical for me in getting stuff done. And Java doesn't do it justice because Java is held back by its history. "Superset of" makes it sounds like a weakness and overwrought. In my experience it offers a sweat spot of the best features of static FP and OO.
So what about your mention of Lisp and Javascript? Unless you're deep in some framework you don't need to know about the support for macros and structural typing. I've ignored those two so far because I haven't needed them (yet?). And I haven't felt they were in my way.
So where you say "a superset of Haskell, Lisp, Javascript and Java" I say "the sweet spot of the best features of static FP and OO for the real world. Leveraging the JVM ecosystem".
I know this will sound snarky, but I have to ask: have you tried haskell before? I only ever hear that line of reasoning from people who have never used it (and I was once one of them, using that very same reasoning to choose a multi-paradigm language). We bailed on scala for haskell precisely because it is pure and has a better type system.
You can't say that Erik Meijer doesn't know Haskell. :-)
From the sound of it this is his first job in the "real world"? If that's the case, perhaps he just hasn't seen patterns of applying his current functional knowledge in a way thats better than the best practices from the imperative realm.
How do we know after a few years he won't switch (provided he was a fundamentalist functional programmer) back to saying "now that I have a better understanding of 'The real world' I can see patterns applied with the functional paradigm are better than the best practices I've been using from the imperative paradigm."?
I believe this is the reason to keep an ear open for authority figures, but not to take everything they say empirically, especially when it's in contradiction with a position they've held much longer.
Apologies for the rambling, I was just typing out what came to mind.
Nor is that even, I think, what I think Meijer favors. Meijir's position, from what I've seen from him in various contexts, seems to be that there are cases in real world software where the most clear expression of intent uses imperative constructs, and its better to use them -- but understand and contain their dangers -- in those cases rather than trying to avoid out of devotion to purity.
> From the sound of it this is his first job in the "real world"?
Well, if you don't count the 13 or so years at Microsoft as being "real world".I don't think he ever was a fundamentalist anything.
> I believe this is the reason to keep an ear open for authority figures, but not to take everything they say empirically
"Empirically"? Are you meaning something like "uncritically"? Because "empirically" doesn't have any meaning that makes sense in this sentence.
That's true. But I can say that he is quite happy to tailor his message to his audience, If you listen to what he is saying, he is making the argument for haskell. He is just wording it for the PHP crowd. Haskell does allow side effects, which is entirely the point. But the "unwashed masses" as it were are under the misconception that it does not. So he has to take the "side effects are awesome" sales pitch, and kinda tosses haskell under the bus in the process. Unfortunate, and ironic given that haskell programmers genuinely feel that side effects are awesome, but what can you do?
If you think scala is a superset of those, then you either really don't know scala at all, or you have an incredibly low opinion of all the languages you listed.
The main downside of Groovy is: it's not as fast. And of course the programming paradigm is less revolutionary and more pragmatic, though that could also be a big upside.
https://news.ycombinator.com/item?id=6836632
I was in an odd position of having picked up 4GL and MUMPS via odd random ways when I was 19/20 -- so when everyone who used to maintain those systems vanished, I was around to step in and bill like crazy for helping them port OFF those systems onto more modern tech. Every port a MUMPS app to Erlang... I have!
These systems are VERY different that what you are most likely used too, so having face time with them is really important.
Wow - that sounds like an article I'd read!
Just curious, what are the some languages/platforms you like or enjoy using? (Mine are Python, Erlang and Go for ex).
Shipping code: Go, Erlang, C++11 (avoiding legacy), F# (with Xamarin)
I program in many more, but those are probably my top 8 right now.
But in reality, when I need quick scripting, I mostly use ZSH.
That said, I do prefer JRuby to Scala.
Also, I think you exaggerate the 'Scala is bad because DSLs' point. There are indeed a lot of libraries which overuse symbols but you are not obligated to use them. I have found the Scala I've written and read personally to be both concise and readable.
And, Scala isn't the first or the last to 'reach for the expressivity goal'. See: Haskell, Scheme, F#, & ML.
I think he meant the language that lawyers might use amongst themselves. Legalese is actually fairly low level. It's like a fully type annotated version of English that redefines all library functions each time.
There's this joke about how a Haskell programmer's style on a hello world programme evolves with experience, starting from a very readable, sort of down to earth implementation, and turning out in its last iteration into a complex "mess" of abstract concepts, for sensibly the same result.
It's always possible to keep things simple, even in Scala, and the opposite is also true with a language known as simple, Java, because the type system happens to be quite powerful actually. People are tempted to make things complicated also because there is this prevalent programming style in the community.
The FP model gives good tools to enable that, and encourage people to think that way.
I may also be biased because I feel more confortable thinking that way. Certainly programmers excelling at imperative programming might disagree, but I don't think that the latest trends of "functionalizing" Java, C++ or PHP are coincidental. Javascript opened the way by bringing back that paradigm to a larger audience, and these languages, which already have FP concepts available, but not in a very usable way, are now incorporating them to the core. That's a good thing.
Regarding the original topic, Scala is very much an experiental language in my opinion (because of the concepts it involves; the implementation is pretty good), so maybe there's a little bit of thruth in the article in that regard. Perhaps that's the "flaw" of academic languages. Also the comparison with Java is quite pertinent, Java being a language designed from the ground up for engineering: the grammar is fairly simple, which provided a somewhat good compromise between high readability (because of its similarities with C) and easiness at machine processing (not as easy as lisps dialect though).
I've been working with Scala full-time for the past 2 years. Prior to that I worked with Perl, Python and Ruby and I still work with these languages for quick scripting or if the codebase demands it.
Scala code-bases tend to be based to a higher degree on good engineering practices. Scala itself is a much more static language than a language like Java, hence it gives you plenty of compile-time safety, with its static type system being one that helps you, instead of staying in your way. Even a tricky feature (now market as experimental SIP-18 and so they have to be explicitly enabled), like implicit conversions, is far more safer than the monkey patching that goes on in Ruby/Python, as it's lexically scoped, doesn't modify anything and the compiler throws errors if there are conflicts.
1. Lack of documentation
2. Breaking backwards compatibility
3. Opaque error messages
4. Encourages ad-hoc syntax that makes sense to one person (or team) but does not to the next -- maintenance nightmare.
5. Lack of general stability in language and libraries serving to confuse the eco-system.
Hmmm....
Again, in my experience, the documentation in Scala land is very good. The standard library has a really good API documentation, also checkout the documentation project at http://docs.scala-lang.org/ plus there are several very good books available; then there are the libraries in Scala's ecosystem, like Play2, or Akka, or Slick for example that do have good documentation. The online documentation for Play2 does not match the online documentation for Ruby on Rails or Django, but it's newer and it's improving and I remember a time when Rails was several years old and lacked online documentation. I did find undocumented features in Play2's online documentation, but nothing that couldn't be solved with a question on its mailing list. These are open-source libraries, with strong communities that communicate a lot on mailing lists, you know.
The great thing about Scala is that you can also use any Java library you want and wrapping Java libraries in Scala-ish interfaces is actually easy and a great learning experience. I wished you'd be more explicit about this point, because for me I don't feel like there is a lack of documentation.
> 2. Breaking backwards compatibility
This is a point that comes up a lot, but I don't think it's that important for people actually using Scala. Scala is a compiled language, the libraries get distributed / deployed as compiled bytecode packaged up as Jars. This means that breaking compatibility is really easy, as all you have to do is to change an interface, like adding, removing or changing the signature of a method and boom, all code that depends on that interface needs to be recompiled, even for code that's not using the method in question. Dynamic languages that get interpreted or compiled on-the-fly, like Python or Ruby, are distributed as source-code. So by their nature don't have this disability.
The alternative to breaking backwards compatibility in Scala is to freeze the standard library. Personally that's not a compromise I want, because for this very reason Java's standard library is full of idiosyncrasies, broken interfaces, broken behaviour and various other artefacts going back to Java 1.0, that were never fixed in order to preserve backwards compatibility.
Scala has improved a lot though, compared to the 2.8 days. Nowadays you've got a guarantee that minor versions aren't breaking backwards compatibility. Code compiled with Scala 2.10.0 is guaranteed to be compatible with Scala 2.10.3 at least. The next version free to break compatibility with 2.10 is Scala 2.11. The tooling in Scala's ecosystem, like SBT, is also friendly to supporting multiple versions. To compile, test and deploy versions for multiple Scala versions is often just a configuration change, assuming you don't use APIs that aren't available in older Scala versions, in which case the back-ports are hard to accomplish in any language.
> 3. Opaque error messages
That's in the eye of the beholder. Sometimes the error messages are not so good, especially when triggered by the new macro support in Scala 2.10, but you know, those macros are experimental and improving by leaps and bounds. 90% of the time I have no problem understanding the given error messages and many times you get really helpful errors or warnings about code that you think it's correct, but isn't, like when pattern-matching on an ADT and missing a case. And I prefer opaque compile-time error messages to subtle or non-deterministic runtime error messages. In Python I used to suffer from null pointer exceptions all the time. In Scala null pointer exceptions are very rare.
> 4. Encourages ad-hoc syntax that makes sense to one person (or team) but does not to the next -- maintenance nightmare.
This is a thing that gets repeated by people that haven't used Scala, either personally or in ...
I think what I want to say is, Scala is not a mature platform. I believe the language was originally conceived to address the deficiencies of the JAVA language while retaining the versatility of the JVM as a platform.
If you look at the history of JAVA, it was a 'halfway successful attempt to drag C++ programmers towards Lisp'. Clearly this did not work well as it was not a well reasoned effort (syntax, semantics and so on) and went further downhill from the introduction of Generics in 1.5. Scala incorporates all the features of JAVA, adds halfway-to-Haskell-FP, OO-FP, XML-DSLs, some other very funky concepts stretching Generics and then...Macros...and probably stuff from JAVA 8. I humbly submit that this mixture is too much for a reasonable brain to handle. Also in the mix goes the backwards compatibility breakages. How many concepts can you cram into a semantic that in itself is not sound? Is there a standard for the language? Can I implement core Scala in C?
Scala improved a lot from previous proves that point that it is still "improving" i.e. not a mature platform as yet.
Functional programming concepts are not a problem for myself (and I believe any other reasonable programmer) it is the sensory overload of fitting it all into a model: all the language rules that you need to juggle to read a 15 line block of code that can jump between Scala, JAVA, DSL, Generics, operator overloading, etc.
Code written in more powerful languages feels like being harder to read, simply because each line of code does more...hmmm, is this a good thing? Because I have some Perl that you might wanna look at. Succinctness is power, not sensory and mental overload.
If I want the power of OO/FP/DSLs/MACROS all in one bundle, I would prefer a reasonable modern Lisp: coherence and maturity being the deciding factor in that choice.
Maybe Clojure?
Most of the core assumptions here, on which you base your opinion, are not correct.
For instance, Scala removes tons of crazy stuff which plagues Java.
I'm also not sure how one can add Scala's first-class OOP-FP integration as a minus. Have a look at all the other languages which only managed to do that in a lot more terrible way (F#, Java).
Generics as well. Why is the fact that scalac doesn't try and throw obstacles at you when programming with Generics bad? (Have a look at Java or C#, where tons of reasonable code is rejected by the compiler, because those compiler devs were too lazy to implement things properly.)
Same with macros. Have a look at the state of art in Java. It's a terrible mess with various black magic tools and invocations combined with poor IDE and tooling support.
If you can handle Java, I don't see an issue with Scala. Most of the stuff in Java is done in a better, more consistent and better designed way.
> How many concepts can you cram into a semantic that in itself is not sound?
I'm not seeing that at all. Care to explain?
> Scala improved a lot from previous proves that point that it is still "improving" i.e. not a mature platform as yet.
So Java is not mature, too? They are painfully adding mediocre lambda support right now. I'd call a language which was designed with lambdas in mind from the beginning and shipped with them since in 2005 more mature. The language in question is Scala.
> all the language rules that you need to juggle to read a 15 line block of code that can jump between Scala, JAVA, DSL, Generics, operator overloading, etc.
I have never seen that in practice. I often wished code written in other languages would adhere to the standards of code written in Scala. That would make things a lot more readable, maintainable and understandable.
> Is there a standard for the language?
Yes, there is.
> Can I implement core Scala in C?
Yes, why not?
> If I want the power of OO/FP/DSLs/MACROS all in one bundle, I would prefer a reasonable modern Lisp: coherence and maturity being the deciding factor in that choice.
> Maybe Clojure?
Too bad, they are currently trying to add a half-baked static type-system to core. Again, I think a language which shipped with such basic things in mind since 2003 is a lot more mature.
Which ones are not correct? What is the core philosophy of Scala?
>For instance, Scala removes tons of crazy stuff which plagues Java.
If they are removed, how can you claim efficient interop between the two? They are not removed, they are hidden/masked.
> I'm also not sure how one can add Scala's first-class OOP-FP integration as a minus. Have a look at all the other languages which only managed to do that in a lot more terrible way (F#, Java).
Anything the brings C++ inside JAVA is a minus.
>Generics as well. Why is the fact that scalac doesn't try and throw obstacles at you when programming with Generics bad? (Have a look at Java or C#, where tons of reasonable code is rejected by the compiler, because those compiler devs were too lazy to implement things properly.)
Java does not throw "obstacles" its just that the thing was not designed to handle Generics efficiently in the first place. The compiler rejects it because it is not in the spec.
>Same with macros. Have a look at the state of art in Java. It's a terrible mess with various black magic tools and invocations combined with poor IDE and tooling support.
See above, the core language spec does not have any macro facility. So what state of the art are you talking about? If you try to shoehorn it in, of course the result is black magic and poor support. And I am not too sure that macros are a 100% necessity -- Paul Graham advises sparing use of macros in your code. And he is talking about LISP code -- something that has the facility built right in.
>If you can handle Java, I don't see an issue with Scala. Most of the stuff in Java is done in a better, more consistent and better designed way.
For me, consistency means the ability to hold a reasonable model in my head. Java + Generics + OO-FP + Macros + god knows what else is not a reasonable model. Do not mistake complexity for power.
>I'm not seeing that at all. Care to explain? Sure. Take Java syntax: If something is not designed to have a feature why do you want to try to shoehorn complex features in it? Clojure went the other way and completely changed the syntax, not mangling existing Java syntax.
Apply that to anything: the syntax, the compiler, the model, whatever.
>So Java is not mature, too? They are painfully adding mediocre lambda support right now. I'd call a language which was designed with lambdas in mind from the beginning and shipped with them since in 2005 more mature. The language in question is Scala.
I never said Java is not mature. In fact, it bends over backwards to accommodate code written in previous versions. If you want a language with lamdas built in (as an example of one feature) why not choose something that has been in existence for over 30 years, has tons of problems solved in it, was a result of original research first and commercialization later, has had more man hours thrown at its problems and implementation than Scala, etc? Why re-invent the wheel? Why not find a way of greasing the wheel better and applying a nice shine on it to make it attractive to modern programmers?
>I have never seen that in practice. I often wished code written in other languages would adhere to the standards of code written in Scala. That would make things a lot more readable, maintainable and understandable.
So all the people complaining about Scala library code readability are whiners? All code written in Scala is a lot more readable, maintainable and understandable?
Can you please point me to where the Scala specification is? It would have to be stand alone to implement in C, not built on something else. Genuine question. If there is a spec to the language (implying design and thought), why does the language keep on changing and breaking previous versions?
>Too bad, they are currently trying to add a half-baked static type-system to core. Again, I think a language which shipped w...
https://docs.google.com/document/d/1P3BLR31VA8cvLJLfMibSuTdw...
Q.E.D
Get your core model and concepts right, everything else follows.
I can't speak for SBT because I don't use it, but Spray is probably the nicest library for defining HTTP APIs I've ever used, in any language. As for type inference, yes it's imperfect, and maybe disappointing for someone used to Haskell, but coming from Python I found the set of type annotations I needed to add to make my Scala compile was a subset of the ones I wanted to document anyway.
Scala has unicode operators?
Wow.
I agree that it becomes tricky to get an overview of the whole project in C/Java/etc, but I very much disagree that it actually becomes easy to get that high level overview in Scala/Ruby/etc. As soon as the project becomes 'interestingly large' and full of the corner cases that comes with interacting with reality, all languages fall down here. Regardless of the level of the language, you are still communicating with a machine. I'd guess that for a mathematician who has spent most of their lives looking at equations and little time talking to people, a mathematical functional language may seem easier to read than a novel - but for most people this isn't the case.
The best way I've seen to handle this regardless of language is to have the high level overview outside of the code in a human form document describing the reason for components and not just what they are.
This is also why I prefer simpler languages (like Java or C, as you say) - they are very good at specifying exactly what is going on with little room for creativity to confuse things. We use legal contracts for a reason - imagine if our laws were written in poetry? Writing a computer program is much closer to a law than a poem as you need to limit ambiguity as much as possible and specify as many corner cases as possible to prevent undefined behavior. Plus being at a lower level means optimization strategies are easier to see.
There's a reason C/Java/C#/etc are still the most popular languages, imo. The only real outlier being Javascript which gets its popularity from being the only option for the browser.
This is probably the reason for Javascript's popularity, but if you ignore some bad language design, Javascript is a very simple language with a very small number of concepts that you need to understand to start getting work done in it. Even Python (which I think is the simplest of the widely used dynamic languages) has a larger number of concepts that you need to understand than Javascript.
So I don't think Javascript it's an outlier according to your theory, it's very much a simple language, the only remarking features compared to C/Java/C#/etc are the fact that it's dynamic and that some corners of it are badly designed, plus exceptionally badly designed API if you're doing anything in the browser that's not abstracted by a platform library.
Isn't this just a rationalization? Any unexpected behavior is by definition something the user didn't know to expect.
I hear this a lot. JavaScript is great unless you [insert example why JavaScript isn't great]. You could easily turn that statement around: JavaScript sucks, unless you don't [insert example why JavaScript sucks]. It's an empty statement that could apply to almost any development language no matter how objectively 'good' or 'bad' it is.
I don't know Scala, but judging from the (interesting) article it appears that Scala can be perceived as a bad language because it allows you to write obfuscated, hard to read code that hides many details of what's going on in the program. This can be both a good and a bad quality, depending on the kind of program, and the kind of developer. Personally I like languages that aren't too opinionated or restrictive, so I might like Scala. Compare this to JavaScript, which is a bad language for the simple fact that it's downright dangerous to program in looking at all the idiotic, arbitrary corner cases you have to avoid.
You could have a philosophical discussion about the merits of the design choices in Scala, I don't think you could say the same about JavaScript though, it really is popular only by accident.
No, it isn't really contentless.
All really complex systems will have ... well, less than perfect parts. That goes for programming languages in (at least) a subset of their use cases.
You can either live in denial of "cruft" when choosing programming language or accept that you need to enforce a standard of best practices in your group.
Then you evaluate languages with how they works if the best practices are followed. JavaScript's "good parts" -- and bad -- are well documented and discussed, most everyone knows about this subject.
The overhead of designing/teaching and following those "best practices" needs to be factored into the equation too, of course. It might e.g. be too much of a pain for the std library of PHP (example chosen because I don't know PHP enough to have an opinion.)
Look around and see those (depending on how you view them) odd/complex "design patterns" that only exist in JavaScript to emulate missing features.
But when I read production code it was aweful because of all the DSLs.
Scala does much to reduce code to whats necessary, like python, but there is so much more that it does, which confuses the code readability later :\
The DSLs also lead to bad API design.
The devs are always like "uhuuu if you don't like the DSL just use the normal functions" and write the horrible DSL stuff without the DSL.
(asd ~! fdd %%% sdasd) gets to asd.doSomethingRatherComplicated( with( fdd ) ).alsoGetSomeStrange( sdasd.compile() )
It looks like they are using the ability to build "easy" DSLs as excuse for bad API-design.
The next chapter delved deeper into the typing system, and I recoiled in horror.
I still want to do Scala some day just to use their actor messaging, but there really is a very strict limit to how far a sane person can look into Scala. At some point, the Abyss looks into you, and if you're not careful, you'll also start building crazy DSLs with incomprehensible operators based on Type Declarations Man Was Not Meant To Know, just to maintain rigid type safety in some situation nobody really cares about.
I worked on a large C++ project. Most code was written in a very concrete way. This lead to reams of boilerplate code which bothered me a lot. I thought it was difficult to grasp because there was so much code and there was no explanation of concepts. To me concepts are important. Instead I wrote high level but quite abstract code, but with good documentation of concepts I used.
Sadly I noticed people had big problems understanding my code. I tried to analyze why. My best explanation would be that they were not interested in software architecture like me so they could not recognize concepts and patterns as easily. Furthermore they were not used to reading documentation about concepts. They just wanted to look at the code right away. That is what they were used to. But that was hard, because my code was quite abstract.
I have no idea what the solution to this contradiction is.
Take clojure. Both very expressive and very readable.
The problem of Scala is not that it is oh so awesome and expressive. It is in a failed attempt to marry two very complex worlds: OO and FP. Of course the complexity of language explodes on unsuspecting developers.
Scala is a cautionary tale for every language creator out there. Chose carefully what you pack into your language.
There's absolutely no need to create a monstrosity like scala in order to reduce boilerplate. Even such complex language as haskell is much simpler and more readable than scala.
That's the reason both OO and FP camps reject scala. It is OVERENGINEERED.
Solution: author should abandon the JVM ecosystem and use Go.
- Fast compiles.
- Ultra simple, non extensible syntax, yet not verbose in practise.
- The code you see is 100% of the code.
- A culture of implementing the simple algorithm.
- Stable, with version compatibility guarantees.
- Nobody is trying to make the types jump through hoops, so the type inference works.
I'm starting to wonder when, when I mention C++, I'm going to be told that Go will fix all my problems. (Rust might; Go won't.)
Groovy's static typing is quite recent, written by one person only, and not actually used in many codebases. Neither Grails nor Gradle uses it.
There's only really 2 or 3 use cases for Groovy:
* quick & dirty scripts for Java class testing and manip
* Grails
* more recently, Gradle (which still ships with Groovy 1.x)
If you want static typing on the JVM, best use a language designed from the ground up to be staticly typed, e.g. Java, Scala, Kotlin, Ceylon.
Instead, I learned Clojure. I use Ruby, the epitome of comfortable languages, for most things, and when the hard problems come up, I use clojure. My next major scientific computing problem, rare as they are, will be in Julia instead of Matlab for prototyping and java for production. Scala seems to be the hard language for easy problems. No thanks.
The Clojure community has its navel gazing of course, but every time I've been exposed to some crazy idea in that community it was always through the lens of providing real leverage for real problems. Most of the time when I've dealt with people trying to explain concepts to me for Scala code, I've walked away wondering what the point of it all was (beyond the fun Computer Science.)
If you don't want to learn FP or you don't value type-safety, Scala is simply not for you.
Is it actually possible? I've been using Scala for over a year and still have to spend more time learning about the language than writing code in it.
Actually, I spent some time over the weekend trying to get familiar with Scala by using it to solve some Project Euler problems, and it was pretty entertaining. Still, the language's bias towards there being more than one way to do anything does worry me; it does seem that the kind of mutually incomprehensible code bases the OP talks about are likely. I would assume that, like C++, you need a strong style guide for a Scala project laying down which parts of the language you are going to use. Does anyone have any recommendations for guides on writing comprehensible, maintainable Scala?
Scala does have some rough edges but they are not the kind of C++ ones, and even the complexity of the most powerful features (implicits) is very controllable.
Seriously - which features would you like to remove from Scala? I'm really curious because I don't find any redundant ones. All are pretty complementary and very useful.
The most obvious example that comes to mind is whether you should use mix in traits or type classes for api design. Another one is the "magic-ness" of map/flatmap/filter for for comprehensions but no way to extend that for Functor/Monad/Monoid type classes.
Finally, the Scala community is a huge advocate of Algebraic Data Types yet don't support Disjoint types making any sufficiently complex system cumbersome to model as an ADT.
Scala seems to have a huge image problem. I think part of the problem is that Odersky and crew have never written the treatise on how to use Scala's OO and FP effectively. I'm surprised that Typesafe didn't come up with their own web framework instead of using Play.
One lesson to be learned is that these days you need good IDE integration and fast compiles (incremental) for rapid development. But Scala IDE support has come a long ways in the past year or so. The Eclipse Scala worksheets is awesome. I like it better than a standard REPL. Intellij support is still going strong too.
So for someone like me who wants a statically typed language (there goes Ruby, Python JavaScript, Clojure), who thinks Haskell is too academic to be really productive (I have to think too much to get things done with it) and who don't get what is all the rage about Go (perhaps because I'm not a system programmer, in any case I still don't get it, sorry) This leaves me with no other options (except C#, which I would probably use if it was really portable)
Scala is not perfect, but I feel more productive with it than with any other language, if anyone who never used Scala will decide not to even try it because of this article, I wish them luck, but I doubt this will be the case. for those who use it, they will still continue.
So I really don't think I understand what is the point of such an article. Try the language for yourself, if you like it use it, if not, and you have a choice, don't.
p.s. for all those poor bastards who are forced to use Java at work, Scala is by far a gift from the Gods, so it helps to keep things in proportions, one man's source for a rant article, is other's source of means to finish work at 5pm and go back to the SO and kids. (they would go back at 1pm but their Sun Certified Java EE team lead brain will explode if they will use Clojure, with Scala your EJBs or Spring code can still look recognizable, perhaps a bit more pretty) p.s. did I forgot to say I love Scala?
I mistakenly wrote a Java anonymous inner class that called a closed over variable from the outer scope like one would do with Scala closures. Of course the Java compiler threw an error because I didn't mark the variable as final.
When programing in Scala, one never has to deal with such low level rigidness. It just let's you get shit done.
The Scala team does have a plan to fix this though. Of course, if you aren't operating asynchronously or you're only closing over immutable values it doesn't matter anyways.
As an aside, insofar as you have some sort of willingness toward C#, you should check out F#, which is functional with really nice type inference and none of the syntactic woes that I have come to associate with Scala. (Not sure how portable it is, I have heard stories of people using it with Mono, but I haven't tried it myself.)
P.s. I did mention I chose it via elimination, and due to a very subjective preference to typed languages.
Another plus for scala for me is this: I can use it at work.
Though, this could just be me getting more comfortable with the language, knowing where to look, or a combination thereof.
But once haircut fascination is over - people expect you to do mundane tasks, like cook food or take out the garbage. Or they won't pay you.
And then you realize that when Scala cannot do what you want - you can always revert to Java.
And then you realize that you don't really need Scala-ing if you can do the same stuff in Java or any other strongly typed language.
That's the turing completeness fallacy. Why not just write everything in C? And java's types are inadequate for doing really generic methods - how would you go about writing scalaz's "sequence" in java?
Has scala become a readable alternative to java, while most of the future focus is on clojure? Does anyone know how real life performance compares between both.
From my viewpoint, scala is in use at several banks and Twitter - clojure doesn't really have a big name advocate behind it. From a startup standpoint, isn't talent/hiring an issue?
Performance is probably the last thing you need to care about when choosing a programming language for most businesses - unless you are doing hard-core analytics or handling huge scale, you just won't hit the sort of performance problems that are solved by a faster programming language (as opposed to a faster algorithm or architecture).
It really frustrates me that people _still_ put such weight on low level performance. In 1997 I had people saying "don't use Java, it's performance is far worse than C++". It was mostly untrue for business problems then - and computers are many orders of magnitude faster now.
Well-written Scala and Clojure can provide comparable (ie Java level) performance.
Clojure has tools (like core.typed and Prismatic's schema library) to optionally provide you with static typing where you want it, without the burden where you don't need it.
Clojure does regular releases every year (that continue to be high quality and maintain backwards compatibility) and now has paid developers and support that will continue to accelerate progress. Because of the flexibility of the language, a great deal can be done outside the language in libraries (such as the entirely new concurrency paradigm in core.async).
I'd just put any kind of application, whether built in Scala, node.js or Go or ruby on rails behind a nginx proxy and use that for setting the headers. That simplifies a lot of things. I hope your HTTP headers aren't really so dynamic that you need to build software that changes them so much, especially not for a RESTful application.
The last thing you want is to make the deployment harder.