Hacker News new | ask | show | jobs
by mortyseinfeld 4532 days ago
With Scala you feel smart having just got something to work in a beautiful way but when you look around the room to tell your clojure colleague how clever you are, you notice he left 3 hours ago and there is a post-it saying use a Map

So he was making reference to Clojure here. That's fine, but you don't have to make things complicated in Scala if you don't want to.

I love the semantics of Clojure, but until you get some optional typing and possibly another syntax baked in forget about it for a whole class of devs.

3 comments

About this:

"until you get some optional typing"

There is work being done on an optional type system:

https://github.com/clojure/core.typed

There are also some interesting experiments in enforcing specific data structures:

https://github.com/prismatic/schema

Much effort has been made to make contract programming easy in Clojure:

https://github.com/clojure/core.contracts

And if you would feel the urge to respond with something like "why is such important functionality in a library", I'll point out enforcing pre and post conditions (on a function) has a nice syntax that is part of the language:

http://blog.fogus.me/2009/12/21/clojures-pre-and-post/

I find that every time I read an article about Scala I am left wondering "Why don't these people just use Clojure?"

Having made the choice between Clojure and Scala many times, always in favor of Scala, here are the 3 main reasons I keep going back to Scala (even though I don't particularly like it):

1. I like type systems. I want strong typing, I'd prefer stronger typing in Scala (ie purity constraints as type information etc). I don't want optional typing (if I need dynamic interop, I can make a case for opt-out typing, but I've never needed).

2. Performance. I spend a lot of time dealing with performance issues, specifically latency & throughput. I often have to back off of idiomatic Scala to achieve these goals (especially when it comes to GC pressure). Scala makes that easy & painless. Clojure doesn't.

3. Style (purely subjective). I don't like LISP style languages. My very first experience in programming is in Scheme, so it's not that, I just don't like how they look. It's fine for other folks to like them, different strokes and all that, but I don't like it.

There are a ton of things I don't like about Scala, but for me and my projects, right now, if I'm targeting the JVM it is the best choice and Clojure isn't even second.

> 1. I like type systems.

I believe with schema you can get much of the same benefit and even more on top of that.

I think schema will still evolve and work together with core.typed (witch will also evolve) will be a awesome combo.

I generally prefer not having to right the types but putting down some automatically enforced documentation is nice once in a while.

> 2. Performance. I spend a lot of time dealing with performance issues, specifically latency & throughput.

I cant really say on this issue. But I know that the story here really changed and keeps changing. Because of macros we get library's that are where fast but feel easy and simple to use.

Some teams like prismatic, runa and relevance did some pretty performant APIs and used Clojure.

"I often have to back off of idiomatic Scala to achieve these goals (especially when it comes to GC pressure). "

Can you give an example of when you had to do this? I often wonder about the performance costs of chaining together several collection API calls.

Options are the most obvious:

def foo(opt: Option[Bar]) = opt.map(_.toString).getOrElse("")

This non-obviously creates an extra object in the Some case. As opposed to:

if(opt.isDefined) opt.toString else ""

which creates 0. Not a huge deal in this specific case (unless this is a hot call). But this sort of thing is endemic to all of the standard libraries.

Edit -- only 1 extra object, but it is in both the Some & None case (which is sort of the point, it is hard to know with idiomatic Scala)

This is why I'm really happy with the Clojure community. People in Clojure get that types are useful and important. You don't have the "I don't understand that, so I'm going to call it unimportant" attitude. Instead, you have people using Clojure as a lens to explore and, one hopes, solve the problem-- even when it seems so difficult as to be almost infeasible (such as static typing on a Lisp).

Clojure is a dynamically typed, JVM language-- now. (However, ClojureScript is also pretty far along.) It might not always be that way. It will evolve according to the needs of computer science over the next 20+ years.

> even when it seems so difficult as to be almost infeasible

That is quite fun. Lisp had experiments with static types for a long long time. Look at things like Qi and there history.

>With Scala you feel smart having just got something to work in a beautiful way but when you look around the room to tell your clojure colleague how clever you are, you notice he left 3 hours ago and there is a post-it saying use a Map

I don't get this. Scala has a great collections library, including a Map type. What, exactly, is the author complaining about?

His point is that Scala and the Scala community dont just use maps, they always want everything in types and that is why every library does it that way. Its bad practice just to use a map. In Clojure land its the other way around even if we put something in a type (deftype) we right interface to make it look like its not (defrecord).

Its not what is possible, but what is. And the fact is that all the Clojure web framework and library's use the same data structure even if the underlying implementation is different. See how ring uses much of the same thing as the pedestal service.

Yes, and there is a good reason why Scalaland uses types. Consider a Spray-like API using only maps:

    val cookies = Map("sessionid" -> "1234567")
    val headers = Map("Content-Type" -> "application/javascript")

    setCookies(headers) {
      setHeaders(headers) {
        complete { obj }
      }
    }
With Scala's "make everything a different type" approach, that's a compile error - setCookies will expect a List[Cookie], not a List[HttpHeader].

Those of us living in Scalaland are not as smart as the Clojure guys. We make mistakes sometimes and find it handy when the compiler yells at us.

This is actually a good example of something I don't like in Scala. They don't make this sort of differentiation easy enough. Adding a Haskell style newtype would be really, really useful.
Scala has value types.

    case class MyNewType(x: String) extends AnyVal
What do you want to do that that isn't sufficient for?
AnyVal's would probably be sufficient except for the following: - Instantiation of the MyNewType happens all the time and is not obvious from inspection of the code (generics, use as another type if we implement a trait, etc). - If we want to call any of the methods on the wrapped type we have to call directly to the wrapped type violating Demeter. - Verbosity.
Unboxed tagged types to the rescue:

http://etorreborre.blogspot.co.uk/2011/11/practical-uses-for...

Scalaz implements this, so you can use it straight away. We use it mostly to control implicit selection.

Tagged types also have their problems.

1st they don't propagate, call a function on the tagged type and it returns the underlying type.

2nd they aren't type safe against the tagged type, so you can pass tagged types into functions that take the underlying type by default.

3rd in practice my code with tagged types ends up having lots of boilerplate and/or magic code that is hard to understand.

4th there are some pretty heinous compiler bugs that you will encounter with tagged types.

Value classes make tagged types obsolete:

http://docs.scala-lang.org/overviews/core/value-classes.html

> but until you get some optional typing

The schema library form the prismatic guys should be what you want, its pretty powerful.

https://github.com/prismatic/schema

Aria Haghighi - Prismatic's Schema for Server and Client-Side Data Shape Declaration and Validation (http://www.youtube.com/watch?v=o_jtwIs2Ot8&list=PLZdCLR02grL...)

For static type checking: https://github.com/clojure/core.typed

> possibly another syntax baked in

Not needed in my mind. I would rather have less devs then C syntax. Not trying to be elitist but clojure will never not be a lisp, and if somebody can move from a(b) to (a b) then let him do python.