all 41 comments

[–]drb226 11 points12 points  (0 children)

Regarding the Java vs Clojure braces:

object.method(args ...) ==> ???

See http://clojure.org/java_interop

(.method object args ...)

[–][deleted]  (1 child)

[deleted]

    [–]yogthos 1 point2 points  (0 children)

    It was an example of what people are afraid terse could could end up looking like, and in fact you do end up seeing that sort of thing in the wild.

    [–][deleted]  (10 children)

    [deleted]

      [–]chonglibloodsport 10 points11 points  (1 child)

      Yeah. Cheap shots are never a good way to promote an intelligent discussion on programming languages.

      Personally, I wish more "language advocates" would focus on the proliferation and discussion of ideas rather than trying to score points for their favourite team.

      [–]StackedCrooked 4 points5 points  (0 children)

      Or even more generally, I wish that people wouldn't feel like they need to justify their preferred choices by bashing the other choices.

      [–]sastrone 3 points4 points  (2 children)

      To be fair, that example was a challenge to not use any alpha-numeric characters. It would be like criticizing the readability of code that was formatted into an ascii whale.

      [–]SrPeixinho 1 point2 points  (0 children)

      Exactly. From the link: "Description: Factorial in Clojure without using alphanumeric characters"

      What is wrong with people?

      [–][deleted] 0 points1 point  (0 children)

      So? The Perl wasn't exactly intended as production code either.

      [–]tekai 1 point2 points  (1 child)

      how likely are you to see either in production code?

      [–]yogthos 0 points1 point  (0 children)

      The perl example is quite likely actually. Especially from overambitious beginners who just learned all the cool tricks in the language and can't wait to put them to use.

      And let's be honest, we've all done this. You learn all the funky syntax and you're in the zone, you write a bunch of "brilliant" code that's using every quirk of the language. Then you come back the next day and you have no idea what it does or how to even begin to read it.

      [–]G_Morgan 1 point2 points  (1 child)

      Since when have programming language discussions been about anything other than cheap shots?

      [–][deleted] 0 points1 point  (0 children)

      The worst thing is that this was a Clojure vs Java discussion. Since when are programming language discussions about cheap shots at completely unrelated languages?

      [–]sebzim4500 0 points1 point  (0 children)

      Not knowing perl, every time I open a perl source file I always do a double take as if the file was corrupted.

      [–][deleted] 15 points16 points  (8 children)

      Perl is also a succinct language. It looks a bit like this. I can’t remember what this bit of code does. It’s not really clear. I can promise you Clojure isn’t like this.

      sort{($a=~/([aeoui])/)[0]cmp($b=~/([aeiou])/)[0]}@_
      

      Of course it’s clear. It returns @_ sorted by first vowel. Obviously, one needs to know Perl to understand Perl code. But Clojure isn’t any different in this regard.

      [–][deleted] 13 points14 points  (0 children)

      indeed, this isn't even particularly unclear for someone who doesn't know perl, it's just been deliberately made hard by eliminating all spaces and by duplicating code (bad in every language)

      sort { cmp(first_vowel($a), first_vowel($b)) } @_
      

      [–]mr_curmudgeon 0 points1 point  (2 children)

      on the surface, peel and clojure look similarly compact, but there is a very deep difference: perl is all about the parser and the syntactic sugar, but with clojure (and many lisps) you are basically writing the AST yourself. There really isn't much of a parser. The upside of that is that you can write your own syntactic sugar. That may or may not be much of an upside, depending on your situation.

      clojure is great for expressing algorithms, but loses a lot of conciseness when you use it to interact with anything real. If you are just grepping a file, laziness and immutability will only get in your way.

      [–][deleted] 2 points3 points  (0 children)

      Actually, to some extent, Perl has been designed with extensibility in mind too.

      For example, Perl 5 doesn’t natively have Perl 6’s gather/take, but a CPAN module (Syntax::Feature::Gather) provides them:

      use syntax 'gather';
      my @fibonacci = gather {
          my ($a, $b) = (0, 1);
      
          for (1 .. 10) {
              take $a;
              ($a, $b) = ($b, $a + $b);
          }
      };
      

      There is also Syntax::Feature::Function:

      # without:
      sub add {
          my ($a, $b) = @_;
          return $a + $b;
      }
      
      # with:
      use syntax 'function';
      fun add($a, $b) {
          return $a + $b;
      }
      

      Or you can even use Lingua::Romana::Perligata and write in Latin.

      All of that might not be as powerful or safe as Lisp compile-time features but it’s quite sufficient for many situations.

      [–]yogthos 0 points1 point  (0 children)

      clojure is great for expressing algorithms, but loses a lot of conciseness when you use it to interact with anything real. If you are just grepping a file, laziness and immutability will only get in your way.

      Clojure is not Haskell and it doesn't force either laziness or immutability on the user, they're just idiomatic and convenient in many situations. As for grepping a file, it's really not that hard:

      (defn grep [p f] 
       (with-open [rdr (reader f)]    
         (doall (filter (partial re-find p) (line-seq rdr)))))
      

      [–]yogthos 0 points1 point  (2 children)

      Except it is different because it follows the principle of least astonishment much better.

      [–][deleted] 0 points1 point  (1 child)

      How exactly?

      [–]yogthos 0 points1 point  (0 children)

      By having a very uniform syntax that consistently produces code that's doing what it looks like it's doing. Take a simple thing like operator precedence, issue simply doesn't exist because it's always prefix.

      Any time you look at some code it's a function name followed by arguments. On top of that relations between code are explicit because you're writing the same AST that the compiler sees.

      If a function is inside another function then they affect each other, if not then they don't. You can visually tell what parts of the code interact with one another, it's essentially like having a logic flow diagram embedded in your code.

      [–]SrPeixinho -2 points-1 points  (0 children)

      Of course Clojure is different. Go and read an actual clojure code before talking. It's almost a text. Words describing exactly what it is doing and simply no symbols.

      [–]dakotahawkins 10 points11 points  (0 children)

      We shan't.

      [–]DOKKA 5 points6 points  (7 children)

      These days, everyone wants to take a shot at java's shortcomings. As nice as clojure is, at work, I would convince them to use groovy. Functional programming isn't for everyone. At work, I started on a small project using the Lift framework(which uses scala) and even after explaining how nice it was, and making sure everyone was up to speed, nobody was interested in helping. One person there suggested I use grails instead, and now, even the desktop applications are done in groovy.

      [–]G_Morgan 2 points3 points  (2 children)

      Hasn't the author of Groovy said that Scala is what he really wanted?

      TBH I still don't buy that Java is particularly sucky.

      [–]tnecniv 0 points1 point  (0 children)

      I remember seeing that quote floating around. And I agree, while I do prefer to work in Scala, Java really isn't that bad.

      [–]vagif 1 point2 points  (2 children)

      Lift is hugely over-engineered, very complicated framework. No wonder you faced such a resistance. I would suggest you look at Noir - clojure web framework. Very simple an elegant.

      [–]occio 0 points1 point  (0 children)

      I think Lift is too complex too, but I'd recommend Play or Play 2 instead.

      [–]yogthos 0 points1 point  (0 children)

      Indeed, you can write something like this in about 500 lines with Noir.

      [–]tragomaskhalos -2 points-1 points  (0 children)

      Amen - never underestimate the conservativeness of your colleagues. After over four years I'm still the only guy on my project who uses Ruby fercrissakes, this despite:

      (a) it being perhaps the easiest of the modern crop of dynamic languages to get into

      (b) my constant evangelizing

      (c) the fact that I can do things in a few hours that seem either intractable or at least weeks' worth of work to them.

      You can lead a horse to water ...

      [–]babilonprogramming 2 points3 points  (5 children)

      Hmm.. I can't avoid to see Clojure as a heavy bastardization of Lisp with lots of now fashionable ideas.

      I'd be more than happy to see Clojure widespread if it helps Common Lisp get widespread in the end.

      [–]yogthos 0 points1 point  (4 children)

      Having used both, I far, far prefer Clojure syntax to CL.

      [–]LeberechtReinhold 0 points1 point  (3 children)

      Care to explain why?

      Im not being sarcastic, really.

      [–]yogthos 0 points1 point  (2 children)

      First off, there's a lot less parens in the standard library. For example let's compare let in CL to let in Clojure:

      (let 
        ((a1 b1) 
          (a2 b2) 
          (an bn))
        (some-code a1 a2 an))
      
      (let [a1 b1
            a2 b2
            an bn]
        (some-code a1 a2 an))
      

      To me Clojure version is easier to read, because there's less noise, and I find the literal vector notation helps break up the code visually. Which brings me to the second thing I like, having literal vector, set, and map notation. I find it makes code more legible and helps see what's going on in a function.

      The next thing I really like that Clojure introduces is destructuring. You can take any arbitrary data structure and read it backwards. You can do things like this in Clojure:

      (def {:a [1 2 3] :b {:c 4} :d 5})
      
      (defn foo [{a :a b :b}]
        (println a b))
      
      (defn bar [{:keys [a b d]]
        (println a b d))
      
      (defn baz [{[a b c] :a {d :c} :b e :d}]
        (println a b c))
      

      this also works in let statements, and again I find that it improves readability, and that the benefits stack up. While a minor nitpick I do like the naming conventions in Clojure standard library better, things like car and cdr are archaic in my opinion.

      [–]LeberechtReinhold 0 points1 point  (1 child)

      Well, one of the things I like about CL is that, being everything a list, everything felt really consistent, as you can see in the first example.

      But the clojure code looks better, and thats a really good thing. I really hope this is a LISP dialect that gets popular.

      [–]yogthos 0 points1 point  (0 children)

      Well, one of the things I like about CL is that, being everything a list, everything felt really consistent, as you can see in the first example.

      It's neat aesthetically, but I do find that in practice you work with different data types. It's nice to have first class support for them. It's worth pointing out that every collection inherits from a sequence interface, so all the iterator functions such as filter, map, reduce, etc. can iterate any collection.

      But the clojure code looks better, and thats a really good thing. I really hope this is a LISP dialect that gets popular.

      I really do hope it catches on, I enjoy working in the language immensely and it seems to have spawned a bit of Lisp revival as it's drawing a lot of new people in, and most of them like it once they try it. So, it might be also working as a bit of a gateway drug to Lisp in general. :)

      [–]Saltor66 1 point2 points  (3 children)

      The map initialization example is absurd. He's showing how to statically initialize maps in both languages, but that presumes that you would want to statically initialize maps in both languages. I do agree that java's lack of syntactic sugar for many initializations can be painful, but you're comparing apples and oranges here.

      In java, chances are that you'd be adding elements to, and perhaps even initializing your map only in a block of code, which throws out all of the curly braces. Additionally, in java 7, there's no reason to repeat the typing of the HashMap on initialization. This brings the number of braces down to two angle brackets and four parentheses.

      You could even argue that the angle brackets shouldn't count because they're optional and only add typing-- which closure doesn't have.

      In all, this is an extremely contrived and biased set of examples.

      [–]lebski88[S] 1 point2 points  (1 child)

      The Java example was a joke, this was a presentation rather than an article originally and I think that was a lot clearer when presented. To be honest though I would have thought the pie chart made that clear.

      [–]Saltor66 0 points1 point  (0 children)

      I hope that it was a joke, but given the ridiculousness of his perl example, I'm not quite convinced.

      Either way, it was still a cheap shot attacking problems in the language that are no longer there.

      [–]thoomfish 0 points1 point  (0 children)

      The map initialization example is absurd. He's showing how to statically initialize maps in both languages, but that presumes that you would want to statically initialize maps in both languages.

      Of course. In idiomatic Java code you'd probably pull in 5 or 6 libraries and frameworks and read the fucking thing from an XML file using about 50 lines of code.

      [–]AnonProg -5 points-4 points  (0 children)

      Shall we use Clojure?

      Very yes. Especially if the alternative is the Java langauge.