
Clojure vs. Scala - iamtechaddict
http://programming-puzzler.blogspot.se/2013/12/clojure-vs-scala.html
======
lmm
Scala guy here

Suits would surely be case objects rather than classes, or I'd be tempted to
just use a Java enum (Scala could really do with an equivalent). With card
ranks, either you want to be able to compare them - in which case integers are
the correct representation - or they're just 13 "things", in which case again
an enum-like representation is good; I can't imagine why you'd ever want to
represent a card rank as int-or-string.

Case classes are java-serializable by default. Any number of other serializers
(json, database...) exist that work seamlessly with case classes. I do think
it would be nice to have an abstraction for something weaker than a class,
something that was guaranteed to be inert data, but still typed.

And yeah, I might implement a deck as something that contains a sequence. But
I could then derive typeclasses for sequence operations quite cheaply using
lenses. (I do wish there was a nicer way of doing this kind of delegation
though).

Sure, Scala steers you towards making a type straightjacket for yourself; you
definitely can operate on stringly typed or maply typed data, as it sounds
like Clojure encourages you to do all the time. And maybe it's not the best
language for exploratory manipulation of semi-structured data. But when the
time comes to write a production-ready system, the strong types that Scala
gives you are a much faster way to achieve the level of reliability you need
than the level of testing you need in a less typed language.

(And even if you don't need the safety, I find types are a great aid to
figuring out WTF you were doing if you come back to the code in six months'
time)

~~~
profdemarco
> Scala gives you are a much faster way to achieve the level of reliability
> you need than the level of testing you need in a less typed language

I have serious doubts about this since practically everything in the Scala
standard library is horribly broken (collections, views, everything in
scala.io, scala.xml and scala.actors etc.). The number of bugs found by Paul
Phillips alone is absolutely ludicrous.

As it stands now, both Haskell and Clojure have vastly superior libraries,
build systems that actually work, and implementations that people actually
understand and can modify.

~~~
lmm
The scala collections library is the most powerful/flexible I've ever seen in
a strongly typed language; it combines the safety of Haskell with the
flexibility of Clojure. Given the amount of ongoing complaints I see around
cabal I don't think it's fair to say it "actually works" (fwiw I'm very
happily using maven to build my Scala projects, so I never really know what
the sbt fuss is about). And the rate of features and other progress in recent
scala releases clearly demonstrates there are plenty of people who understand
the implementation well enough to modify it.

~~~
profdemarco
> it combines the safety of Haskell with the flexibility of Clojure

Foldable, Traversable, Monoid etc. are all far better abstractions than what
Scala collections provide, and they don't lead to unmanageable inheritance
hierarchies and ridiculous APIs. How many bugs have been caused by that? A few
hundred maybe? Does Set equality work in the current release or is that broken
again? Is it possible to do thread safe efficient merges in immutable
collections yet?

The only thing Scala collections offers that Haskell doesn't is the
CanBuildFrom travesty. At least in Clojure you can chain transformations
together without generating tons of intermediate values. In Scala you're
forced to choose between being ridiculously inefficient or using iterators.

~~~
happy4crazy
Can you expand on the CanBuildFrom travesty?

(It seems like you've got interesting things to say, but you're being a bit
strident. It bums me out that Scala discussions on HN take such a heated
tone.)

~~~
profdemarco
CanBuildFrom is essentially a typeclass in Scala that is used for converting
between collection types. Ignoring the coherency issues associated with using
implicits for typeclasses, it makes the implementation of the collections
library significantly more complicated and causes issues with type inference.

In the rare cases where you actually need to convert between collection types,
it's usually trivial and more efficient to do it manually. Essentially they've
added tons of complexity for negligible benefit. One of my main gripes with
the Scala collections library is that it's overly complex and that this
complexity has been the source of hundreds of bugs.

If there was any real benefit to the way it's currently done they wouldn't be
hiding the true type signature for things like `List.map` in the official
Scaladocs.

~~~
frowaway001
You are kind of either ignoring or not knowing the core use-case of
CanBuildFrom. Why talk about things you don't understand?

~~~
profdemarco
The reasons other than the ones I've outlined are caused by implementation
details and wouldn't exist if they chose the correct abstractions.

~~~
frowaway001
That's wrong.

------
octo_t
So the Scala solution for this is:
[http://ideone.com/Vussjh](http://ideone.com/Vussjh)

    
    
      object Cards {
        sealed trait Suit
        case object Spades extends Suit
        case object Clubs extends Suit
        case object Hearts extends Suit
        case object Diamonds extends Suit
    
        sealed trait Rank
        trait FaceCard extends Rank
    
        case object Jack  extends FaceCard
        case object Queen extends FaceCard
        case object King  extends FaceCard
        case object Ace   extends FaceCard
    
        case class ValueCard(n: Int) extends Rank
    
        case class Card(rank: Rank, suit: Suit)
    
        type Deck = IndexedSeq[Card]
    
        def numberToRank(n: Int): Rank = n match {
          case 1 => Ace
          case x if x <= 10 => ValueCard(x)
          case 11 => Jack
          case 12 => Queen
          case 13 => King
          case 14 => Ace
          case _ => throw new IllegalArgumentException
        }
    
        def numberToSuit(n: Int): Suit = n match {
          case 0 => Spades
          case 1 => Clubs
          case 2 => Hearts
          case 3 => Diamonds
        }
    
        def apply(): Deck = for(rank <- 1 to 13; suit <- 0 to 3) yield Card(numberToRank(rank), numberToSuit(suit))
      }
    

Now I have: normal operations bound to Deck (head, take, drop etc) and the
ability to pattern match on cards. Also strongly typed. This took about 5
minutes top to write.

edit: I'd say the 'numberToRank' parts are probably code smells, but given
that its Christmas Eve, I really can't be bothered to think of a better
solution right now. Implementing ordering etc can be done on the traits very
easily too, but that is game specific (for example are aces high or low, is a
King ranked higher than a Jack etc).

~~~
brudgers
Some things are strongly typed and playing cards are among them. It is just
that playing cards are strongly typed as playing cards, not integers or pairs
of integers.

In blackjack:

    
    
        case 10 => Jack or Queen or King or 10
    

and

    
    
        case Ace => 1 or 11
    

and poker with "Dr Pepper"

    
    
        case 10 => ace or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or jack or queen or king
        case 2 => ace or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or jack or queen or king
        case 4 => ace or 2 or 3 or 4 or 5 or 6 or 7 or 8 or 9 or 10 or jack or queen or king
    

It is sometimes better if the data type provides abstractions over the messy
details of the world rather than adding another one to it and planning for the
possibility of a Joker in the deck might make sense.

~~~
octo_t
Heh, same time as my edit. Those methods should be private (i.e. they just
exist for building the deck, its the consumers responsibility to shuffle /
split into multiple decks etc, as well as assigning value to each card).

~~~
brudgers
So what then does 13=king get me over king=king? And does forgetting to
privatise implementation details suggest that the necessary language idioms
make the data structure complex in a way that is orthogonal to the real world
complexity of the objects it represents, and wasn't the opportunity to avoid
that complexity the advantage suggested by the author. To put it another way,
private and sealed and trait don't reflect characteristics of a deck of
playing cards. They are overhead from the language. It is a case where a
static type system, because it is biased toward it's and strings and objects,
makes it more difficult to reason about our code - leaving jokers aside, how
much of the Scala code makes sense if I want to play Pinnocle versus the data
approach advanced by the author? Now I'll admit that Lisp has shaped the way I
see the two approaches to representing cards. and this may be why I see
implementation of jokers and pinnocle as easy extensions of lists and rather
more complex under an object system with static type checking. But I will
point out that this model got me to thinking about card games rather than card
data types pretty quickly, and card games are probably the reason we're
draining the swamp.

------
adrianm
I think people here are totally missing out on appreciating a very
thoughtfully written post by focusing on the fact that he may be comparing
programs written in his favorite language to your favorite language. He is not
asking for Scala solutions to any problem - and he has not contrived a
deceptive Scala solution to "prove" the superiority of his language of choice.

He's comparing the structure and design of programs between two great
languages of similar capabilities (features) and philosophies. I think his
point about lightweight data modeling is spot on - Clojure is a language that
goes out of its way to make modeling your problems idiomatically painless and
dramatically simpler than most other languages.

It's idiomatic in Clojure to use plain old maps to represent structures or
entities in your program that you would otherwise represent with a class or
equivalent construct in many Object Oriented languages. That isn't a code
smell either - it's idiomatic and wonderful. Keywords (similar to Ruby symbols
in both use and philosophy) are wonderful things that together with maps make
enums as a language primitive irrelevant.

~~~
lispm
It's basically a kind of step back to the Lisp of the 60s and seventies.
Unfortunately I don't think this approach scales well. For example I prefer to
look in a debugger or inspector at an object and not at some other map.

~~~
adrianm
I'm going to be honest - you are coming off as very contrarian for the sake of
being contrarian. You seem to be consistently responding to my comments in
this thread with the equivalent of "You're wrong, because I like to do things
this way."

That isn't an argument against any point I've made. Please show me some code
and give me some context that will make me rethink my assumptions and
arguments if you feel the need to point out my flawed thinking.

~~~
lispm
No, plain maps are nothing more like plain assoc lists (and similar stuff) in
plain old Lisp. We were modelling key/value data structures like that from the
earliest Lisp. Sure its easy to use. Up to a point. Lisp had an evolution.
Things changed. I've seen quite a bit larger Lisp software over the years and
the ones not using explicit classes turned out to be harder to maintain.

------
pixelmonkey
Sounds like idiomatic Clojure has more in common with Python than it does with
Java. I'm finding that to be true as I teach myself Clojure. My background is
an ex-advanced-Java programmer who left that all behind and has built
production systems in Python for the last ~5 years. I'm learning Clojure now
because the Java ecosystem is important to me, but I simply refuse to use Java
to interact with it :)

Lightweight data modeling is important and Java is truly terrible at this. I
illustrated this in a gist about creating and iterating over a list and a map,
and contrasting that to the equivalent Python:
[https://gist.github.com/amontalenti/8114359](https://gist.github.com/amontalenti/8114359)

The author says about Scala: "Due to its highly detailed static type system,
Scala attracts the kind of programmers that like to carefully categorize and
enumerate all the possible data structures."

It turns out, this describes expert Java programmers very well, too -- so it's
no surprise that Scala is a very popular language with Java programmers. I'm
finding that Clojure is the more attractive language if your sensitivities
lean toward the "simplicity" and "dynamism" camp. I was reading some Scala
code being used in production at Twitter and found this marvel:
[https://twitter.com/amontalenti/status/410977749629546496](https://twitter.com/amontalenti/status/410977749629546496)
\-- you would simply never see anything like this in Clojure or Python
codebases.

The point about multi-paradigm is interesting. It's very true that Clojure,
unlike Python, does not support true multi-paradigm. Then again, Python does
not support "true" functional programming. It's close, but no cigar, due to
the lack of full-featured lambdas / blocks. If you have to pick one paradigm,
functional is definitely the simpler and more essential one.

Illustration: imagine a variant of Python that forced all code to live in
classes -- ick. But imagine a variant of Python without classes -- that's not
so bad.

It's worth reading about Clojure's take on object-orientation-atop-functional
using multimethods and hierarchies:
[http://clojure.org/multimethods](http://clojure.org/multimethods)

~~~
adrianm
Great points all around.

I'll add one thing to your point - multimethods are a fantastic example of how
Clojure allows you to structure programs in functional way that takes a
programming feature (in this case polymorphic method dispatch based on the
arguments at runtime) to the nth degree.

In Java and many other languages that have polymorphic method dispatch - the
dispatch value is usually the type of the object for whom the method is being
called on. Functional languages like Haskell take a much more powerful and
expressive approach to this and extend it to matching the dispatch values for
the called function on the type or pattern matched value of any argument.

Multimethods are essentially Clojure's take on this in a dynamic language.
They allow the programmer to define a function that constructs the dispatch
value however it wants - usually from the arguments given as input, in any
order, on any condition.

To illustrate, I'll give an example I showed my wife yesterday. She's writing
a roguelike game in ClojureScript at the moment that you can play in the
browser - naturally she needed a way to represent the game world and the
players position as they move around.

So, for illustration I'll omit the code for the world state, but she needed to
bind event listeners for the keyboard to properly dispatch the proper movement
logic. So the code she wrote looked like this:

[https://gist.github.com/aamedina/8114944](https://gist.github.com/aamedina/8114944)

She came to me with this code with the following problem - how do I think she
should organize it? Clearly the handling logic is going to be more complex
than a single line per direction (:up, :down, :left, :right) could handle, she
has to account for terrain differences, buildings, monsters, what have you.

So I suggested using multimethods to accomplish this. This is what the
multimethod solution I cooked up would look like in this case.

[https://gist.github.com/aamedina/8114949](https://gist.github.com/aamedina/8114949)

Now she has room in those multimethods to handle the potentially complex logic
needed to make those arrow keys move the character properly. But another
effect of this is that it hides the underlying state mutation from the
implementation.

Now your move functions are pure and isolated from the coords atom, in
addition to the fact that multimethods made the logic more organized, at the
expense of a few more lines of code.

edit: moved code to gist

~~~
abengoam
In my experience mulltimethods get you a long way when writing Clojure code.
My projects use them often and add two or three macros. That is normally the
only "overhead" I have to impose over regular functions.

That said, in the example you posted I don't think you are using all the power
of the multimethods, because you did not replace the case statement. You went
from a case statement to a multimethod+a case statement. In this case, why not
let the mutimethod dispatching to do all the routing/case functionality for
you? Just use (.-keyCode e) as your dispatch function and use the different
values of KeyCodes.XXX for each implementation of the multimethod. And you can
even add a :default implementation that leaves the coords untouched.

In my experience the natural use of multimethods arise when you can choose the
dispatch function for an element based on either some piece of data from the
element or a computed value derived fron the element. But if you have to rely
on case/cond/if statements the value of the multimetod is lessened, as you
still have to touch your dispatch function when your hierarchy of values
change.

edit:typos in the code

~~~
adrianm
Very good point. This was an artifact of the way my wife originally structured
the function (dispatching on the keywords :up, :down, :left, :right), and I
just kept that.

------
hythloday
I actually had something similar a couple of weeks ago. My initial model was
just:

    
    
      val cards = for {
        rank <- 'a, '2, [...], 'j, 'q, 'k
        suit <- 'h, 'c, 'd, 's
      } yield (rank, suit)
      val deck = scala.util.Random.shuffle(cards)
    

which gives you something to play with to validate your model. It's not an api
I'd choose to publish, of course, there are many better type-safe ones written
here, though I'm sad none of them have used Unicode for suits (I know someone
working on a dating app who used a method called ❤ to compare two users: so
something like "if (sappho ❤ rhodopis > 95) { ... }")

But my point is that Scala gives you the option, and is tolerant, of working
in this slightly dirty way, and then lets you clean it up (and a type-safe
compiler will flag up where you are using your old api). I don't know clojure
well enough, so, what's the similar workflow there?

~~~
ellicottvilleny
So some developers will love type-systems, and some will prefer to stay in
Lisp-land forever. :-) The OP seems to be a lisp hacker at heart, and Clojure
is the batteries-included Lisp du "jure". (sic)

------
Shamanmuni
The article starts saying that Scala gives you lots of options while Clojure
guides you to a certain style, but the Scala example takes the most
complicated solution as if every programmer would solve it that way. He's
contradicting himself.

Scala can solve it in a way quite similar to Clojure. The author is trying to
hammer a point about Clojure which doesn't emerge from the example, as most
Scala programmers can notice.

It would have been great if he had listed all the possible solutions and told
us "Scala lets you solve it in all these very different ways without the
language guiding you, Clojure guides you to the simpler solution". That's a
fair point, and one Scala programmers will tend to agree with.

~~~
disputin
Agreed, any problem may be better solved by one or the other. What I notice,
having never used Clojure, is that the Clojure devs may well finish the
implementation while the Scala devs are still discussing the design. Of
course, that level of flexibility will better suit some problems. I read a
high profile project's coding guidelines recently: "Scala is a very flexible
language. Use restraint." Perl's TMTOWTDI is the reason I moved to Python.
I've recently been using Go instead of Scala, partly again because TMTOWTDI,
whereas Go is supremely clean, but also, I think, Scala is just too big for my
needs, a skyscraper when I need a house. This sounds a bit like sql vs nosql,
rather than when should I use x vs y. I look forward to trying Clojure.

~~~
lmm
Have you considered F# (or Ocaml), or Haskell? I can see good reasons to move
away from Scala, but I don't think you need to throw away all that wonderful
functional typing goodness.

------
dzderic
The example cited here is insulting to everyone's intelligence:

    
    
      The possibility of representing face cards with a name would likely never occur to you, because it would be too complicated to go through the effort of defining the type of a rank to be a "integer or a class comprised of four case classes -- jack,queen,king,ace".
    

I'm sure every competent Scala developer will see that the equivalent in
Clojure can be done with _val King = 13; val Queen = 12; ..._ , which also
means you get ordering for free as you're not mixing ints and keywords.

I do agree with the author's point that Clojure almost forces you to adopt a
simpler design, but I feel that long-term maintainability requires a delicate
balance of simplicity and structure that can be achieved with Scala, but takes
more self-control with Clojure.

~~~
JeanPierre
Using _val King = 13; val Queen = 12;_ in Scala is not equivalent with using
Clojure keywords, as their printed variant will be 13 and 12, not :king and
:queen. Reading debugging output or logs would force you to manually convert
those values.

Ordering for free is valuable, I guess, but it sort of depends on the
situation. Sometimes face cards are worth 10, other times they are worth 11,
12, 13. If you use _val King = 10;_ , then it suddenly is impossible to
distinguish between face cards and tens.

~~~
anonymoushn
Right, if you wanted to have an ordering around, you would use an enum. The
enum's values would print as Ace, 2, 3, 4, ..., Jack, Queen, King, and then
when you wanted to implement a particular game the game could define the
mapping from rank -> set of possible values. You wouldn't want to map each
rank to a single value, since in commonly played games aces are worth both 1
and 11 or both 1 and 14.

If you didn't want the ordering (or the compiler warning when your blackjack
implementation omits queens), you could use Scala's symbols, which are more or
less the same as Clojure's keywords:

    
    
      scala> 'king
      res0: Symbol = 'king

~~~
drewhk
Or use value classes and get the best of both worlds.

------
wiremine
Scala feels like the Perl of the modern era: there is more than one way to do
it. There is value in that mode of thinking, and Perl is a better language
than people give it credit for.

However, I think there's a reason Python and Ruby have overtaken Perl in the
interpreted language space: Python values simpler solutions [1]. Ruby also
values a certain type of beauty over Perl.

Clojure/Scala is a similar dichotomy. Scala has everything you might need,
while Clojure is rooted in the spartan power lisp provides.

Also, I wonder: if they weren't both JVM languages, would we even be having
this type of discussion? I mean, we aren't comparing Clojure to Cobra or D.

[1] See the Zen of Python
[http://www.python.org/dev/peps/pep-0020/](http://www.python.org/dev/peps/pep-0020/)

~~~
necrobrit
Back in my uni days, aka not that long ago, the scala (which I love)/perl
(which I hate) comparison is what made me realise that language arguments are
almost always pointless. Any choice you make in a certain class of language is
probably going to be roughly equal in terms of ease of use, productivity,
whatever; so you might as well just go with what you are comfortable with.

~~~
lmm
I also love scala and hate perl. I wonder how close the correlation actually
is - do the same type of people really like both, or is this just something
people who don't like scala say?

~~~
prakashk
I am not as fluent in Scala as I am in Perl, but I do like both. Perhaps, I am
an exception.

------
anonymoushn

      type Card = (Any, Any)
      type Deck = Seq[Card]
      val foo: Deck = Seq((4, 'clubs), ('king, 'diamonds))
    

It seems to work over here. I would have to be a bit out of my mind to
actually want to write code this way, though.

As to the "Lightweight data modeling" pitch, there's a pretty large number of
other languages that are better suited to this because they have TCO (when run
on their main platforms, the analogues of the Sun JVM) and don't require you
to debug apparently-endless stack traces in a different language when your
completely untyped exploration/prototype inevitably explodes.

------
hrjet
Looks like a slow news day.

A dynamically typed language is _obviously_ easier to begin coding in,
especially with a trivial example. The problems that statically typed language
solve are usually found in larger code bases and in performance critical
applications.

~~~
brandonbloom
There is an orthogonal Clojure/Scala axis of interest for code bases of
appreciating size: Mutability.

Clojure programmers choose immutability by default. Scala, however, makes it
just as easy to write "var" as it is to write "val", and just as easy to
create a mutable collection as it is to create an immutable one.

In my experience, this is far more important for larger code bases than static
typing. Luckily, Scala offers immutability as a feature, which is more than
can be said about Java/C++/Go/etc.

~~~
wpietri
Interesting! I suppose var and val are as easy to type, but in Scala my mental
default is always val; var is a smell to me. Isn't that the case for most
people writing in Scala?

------
dragonwriter
> On the other hand, in Scala, you'd be more likely to create a card Class
> with a rank and suit field.

No, if I was trying to do something intended to be generic, I'd be tempted to
start out with this definition of Card:

    
    
      trait Card
    

Scala makes it cheap to use descriptive type names while starting out making
minimal assumptions. This helps avoid making too many assumptions up front,
like the whole model-cards-as-ints one.

> For modeling the deck, you probably wouldn't say a Deck is-a sequence,
> because composition is favored over inheritance.

"X is favored over Y" does not mean "never use Y". And, in Scala, "favor
composition over inheritance" mostly strongly applies when you are talking
about classes, particular classes as the thing being either composed or
inherited from.

I'd probably say something like:

    
    
      trait Deck[C<:Card] extends Seq[C] {
        ...whatever special behavior Decks need to support in general...
      }

------
lukev
I find it interesting that there are about 50 comments in this thread
discussing the best/better ways to model the problem in Scala, and no
controversy at all about the Clojure implementation.

That's a feature of Clojure, IMO.

------
kailuowang
I am not sure I would agree that the deck example he gave represents the Scala
idiom. I myself would probably start with something like

========================

object Cards {

type Deck = Seq[Card]

case class Card(r:Rank, s:Suite)

type Rank = Int

sealed trait Suite

case object Spade extends Suite

case object Heart extends Suite

case object Diamond extends Suite

case object Club extends Suite

}

==================================

Granted, all this code is unnecessary in Clojure but there are two benefits of
writing them:

1) compilation type check

2) for developers who have no context of playing cards, this provides a
clearer picture, while in the Clojure code they will have to browse more code
to get the full picture of the data domain.

~~~
wpietri
I think that last part can be especially important.

I'm perfectly comfortable with both approaches, but as things get bigger, I
value explicit structure more than convenience. When I'm dealing with implicit
structure, I definitely notice the increased cognitive load.

That's fine for something small, short-lived, and personal. But if I'm doing
something large, long-lived, and shared across many people, I think implicit
structure gets more and more dangerous. It's hard to keep everybody's mental
models aligned over time, which makes it easy to end up with a code base whose
coherency declines.

------
jaxytee
After modeling Clojure's Card Deck as a simple sequence of maps, the author
models Scala's card deck in an overly complex way using a Deck Class with a
nested card class, and each card nesting four distinct case classes to
represent suit (Yikes!). The author defends the terrible Scala design by
writing:

> Sure, you could eschew objects in Scala and mimic Clojure by using generic
> maps/vectors/lists/sets for all your structured data needs, but that's
> clearly not how Scala is meant to be used.

Scala isn't "meant to be used" any way. Scala is a lots of things (often times
to its detriment) but opinionated is not one. The author even alludes to this
early in the post:

> Ten years ago, I would have said that my ideal dream language is one that
> provides the flexibility to program in any style. I want to be able to
> choose object-oriented or functional, immutable or mutable, high-level
> abstractions or low-level speed. With respect to this ideal, Scala clearly
> wins, supporting more programming styles than Clojure.

Classic fanboyism, as the author purposely created a shitty Scala example. I
would advise that someone investigating functional languages on the JVM take
this post with a grain of salt.

~~~
mortyseinfeld
Not surprised by this comment. Scala has the most bitter community I've ever
seen. Contrast that to the Clojure community

~~~
jaxytee
Why would you paint an entire programming community as bitter? That is
extremely close minded.

The author clearly contradicted themself. Did you read the article before
downvoting? Also why invoke a false duality like someone being part of the
Scala or Clojure community is mutually exclusive? For what its worth, I have
used and am a fan of both languages. That won't stop me from pointing out a
flawed post though.

------
edoloughlin
_Well, imagine if you could represent all your data as JSON, rather than a
complex hierarchy of objects and methods, and the language was designed around
making that kind of data super-easy to work with._

Then imagine that you could represent your code as JSON and also that a
database existed that let you store and build queries on JSON directly (i.e.,
Datomic).

~~~
octo_t
Come back to me when there's a standard for JSON schemas so my data can be
actually strongly-typed + verified.

~~~
edoloughlin
JSON was used in the original article as a placeholder for Clojure forms. You
can (optionally) get strong typing using Clojure records[1] (see defrecord) or
using core.typed[2]. Datomic also lets you specify types[3].

I'm not "coming back" to you, as I don't appreciate your snarky, know-it-all
tone. I'm replying for the benefit of others reading who may not be familiar
with Clojure.

[1] [http://clojure.org/datatypes](http://clojure.org/datatypes)

[2]
[https://github.com/clojure/core.typed](https://github.com/clojure/core.typed)

[3] [http://docs.datomic.com/schema.html](http://docs.datomic.com/schema.html)

~~~
Ygg2
I think the parent is saying basically: Greenspun's eleventh rule

    
    
       Any sufficiently complex Lisp implementation contains 
       an ad hoc, informally-specified, bug-ridden, slow 
       implementation of half of Haskell's type system.

------
pron
I actually think that Clojure's relatively unique feature which differentiates
it from most languages (other than, perhaps, Erlang and Haskell) is its
emphasis on managing state, especially in the face of concurrency.

~~~
donjigweed
Sort of. But I don't think most people are actually using the concurrency
primitives in Clojure all that much. How many systems out there that people
are writing make heavy, or even significant, use of concurrency primitives?
I'd guess it's definitely the minority.

Immutability and programming with data structure literals are what Clojure's
all about. Lisp, dynamic, and functional are obviously the other big choices
that were made to achieve the overarching goal of the language -
simplification. But imo, programming with performant, immutable persistent
data structures is the essence of Clojure programming.

~~~
adrianm
I agree that immutability is central to Clojure and the resulting code
definitely reflects that. But managing state, as the OP put it, truly is what
Clojure is all about - and immutability falls out of that very deliberate
design decision.

Let's not confuse the lack of significant STM transactions with refs and its
irk with representing the totality of Clojure's concurrency story. Many
Clojure libraries make use of atoms, agents, and dynamic scope (which is
arguably a concurrency primitive, given the thread locality of the bindings,
but not unique to Clojure).

While "concurrency is not parallelism", parallelism is a special case of
concurrent programs that is often challenging. Clojure's offerings here too
are compelling - we have the amazing Reducers library which allows you to
write higher order functions for collections that, as Rich Hickey put it,
"know how to reduce themselves" \- and get parallelism (without locks, without
even thinking about it really) on top of that.

And then there's the lazy parallel functions - pmap, pcalls, pvalues. Check
them out if you haven't. I use Clojure often in a machine learning context
with Hadoop/Storm, these abstractions are highly valuable in crafting
solutions.

Futures/promises are also widely used in Clojure.

I'm confused as to why you think data structure literals are part of Clojure's
core thesis. Perhaps I just don't understand what mean - are you saying that
the fact that the Lisp reader can read strings as data structures as being
part of what Clojure is about? If so, that statement would apply to all Lisps,
not just Clojure.

~~~
donjigweed
>I'm confused as to why you think data structure literals are part of
Clojure's core thesis.

I use refs, atoms, and agents very sparingly. You just don't need them very
much when you have a suite of performant, immutable data structures (with
literals). These data structures, and the assortment of polymorphic functions
provided in the language to operate on them, imo are the crux of the language.
They dominate the experience of the programmer. As far as managing state goes,
they make it so that you rarely have to reach for the explicit constructs
listed above.

------
mcguire
If object-oriented programmers (here represented by Scala-ites) are
excessively fond of modelling the crap out of stuff, to the detriment of the
code they're trying to write, there is also a problem with the opposite,
"lightweight data modelling" approach: a weird fascination with
representations of data, instead of the structure of it.

Here's an example from _Land of Lisp_ :

    
    
        (defun limit-tree-depth (tree depth)
          (list (car tree) 
                (cadr tree) 
                (if (zerop depth)
                    (lazy-nil)
                    (lazy-mapcar (lambda (move)
                                    (list (car move) 
                                          (limit-tree-depth (cadr move) (1- depth))))
                                 (caddr tree)))))
    

and here's the version that I re-wrote, using your friend and mine, defstruct:

    
    
        (defun limit-tree-depth (tree depth)
          (labels ((limit-depth-move (move)
                     (let* ((next-tree (limit-tree-depth (get-tree move) (1- depth))))
                       (if (passing-move-p move)
                           (make-passing-move :tree next-tree)
                           (make-attacking-move :src (attacking-move-src move)
                                                :dst (attacking-move-dst move)
                                                :tree next-tree)))))
            (make-tree-node :player (tree-node-player tree)
                            :board (tree-node-board tree)
                            :moves (if (zerop depth)
                                       (lazy-nil)
                                       (lazy-mapcar #'limit-depth-move
                                                    (tree-node-moves tree))))))
    

I submit that the second may be preferable, even if it is a bit more verbose.

~~~
lispm
agreed

------
vorg
> All or nearly all of the functional aspects of Clojure have counterparts in
> Scala. On top of that, Scala provides [...]

Scala doesn't provide the syntactic macros, or the same simpler approach to
concurrency.

~~~
eugene_burmako
Scala macros are different. We deeply respect the Lisp tradition, in which we
are rooted, but we also accommodate and empower our language's values - static
types and rich syntax [1]. The end result is admittedly less flexible, but it
also opens a number of interesting possibilities beyond those available in
Lisp [2]. Our design is also not set in stone, and we're experimenting with
different macro flavors [3], but it's too early to say something definitive
about those.

[1]
[http://scalamacros.org/paperstalks/2013-09-19-PhilosophyOfSc...](http://scalamacros.org/paperstalks/2013-09-19-PhilosophyOfScalaMacros.pdf)

[2]
[http://scalamacros.org/paperstalks/2013-12-02-WhatAreMacrosG...](http://scalamacros.org/paperstalks/2013-12-02-WhatAreMacrosGoodFor.pdf)

[3] [http://docs.scala-
lang.org/overviews/macros/annotations.html](http://docs.scala-
lang.org/overviews/macros/annotations.html)

------
vorg
There seem to be 4 primary programming paradigms available on the JVM...

Clojure - concurrency (immutable by default), macros (lisp-style)

Scala - object/functional fusion, lazy evaluation

Ruby dialect (JRuby or Groovy) - "methodMissing" meta-object protocol

Java - low-level OOP (but functional lambdas and lazy streams coming in Java
8)

COMING SOON: Javascript (Rhino or Nashorn) - functional with prototype-style
OOP

~~~
chongli
Clojure uses a lot of lazy evaluation in its collections library. Does that
count?

~~~
vorg
Yes, I just listed the features of Clojure that weren't available in any other
production-ready JVM language.

------
jds375
So it seems sometimes that being 'forced' to adhere to lightweight data
structures and functional methods makes all the difference. I'd tend to agree
with you, as I have noticed that it is hard to avoid OO and imperative
techniques when I have that option.

------
kvtrew76557
Perhaps I'm missing something about Clojure, but it looks completely and
utterly foreign. As someone who didn't have much trouble learning a "complex"
language like Scala I find Clojure really hard to fathom.

~~~
code_duck
Have you learned other Lisp-like languages before? Lisp exists truly in its
own realm, syntax wise.

My experience so far is Logo when I was 6 and reading Godel, Escher, Bach, but
I was thinking yesterday of investigating Clojure and that's my task for
today. I'll check back.

~~~
vorg
> Lisp exists truly in its own realm, syntax wise.

It's fairly easy to put another syntax atop Clojure if you want, though in my
experience the net effect is to _restrict_ what Clojure can do, beginning with
disallowing macros.

~~~
code_duck
I'm looking forward to embracing its lispiness.

------
laureny
It seems to me what he calls "lighweight data modeling" is a synonym for
"untyped data". Use ints, strings, arrays and maps to model everything (his
JSON example).

It's great for prototyping but when you start getting big, you really need to
tighten these models down to real types.

------
smrtinsert
Why vs? What a false choice, I love both of them.

------
Touche
There is no language I love more than Clojure but I would never describe it as
"lightweight" (as I wait 5-10 seconds for lein repl to load).

------
mortyseinfeld
Despite the "kumbaya, we're functional brothers...we all win", I know for fact
(very reliable sources) that the Typesafe guys absolutely hate the traction
that Clojure is getting, especially that they need to get a ROI on their
funding.

