9 ms·
Clojure vs. Scala
- lmm 13y agoScala 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 13y ago> 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.
- deleted 13y ago[deleted]
- deleted 13y ago[deleted]
- octo_t 13y agoHow are collections broken? Views are deprecated/set to be deprecated, I don't really use scala.io, I find java io sufficient for my needs, scala.xml is being split out in 2.11 and macros will let people use a third party implementation, scala.actors is also deprecated, having been replaced by Akka. Paul has definitely found a lot of "bugs", he has certainly contributed a huge amount to the cleanliness of the code base, and has been a big pusher for removing certain levels of unsoundness in the type system, but if you were looking for bug-finders + fixers, Simon Ochsenreither is probably a better bet.
- Hakeashar 13y agoJust a quick question - if the views are set to be deprecated, what would be the way to do a (long) series of collection transformation without spawning multiple intermediate collections? So, essentially, equivalent of .view, transformations, .force?
- profdemarco 13y agoYou use an iterator, which has its own caveats, or you simply accept that chaining collection transformations is going to be ridiculously inefficient.
- deleted 13y ago[deleted]
- lmm 13y agoThe 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.
- brudgers 13y agoI can't imagine why you'd ever want to represent a card rank as int-or-string. I think this illustrates the author's point that languages structure our thinking. The value of a King as 13 and the Queen as 12 is determined by the rules of the card game, not the number of elements displayed on its face as is the case for the non-face cards - e.g. the face cards all have a value of 10 in blackjack. Some languages better allow for the messy details of the world and allow the programmer to treat the partial and occasional isomorphism between names of and the values assigned to cards in a particular context uncomplected. None of which is to say that strong static typing does not offer a particular set of advantages, only to suggest that it can become forced at a certain level of abstraction where real world objects are represented without a specific context for interpretation. Imagine a program which begins by asking, "Which game do you want to play?" and includes a card guessing game, blackjack, Uno!, go fish, and crazy eights. We want the values of the cards to lie in their use within each game, not where we shuffle and deal and discard from hands.
- lmm 13y ago> Imagine a program which begins by asking, "Which game do you want to play?" and includes a card guessing game, blackjack, Uno!, go fish, and crazy eights. We want the values of the cards to lie in their use within each game, not where we shuffle and deal and discard from hands. I maintain that you gain nothing (except the possibility of errors) by representing the cards as int-or-string here. Think about how you'd actually use the cards in implementing those games. With my enum-like scala representation you could do anything you could do with the clojure version, and you'd get the advantage of e.g. compiler warnings if you defined incomplete match/case statements.
- reginaldjcooper 13y agoI am having an incredibly difficult time understanding why int-or-string cards are desirable also. You'd end up with multiple functions like heartsGameCardValue and euchreGameCardValue but with int cards you need to write the same thing and without a type system to catch errors. If it was truly simpler to reason in terms of int, you could also do a cardIntegerRepresentation function and it would add very little length to the codebase.
- jds375 13y agoSo 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.
- dzderic 13y agoThe 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 13y agoUsing 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 13y agoRight, 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 13y agoOr use value classes and get the best of both worlds.
- anonymoushn 13y agotype 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.
- Shamanmuni 13y agoThe 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 13y agoAgreed, 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 13y agoHave 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.
- vorg 13y ago> 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 13y agoScala 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-PhilosophyOfScalaMacros.pdf http://scalamacros.org/paperstalks/2013-09-19-PhilosophyOfSc... [2] http://scalamacros.org/paperstalks/2013-12-02-WhatAreMacrosGoodFor.pdf http://scalamacros.org/paperstalks/2013-12-02-WhatAreMacrosG... [3] http://docs.scala-lang.org/overviews/macros/annotations.html http://docs.scala-lang.org/overviews/macros/annotations.html
- edoloughlin 13y agoWell, 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 13y agoCome back to me when there's a standard for JSON schemas so my data can be actually strongly-typed + verified.
- edoloughlin 13y agoJSON 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 13y agoI 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.
- vorg 13y agoThere 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 13y agoClojure uses a lot of lazy evaluation in its collections library. Does that count?
- vorg 13y agoYes, I just listed the features of Clojure that weren't available in any other production-ready JVM language.
- mnbvcxza 13y agoWhy is Rhino coming soon?
- vorg 13y agoThat was "Javascript on the JVM is coming soon". I don't think Rhino's being used much in production (correct me if I'm wrong) perhaps because of slow execute times, but the far racier Nashorn is likely to kick out any lingering use of languages used for JVM scripty stuff, e.g. Groovy, Xtend, Beanshell.
- pron 13y agoI 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 13y agoSort 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 13y agoI 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.
- octo_t 13y agoSo 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 13y agoSome 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 13y ago
- hrjet 13y agoLooks 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.
- taude 13y agoThis is true. But there are a lot of devs interested in combining the ease and speed of dynamic language syntax with the robust compilation of a static language... This will be a popular topic for awhile, I believe, because the JVM isn't going anywhere in the next decade (gut feeling).
- brandonbloom 13y agoThere 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 13y agoInteresting! 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?
- wiremine 13y agoScala 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 13y agoBack 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.
- wiremine 13y ago> so you might as well just go with what you are comfortable with Very true. I was thinking of the ethos of Perl and Scala, and wasn't trying to compare the languages directly.
- lmm 13y agoI 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 13y agoI am not as fluent in Scala as I am in Perl, but I do like both. Perhaps, I am an exception.
- 13y ago
- hythloday 13y agoI 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 13y agoSo 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)
- jaxytee 13y agoAfter 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 13y agoNot surprised by this comment. Scala has the most bitter community I've ever seen. Contrast that to the Clojure community
- jaxytee 13y agoWhy 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.
- adrianm 13y agoI 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 13y agoIt'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 13y agoI'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 13y agoNo, 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 13y agoSounds 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
- cbp 13y agoIf I understand that scala code correctly it's just enumerating a multiple arity function manually. It's not that uncommon to see that in clojure for performance reaasons, clojure.core has plenty of examples as does the java-written compiler. It's a lot faster to enumerate the common arities than to use apply like: (defn f [& args] (apply g args)) And it usually just takes a couple of strokes in any decent text editor anyway.
- Touche 13y agoThere 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).
- kvtrew76557 13y agoPerhaps 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.
- weavejester 13y agoWhat parts do you find hard to understand?
- code_duck 13y agoHave 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 13y ago> 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 13y agoI'm looking forward to embracing its lispiness.
- eccp 13y agoComing from a Java and Groovy background it took me a while to "unlearn" and I think this is what happens to you. If you spend more than a few hours on Clojure (maybe you can create a small toy project) it make much more sense. I'm experiencing quite the opposite, I'm learning Scala now and it all feels too cumbersome, and even the syntax of Scala bothers me now.
- kailuowang 13y agoI 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 13y agoI 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.
- mortyseinfeld 13y agoDespite 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.
- laureny 13y agoIt 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.
- lukev 13y agoI 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.
- dragonwriter 13y ago> 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... }
- smrtinsert 13y agoWhy vs? What a false choice, I love both of them.
- mcguire 13y agoIf 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 13y agoagreed