Hacker News new | past | comments | ask | show | jobs | submit login
Why I am excited about Clojure (txus.io)
184 points by txus on May 5, 2014 | hide | past | favorite | 169 comments

I'm more excited about ClojureScript because it runs in the browser as JS, of course. My mind is kind of blown that Go-routines were added to the language as a library (core.async). And so was logic programming (core.logic), optional typing (core.typed), and pattern matching (core.match).

That's the neat thing about Lisp-style macros. You have to sacrifice a little bit of the syntactical sugar that you are used to in most languages, but in return you have the ability to add almost any possible construct to the language natively. It makes it much easier to extend the language as you don't need to hack an interpreter written in C or Java. Half of the core language is already written in macros.

Not having to memorize an operator precedence table makes me more than willing to give up syntactic sugar. This is one of the things that I dislike most about haskell. I wish liskell or one of the other projects trying to bring S-expressions to haskell had taken off.

If I have the slightest concern about operator precedence while writing code, I put in extra parens. Because it will definitely hinder me reading the code later. Plus, Haskell doesn't use them much anyways. I'm sure the 9 and 0 keys get lonely.

With haskell's type system most precedence errors are caught quickly. Precedence generally follows intuition: PEMDAS of course, and then the idea that control-flow operators like >>=, <|>, etc should be lower precedence, while operators that tend to group expressions together like (.) should be high-precedence. Of course a lot of the time it's somewhat arbitrary, but this is because a lot of the time it just doesn't matter. In cases where things aren't clear, you can always choose to use parentheses.

There's nothing stopping you from using more parens in your own Haskell code; I definitely use them.

I find if I'm using parentheses to group (non-numeric) expressions in Haskell then I should probably break up the expression and name the parts.

One wonderful thing about Haskell is that there isn't a cost to using let expressions, even if some of the values will never be used. Laziness means I can freely decompose my complex expressions into clearly named components and not worry about doing unnecessary computation.

>Not having to memorize an operator precedence table makes me more than willing to give up syntactic sugar.

Really? This is such a big problem that you have to choose a completely different language.

Knowing what the AST looks like without having to sit an think about it is huge. Maybe you're smarter than me and can instantly intuit it, but I think most people can't. I think that this is one of the reasons that macros are so widely adopted in LISPs but not in other languages that support them. Having an immediately evident AST makes it much easier to reason about, and hence to manipulate either through code or manually.

Edit: Improve clarity.

In that case you can either use $ or parenthesis in Haskell. I personally find the code neat without any parenthesis noise.

While this is a reasonable approach, it quickly breaks down when you look at code written by others who do not follow this approach.

When approach X isn't followed, approach X breaks down? True for all approaches, no?

Any language can be written poorly. I don't think any language will ever be able to force good coding style on programmers. Though Haskell comes closer to that impossible goal than many other languages, due to its type system, functional purity, and mandatory indentation.

The difference is that in lisp you cannot chose to not "follow the approach" because the approach is fundamental. So you will never look at anyone else's lisp code and see that they chose not to use parentheses uniformly.

Well, technically it's possible if someone used macros to embed a DSL that is paren free, but it just doesn't happen in the vast majority of cases. Whereas if you try to follow the approach of using parens everywhere in Haskell, the vast majority of other code you attempt to read will still be awkward for you.

There's a common complaint in this thread that is basically "just write your code better, then it'll be readable." There's also a common praise of Haskell that says that its type system eliminates entire classes of errors. It's not accepted by people who use Haskell that "if you use another language and just write your code better, you don't need a type system."

Having to explicitly indicate the precedence of operators -- as in Lisp's prefix notation -- completely eliminates precedence errors, both in writing and in reading. This is true even though "well-written"^1 code using implicit infix notation is readable.

[1] Note also that the level of implicit precedence that you're comfortable with might be different from mine.

The original infix operators and their precedences were natural to reason about...

  * /
  + -
  = !=
Of course you can always use an infix macro in Clojure, e.g. http://data-sorcery.org/2010/05/14/infix-math/

There _was_ a project to add s-exprs to Haskell?! Hopes raised and dashed in the same five seconds! I'm a seasoned lisper learning Haskell, and trying to figure out when this parameter will go where is driving me crazy. "No you stupid compiler, I'm passing this to that, not the other way arrrg!"

Of course, when writing Haskell, you could always just wrap the individual operators in parentheses and get the prefix forms (as distinct from fully parenthesizing to disambiguate with infix forms). Getting others to do so (and getting them to merge your code) may be an uphill battle, though...

Elixir has Lisp-style macros with a Ruby syntax. It's not quite as close to the AST as a Lisp, but I think the trade off hits a sweet spot. For example:

  quote do
    1 + 1

  {:+, [context: Elixir, import: Kernel], [1, 1]}
which, if you squint at it, starts to look a little Lispy.

I am a Ruby guy torn between diving into Haskell or Clojure. Help! Every time I get excited about one feature of one (ClojureScript) I learn the other has something equivalent or potentially better (Haste).

One thing that has put me off on Clojure is 1) the ugly as hell JVM stacktraces, 2) hitting the wall of the number system results in nasty JVM errors if you are used to Ruby's trivial (to the developer at least) handling of numbers of any size, 3) the time it takes to fire up the JVM itself (I like really fast really instant unit tests)

On the other hand, what has put me off on Haskell is that 1) all its users seem like mathematics professors, 2) a lot of its libraries will fail to compile when combined with each other without a lot of hand-holding and carefulness

I'll try to dispel some of the concerns about Clojure.

1) Stacktraces in JVM may be ugly, but the amount of insight into runtime issues that the JVM offers you is generally way higher than in runtimes like cpython or MRI.

2) Clojure gives you a rather elegant way to work with the different JVM number types as it offers literals for those. I think Java Longs (the integer default) should be long enough as it's a 64 bit value. And on the floating point side the default is a double, which also seems nice to me. See: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/dat...

Above this Clojure offers BigDecimal literals and native ratios.

3) The startup time is gigantic. However, while developing you usually should not have to restart the JVM as you can update the JVM with new bytecode through the REPL. This should also dispel the concern about unit tests (although I'm not sure you can reach the necessary speed, if you talk about < 0.5 second unit tests, because the code needs to be compiled to JVM bytecode 1st. There's definitely still potential there.

One thing I've noticed is that the JVM startup time is actually pretty small. What's slow is waiting for Clojure to bootstrap itself.

Detailed discussion on startup times at http://nicholaskariniemi.github.io/2014/02/11/jvm-slow-start... (and subsequent articles by the same author).

JVM Feature Request: The ability to preserve a complete JVM state (in this case with loaded Clojure stuff) and quickly start from there.

Does anybody know if something like that is possible/already exists?

I have used http://criu.org/ on Ubuntu 14.04 to checkpoint and restore a Java process running a Clojure nREPL server. It took 480 ms to checkpoint a 128MB process and 213 ms to restore on a 2.4ghz E5645.

Not quite what you asked, but I found people recommending this.


> Does anybody know if something like that is possible/already exists?

The majority of commercial JVMs that tend to be ignored on HN, provide JIT cache between runs and AOT compilation.

That's true, but it's generally like this with any Java application. The JVM starts in 0.3 seconds, but loading all your classes usually takes seconds. I don't know the arcitecture well enough, but I think it's because it looks for classes in a lot of places and unpacks JAR files etc.

That of course depends on the number of deps that you have, but you have to have a _lot_ to reach into the second range.

Yep. A JVM doesn't take more than a about 100ms to start up. But Clojure takes a long time, and Leiningen is slow as hell.

2) Clojure has sensible math with auto promotion to bignums, you don't have to worry about overflows like in Java.

3) You don't pay the price for the JVM startup time when running unit tests. When developing Clojure you have a JVM active at all time for your REPL. The JVM startup time is really only a problem if you want to write scripts.

Your first issue with Haskell is a plus! Everyone in #Haskell on freenode are incredibly helpful, and well, if they're all professors you likely to get some quality help, right?

> Your first issue with Haskell is a plus! Everyone in #Haskell on freenode are incredibly helpful, and well, if they're all professors you likely to get some quality help, right?

Eh... The Haskell community is amazing and always willing to help. They get an A for effort, but they often have the curse of knowledge[0].

> The curse of knowledge is a cognitive bias that leads better-informed parties to find it extremely difficult to think about problems from the perspective of lesser-informed parties.

[0]: http://en.wikipedia.org/wiki/Curse_of_knowledge

So the two languages have all their strength and weaknesses. I start with Haskell, and I try Clojure, time to time.

After working a while, I finally give a clear advantage to Haskell. Yes, Math people are chatty in Haskell, but you can do _a lot_ with very few Math.

In fact, with Haskell, the more your project growth, the more time you spend on interesting things. While in Clojure (and most dynamic languages), you'll lose your precious time with undetected syntax errors, and all standard unitype errors.

But for _very_ simple projects, Clojure is great in term of productivity.

So in general, I try to use the right tool for the right job.

- If you want to make a dirty thing, use a shell script or Perl. - If you want to make a prototype, Clojure is great. - If you want to make a project for production, then Haskell is the clear winner here (in term of bugs/efficiency/time).

One thing I get with Haskell I didn't got with Clojure is "code scalability". In Haskell, my code tend to be more reusable than in Clojure.

I'm curious how Haskell could be a clear winner for production code, particularly as it pertains to efficiency and time.

Clojure sits on top of the JVM, and as such, has the benefit of interop with some of the most robust software packages in the world.

Unless I'm missing something, you'd need to roll your own packages in Haskell for all this functionality.

I would argue that the most efficient code is well maintained open-sourced code that you don't have to write.

I don't use Haskell, so there may be lots of libraries I don't know about, so forgive me if this question is naive.

One of little secret of Clojure is that you almost never use Java based library. Because it forces you not to use idiomatic Clojure. So, most library you'll use in Clojure are in fact Clojure made. From this point of view of number of libraries, Haskell and Clojure are in fact at the same level.

I was sold in part by the JVM argument. But in reality, in practice, I found it to be more a burden than a delight. First, the stack trace errors. To deploy your application, it is not just a "copy your jar in Tomcat". You have to serve using Clojure. So in reality, you don't get all advantages provided by the JVM environment, only some.

Clojure is fast, but, Haskell is at least as fast as Clojure.

Up until here, I had all packages I needed. There are all here[1]. I made mostly Web oriented programming, but using MongoDB worked extremely well for example.

And the most important aspect (from my experience):

When your program growth, in Clojure the time you spend to add another feature growth rapidly (it is better in clojure than most other languages thought), but in Haskell, each new feature doesn't cost so much, even in a medium to big project.

So when you need to change something fast without breaking something (the without breaking something is the important part), nothing beat the Haskell type system (or may be Idris, but I didn't played with it enough).

Furthermore, the ability to minimize the number of bugs, gives me a good feeling about the quality of the libraries. Of course, Haskell is not magic, you still have to pay attention to bugs, to test your code. But Haskell helps a lot in not falling into dumb bugs.

[1]: http://hackage.haskell.org

> One of little secret of Clojure is that you almost never use Java based library. Because it forces you not to use idiomatic Clojure. So, most library you'll use in Clojure are in fact Clojure made. From this point of view of number of libraries, Haskell and Clojure are in fact at the same level.

In a production server I'm running right now, I've used three java libs, wrapped them very nicely and neatly, and they work great.

> I was sold in part by the JVM argument. But in reality, in practice, I found it to be more a burden than a delight. First, the stack trace errors. To deploy your application, it is not just a "copy your jar in Tomcat". You have to serve using Clojure. So in reality, you don't get all advantages provided by the JVM environment, only some.

For my current app, I just need to do: lein ring uberwar, copy to tomcat directory. done.

The rest I can't speak towards as I don't know Haskell. Also, it should be noted, I'm only offering counterpoints because I don't want people to not use clojure because of some of the incorrect claims. I guess we've had different experiences with clojure. :)

> One of little secret of Clojure is that you almost never use Java based library. Because it forces you not to use idiomatic Clojure. So, most library you'll use in Clojure are in fact Clojure made. From this point of view of number of libraries, Haskell and Clojure are in fact at the same level.

This isn't really true.

Yes, directly using a Java library forces you to use Clojure that is not idiomatic but 1) this isn't always the case 2) there are idiomatic wrappers over some libraries already.

More importantly, at least you have the option of using Java libraries. Having to use Clojure code that is not idiomatic still will be much more productive than writing the library yourself in Haskell.

Haskell does have a pretty good C FFI, so it's not as if you're necessarily going to have to reinvent the wheel. I know precisely nothing about Clojure's C FFI - I'd guess it has a fine one, which of course means that this isn't an edge for Haskell per se but it does make the Java interop slightly less important.

Just a minor point, some of the build tools allow you to make a .war file, and that you can just copy into Tomcat if you want.

Which kind of libraries are you thinking of that are missing?

imap library with idle support. haskellnet and imapget don't mention idle from what I can see. javamail does.

haskellnet looks like it does polling, but i gather its not quite the same thing. looks like you're right. I wonder how hard it would be to implement such a thing.

General advice: don't let the desire to learn the "right" thing prevent you from learning, period. Eventually, it's better to just make a choice and dive in, then to spend more time trying to figure out which one is "better".

Absolutely learn both! Make sure you learn macros well (I suggest Let Over Lambda) and Haskell's powerful type system. I know Clojure and macros pretty well, but learning Haskell the last couple months has been incredible. And then learn Forth, J, Prolog, do SICP in Scheme, etc. ;)

Agreed 100%. I can learn both, given enough time.

They're both amazing languages that are simultaneously very fun to use and very powerful, not to mention great with concurrency, but here's the grossly oversimplified gist of when you'd want which language:

Clojure has a beautiful dynamic type system. Haskell has a beautiful static type system. If you're working on a project with changing requirements (which for me means most nontrivial applications), Clojure will be much easier to work with and, as with most Lisps, is very well suited to what pg calls exploratory development. If you're working on a project whose requirements are largely static and known in advance (compilers, interpreters, parsers, static analyzers, mathematical tools, etc.), then you won't have to worry about coding yourself into a corner and Haskell's insanely powerful type system becomes a positive.

Wow. I came to the exact opposite conclusion you have. Changing requirements is really where Haskell shines. The ability to make a change in the types and have the compiler tell you everything that needs to be updated is an enormous aid to refactoring. As for exploratory programming? Haskell has powerful tools to do that as well. GHCI, type inference and typed holes[0] work extremely well for exploration of what's possible and can even give you solutions to your problem that you hadn't even thought of.

[0]. http://www.haskell.org/haskellwiki/GHC/TypedHoles

I agree, though one has to compare apples and apples. experienced programmer vs inexperienced programmer is not fair. Of course if one is unfamiliar with how to build a flexible type safe systems, (newbies), there could be these sorts of issues. But for experienced programmers, not really.

though one has to compare apples and apples. experienced programmer vs inexperienced programmer is not fair.

Oh, definitely. I just feel that far too many people focus on programming languages that are good for beginners without really thinking about them from an experienced programmer's perspective. What may be good for a beginner can often be terrible for an expert. What may be hard to understand for a beginner can be extremely powerful and simplifying for an expert.

I think the question people should ask themselves is: "Do I want to stay a beginner forever? If not, why am I using tools that are designed for beginners?"

Excellent point.

We regularly extol the virtues of expert-friendly text editors, but don't talk much about the appeals of expert-friendly languages and frameworks. Also worth thinking about: a huge amount of hype gets allocated towards beginner-level languages/frameworks that solve beginner-level problems (todo lists) more easily.

I'd guess that is because most developers ARE beginners, right up till they retire/career shift.

If we were even half experts, maybe that would change, but in a field where "anyone can be a developer" you will see a long tail of low skill.

Not sure why you were downvoted.

Industry routinely degrades skill and experience in favor of "just ship." New frameworks are continually churned out with the implicit promise that they'll fix everything (except their own lack of composition). Custom development is viewed as expensive when someone else can come along and paste several libs together, then apply duct tape to hold it all together. Domain modeling is viewed as esoteric. Testing is still hotly debated.

...I don't want to go on.

I could argue that for most people, it is only when they start bumping into the limits of the beginner's tool that they see the point of the more advanced tool.

I think this is a very limiting approach to life. It leaves one open to the Blub Paradox[0] (or more generally the Dunning-Kruger effect[1]). My personal approach is to keep an open mind and assume that there's always a better way to do something than what I am doing now.


[0] http://www.c2.com/cgi/wiki?BlubParadox

[1] http://en.wikipedia.org/wiki/Dunning-kruger_effect

As a new programmer I'd say there's an aspect that you're ignoring. The need to take reasonable steps, and to know if not your limitations at least where you stand.

You want to take the next step that has enough familiar aspects that you can acclimate reasonably quickly and build non-trivial programs (the fun part) in a reasonable amount of time. But also different enough that you're exposed to new concepts and new ways of thinking about programming, and also to have access to a more powerful language.

Simply diving head first into a powerful but completely foreign language might not be the best way. Coding can be as frustrating as it is rewarding. And there's something to be said for trying to maximize the rewards and minimizing the frustrations.

What better way to know your limitations than to seriously challenge yourself? I taught my friend to program in Haskell and while he struggled early on he found it incredibly rewarding. Since then he's found it extremely easy to learn other programming languages, despite their extensive differences from Haskell.

There's also a lot to be said for habit-forming. Imperative languages teach you a lot of habits and cause you to develop assumptions that might actually make it harder to learn a language as different as Haskell. This makes the concept of "taking steps" in your growth as a programmer a nonlinear one. Some languages might even hurt your ability in the long run.

Although 'coding yourself into a corner' is definitely possible, I would rather hope that one makes good decisions, there is plenty of space to type things and allow re-usability and flexability. You could make a similar but different negative statement about clojure, about having to maintain a large project when the requirements change, if you're not careful you may find a change in one part of the code breaks another part of the code.

I shared your worries about the turnover time for unit tests. But if you use something like [Midje][1] with the 'autotest' feature on, your tests will run in the background after each save. It typically takes a fraction of a second to run the full suite, so by the time I'm done hitting save and switching over to the midje console, the test results are already there.

[1]: https://github.com/marick/Midje

I went for Haskell. I think Clojure is too close to Ruby in the respect that there is not much safety build in. And I --like you-- am JVM-averse. :)

Here's a serious downside of Haskell:


Experienced and skilled developers (wiegley's open source work includes ledger and great contributions to emacs org-mode), and the task is to make the API client's base URL configurable. Should be trivial. And yet it descends into farcical stuff about whether they need to introduce a new github monad or to "abstract over a type class". It seems like the purity was really getting in their way. The issue was never solved. I may be cherry picking an example which serves to parody Haskell, but for me that example is really off putting.

Hey, I'm a Rubyist in the process of learning Clojure and Haskell. Shoot me an email sometime. I'd love to bounce some ideas around nick dot mcd at gmail

bitemyapp seems to have pretty clear opinions on Haskell vs Clojure: http://bitemyapp.com/posts/2014-04-29-meditations-on-learnin...

I'm a Python user and I love Clojure. I guess I missed the Go bus. But there's 2 things about it I'm not too fond of.

One is due to it's declarative nature (which I love), it's quite difficult to get up to speed with unfamiliar code.

The 2nd is due to it's JVM roots. Those stacktraces, man. And when it happens on an anonymous funtion in a not so documented library, ugh. It's like hitting a brick wall.

The first, I can deal with enough practice and Schema/core.typed. Is there any hope for the stacktraces to improve? How do other JVM based languages fare in this regard?

Oddly enough I never used this, but maybe named fns might help? (http://clojure.org/special_forms#Special%20Forms--%28fn%20na...)

    (fn my-name []
      (throw (Exception. "boom")))
(Sorry, I don't know Clojure internals well enough to have great answers to your explicit questions.)

[Edited: thanks to jerf for pointing out the inconsistency in a term I used.]

Named... anonymous... functions? Wuzzah fuzzah?

They allow you to use recursion without the need for a Y-combinator.

Yeah, that's a terminology issue. They mean lexically scoped named functions. Versus the default in Clojure of global or namespace scope.

Just like in Javascript.

Named anonymous functions are there to allow you to call the function recursively while inside it.


    (= ((fn factorial [x] 
          (if (<= x 1) 
              (* x (factorial (dec x))))) 5)
Note, this isn't run under TCO (see loop/recur).

Also, in your example, the recursive call is not in tail position. You would first need to rewrite it to use an acumulator parameter.

There are people working on improving stack traces[1][2], but there is no standard solution yet.

[1] https://github.com/AvisoNovate/pretty

[2] https://github.com/mmcgrana/clj-stacktrace

That last feature is certainly one of my favorite parts about Clojure. It's one of my favorite parts about Lisps in general actually, but Clojure has a very good handle on it. Having to compile a program before seeing if the changes you made work can be a nuisance. Interpreted programs are slightly better, but being able to make micro-changes to a running instance of a program and seeing in real-time how it affects the whole program is the best. The feature that Clojure misses here is the ability to load new libraries (jar files) on the fly, but that's not Clojure's fault, but rather the JVM's fault.

What I find really surprising is that other languages that have pretty decent REPL support have not embraced it so fully as Lisps have. Connecting to the live[0] instance a Rails or Django app, examining its internal state and making updates that don't involve more or less restarting the app is unusual at best.

Ruby and Python borrow a lot from Lisp, including the REPL, but some of the most popular applications of those languages barely take advantage of it. Why?

[0] I'll stipulate that you might want to be very conservative about doing this with a production system.

The work done at Xerox PARC with Smalltalk and Interlisp was great.

Imagine having a REPL to your complete OS, not the just the basic CLI that most systems have.

There are a few videos of those days showing up the systems.

+1 I still think fondly of the InterLisp environment on the Xerox 1108 Lisp Machine my company bought me in 1982. You can find emulators for InterLisp, but the experience is not the same.

Everything I know is from the documents, papers and videos that I manage to scrap from the Internet.

My experience with Oberon, lead me to track down how Wirth learned about such systems.

Additionally, I got to learn Smalltalk in the form of VisualWorks before Java was known to the world.

So I extrapolate my experience to how it might have felt back then and find it sad we are still trying rediscover it.

I'll stipulate that you might want to be very conservative about doing this with a production system.

No kidding. I knew at least one guy who hosed a product launch by doing that. You even have to restart your development instance from time to time to make sure that your application state remains consistent. I've been scared to try, but I suspect that you could live-patch a server though if you were systematic about it and tested the patch ahead of time.

You even have to restart your development instance from time to time to make sure that your application state remains consistent.

There are ways around that. Stuart Sierra uses a scheme wherein the entire application is treated as a value, which can be re-generated on the fly. Of course, that's not terribly different in practice from restarting the whole environment, but it's faster and more convenient.


Back in 2001, We had a corner case bug in our ORM that impacted a scheduled demo. So I connected with the live Smalltalk app server and changed the state of the DB locks during the demo.

There are technologies deigned to enable live updates. VisualWorks Smalltalk had one, though it was not widely used. There are real time OS that can update the kernel without going down.

You might like Flask. It has an interactive REPL on debug screens.

I have used Flask. I do like it.

I admit to still not understanding what goes on with function definitions in clojure, but this idea of just making a micro change in clojure and evaling that and seeing the real time effects never seems to pan out for me.

I do lots of small functions that build on each other. If I make a change to one of the base functions, the higher functions seem to hold a reference to the old definition and I end up having to re-eval everything or go figure out every place I used that function.

I'm sure there is a better way but I haven't found it yet. I've tried using some ideas from Stuart Sierra about reloading namespaces, but I spend more time trying to orient my code to work with their ideas than just getting something done.

And documentation in clojure code in general is very poor. People think their code is self documenting. It is not.

While clojure is wonderful to write in, it's not nearly as enjoyable to read. The more macros and syntactic sugar people add to their programs, the less likely someone is going to be able to read, understand, and use that code.

If macros are used properly, they should make the code easier to read, not harder. If you can't figure out what it does from it's signature and docstring (maybe with a reference to some documentation for more complex or abstract things,) there's a problem. You shouldn't have to read a macro's definition to be able to use it.

Also, redefining a function should cause every function which directly references it to use the new version. You can sometimes run into issues if the functions are defined in separate namespaces or if the redefined function was passed to the other as a higher order function during the latter's definition.

If it's a macro you're redefining, yes you'll have to redefine functions which depend on it, but you should be defining too many macros.

"If macros are used properly, they should make the code easier to read, not harder."

Well, I think macros often play the role of jargon. They let you spell out a particular concept succinctly and precisely and make the whole much easier to follow once you are familiar with the jargon, but people unfamiliar won't fully understand.

Much like jargon in spoken language in any field it can be picked such that those otherwise familiar with the language draw conclusions (that are hopefully correct), or picked so that they recognize that they are unable to draw substantial conclusions (which may be incorrect). There are upsides and downsides to both approaches (which isn't to say one doesn't dominate, but from my limited perspective it's not clear).

I should note that, to some extent, this is true of most kinds of abstraction.

I suppose. If you don't know what a for loop does you can't really be expected to use one. But you shouldn't have to understand how a for loop is implemented in order to use it correctly is really my point.

Macros can be used to implement some pretty novel abstractions so there can be some temptation to try to understand them by reading the implementation. However, if an abstraction is novel enough, it really should be documented somewhere very thoroughly.

So, to some degree your analogy makes sense. You can use macros (and functions too, really) to express concepts that are unclear unless you have a better familiarity with the topic or the program in question. But I feel that that's what docstrings are for.

All certainly the case. Any sort of jargon should be well defined and well documented. Standardizing on jargon between groups eases transitions between groups, but may mean it fits individual problem domains slightly less well. &c, &c.

>And documentation in clojure code in general is very poor. People think their code is self documenting. It is not.

Clojure functions and macros have docstrings you can query with the "doc" function. Honestly I've started keeping a repl open all time like I used to do in C with a terminal + man, so I can use (doc whatever) or (source whatever) to see the documentation + implementation details of most of the functions I use.

I do appreciate the doc strings. If only more people would write them. Weavejester's code I think is a fine example of doing this well. https://github.com/weavejester/compojure/blob/master/src/com...

You can use Alembic[1] to add dependencies at run time, not just adding them to the path, but downloading them from clojars or maven central, eg. using the example from the docs:

(alembic.still/distill '[org.clojure/tools.logging "0.2.1"])

Or something like clojure/tools.namespace[2] to edit your project.clj and then reload/refresh all namespaces to be current.

[1] https://github.com/pallet/alembic [2] https://github.com/clojure/tools.namespace

> Having to compile a program before seeing if the changes you made work can be a nuisance.

Not being able to compile a program to check if the changes you made are even coherent is also a nuisance.

Also, nothing says that compiling a program has to take a long time (eg. go).

I could load jars on the fly in Java.

This has been possible in Grails and Play for many years.

You can make a code change and refresh the browser and your changes are reflected.

TIL that that is possible. Just googled it apparently requires custom class-loader. Thanks for this.

Check out JRebel [1] which works with a plugin to your favorite IDE if you want to make it really easy.

[1] http://zeroturnaround.com/software/jrebel/

Or you can simply use OSGi.

What is it about Clojure that Rubyists love? I am a Rubyist who is new to Clojure (I love it) and I cant explain it myself. Clojure was suggested to me by several other Rubyists. I find myself suggesting it to other Rubyists as well....

I'm not exactly a Rubyist, but I really like Ruby. One of the things I like about it is its orthogonality: the concepts you learn work identically or similarly in different places, for different object types (where possible) so a relatively small handful of syntax + ideas + the library docs give you a running start at any program.

The same applies to Clojure. There's laughably little syntax to learn, and once you've got that under your belt you're just composing functions.

I'm not made to feel I've wasted a lot of memory space on the esoterics unique to some particular language. Clojure works for me rather than the other way around. This no-nonsense obviousness was one of Matz' design goals for Ruby, and clearly ditto for McCarthy and Hickey.

This is called homoiconicity[0] and it's one of Clojure's coolest features in my opinion.

[0] http://en.wikipedia.org/wiki/Homoiconicity

The concept of homoiconicity has yet to really sink in for me. Conceptually, I understand what it means and I can explain it to others but I have yet to really understand it in a practical sense.

Imagine if, instead of Javascript, you had a language based on JSON, with a few additional types, notably a 'symbol' type and a 'list' type. A few of the symbols are primitives that determine the semantics of the list type, allowing other symbols to be defined as functions.

That's homoiconicity, and Clojure strongly resembles an actual implementation of this conceit.

I'll go out on a limb and say that everyone on HN loves Clojure! It seems to be the least cribbed language here. Its features are hard to beat - that and Rich Hickey's wonderful talks[0] make you all the more confident in Clojure as a language!

[0] - http://www.infoq.com/author/Rich-Hickey

In a community of several 10's of thousands of people saying 'everyone' is always wrong.

To love clojure you'd have to first become proficient in it and I highly doubt even double digits of HN would claim to be proficient, much less to love the language.

In general, you speak for yourself and yourself alone and my take from your comment is that you love clojure.

I have played around with it but not enough to be able to say that I love it, even though I would like to spend more time with it.

I'm sure that when the honeymoon phase is over clojure will be yet another useful tool in the toolbox. I can't recall a single language that I truly love, they all have their specific warts and I expect clojure to be no different in that respect.

Just a different set of limitations to applicability.

To love clojure you'd have to first become proficient in it...

I do not think that the GP was using 'love' in that sense. You can 'geek out' about news and information about something without actually being much involved in that something at all. Witness the popularity of posts about space launches on HN. I doubt that there are very many actual rocket scientists, but we sure do have a lot of people interested in progress made in space.

Love for space travel and love for a programming language are two different things entirely, the one is an adventure on an almost trans human scale the other is a way to tell a computer what to do.

>To love clojure you'd have to first become proficient in it and I highly doubt even double digits of HN would claim to be proficient, much less to love the language.

I'm pretty sure many times more than 99 HN people have used Clojure extensively. Heck, there have been posts here from teams using it in production on their startups.

Apologies, I meant that as a percentage, not as an absolute number.

Speaking as someone who has lately been studying Common Lisp, I'm not quite sure how I feel about Clojure; I like that it's hosted on the JVM, but I don't like the apparent lack of a debugger, which to my mind is a sine qua non of Lisp development. I haven't seen much in the way of progress on that front, either, but it's been a few months since I last looked into it; is there any sign that that handicap is likely to be repaired?

I'm the author of Cursive, a Clojure IDE based on IntelliJ. Cursive currently has a fairly minimal and occasionally frustrating debugger that I'm planning to improve soon. That said, I use it all the time and it works pretty well. It's really nice to be able to debug a REPL session. Currently breakpoints and stepping work well, and expression evaluation somewhat works but is pretty quirky. Types and names are all currently displayed as Java, unfortunately. I'm planning to have a debug REPL per stack frame when I get around to upgrading this part. I'm hoping to get to this sometime within the next month.

Well, I'm glad to see that you at least appear to be headed in more or less the right direction. I'm not about to invest $100 in Clojure at this early stage of the language's development, but I'll be interested to see how the tooling continues to progress.

They have a similar taste, one of many examples is both are dynamic typed. There's at least some LISP ancestry for both (more for Clojure obviously).

As for differences I like Clojure because I can compile up an uberjar and hand that uberjar to ops and walk away, so its faster and easier, whole regions of "fun" (In the dwarf fortress sense of "fun") that exist in ruby deployments simply don't exist as a class of problem in clojure deployments.

I also went Ruby -> Clojure.

Ruby appealed to me because of its simplicity and conciseness, but after a couple years it turned out to actually be rather complex.

I found the simplicity and conciseness I was looking for when I was randomly reading some Clojure code a couple years ago in the speclj sample docs (http://speclj.com/tutorial/step7) of all things.

Well, I think it's because Ruby has borrowed a lot of features from Lisp (and Clojure is also a Lisp). Here's an article that argues that it is actually an acceptable Lisp: http://www.randomhacks.net/articles/2005/12/03/why-ruby-is-a...

I'm learning Clojure, and my favorite thing so far is that the Clojure community's idea of engineering is substantially better than Ruby's. For example:

* immutability by default

* decoupling by default

* small libraries rather than mega-frameworks

The comparison is not quite fair; but there's something to be said for appreciating a well-engineered solution versus the usual "SHIP FASTER, PEON!" schtick that Ruby has.

I think the SHIP FASTER PEON! thing has less to do with Ruby and more to do with the perception that Ruby is some magical tool with which you can rapidly build anything. I learned Ruby 100% on my own and never worked with anyone else who used it and I've found my approach to writing Ruby very similar to my approach to writing Clojure: decoupling by default, immutability by default (where possible), single use design for methods. It wasn't until recently that I learned that what I do naturally in programming has an entire school of thought behind it called SOLID design. I definitely agree that Clojure lends itself more to following SOLID design principles but I think that Ruby can as well.

I love learning, especially how to write succinct clean code. Clojure, like ruby, scratches that itch and is fun to work in. It feels written with the intent of making programmers lives easier through mastery.

I remember reading one of PG's essays about Lisp being the most powerful language, and he made a list of characteristics defending his position. He implied that the new languages that are becoming popular simply move closer to being a Lisp. My guess is that Clojure is the Lisp that emerges most directly from someone who learned about languages from Ruby. I've only ever hacked with Ruby, if I can find a good intro series for non-coders to Clojure, I'm going to dive into it.

Lisp has a lot of strengths, don't get me wrong. But it is an ancient language, and despite its age, it never managed to catch on in a big way. It is true that many more popular languages keep stealing Lisp concepts, but that doesn't tell me that Lisp is amazing, but that despite all of its strengths, it must have some terrible weakness that makes it relatively uncompetitive in the general programming population.

My opinion is that it crosses a syntactic threshold of abstraction, after which a language just loses. s-expressions are extremely powerful, but also the language's Achilles heel.

This resembles how there is a 'happy medium' for writing human languages. We could write all of our text in morse code, but we don't. We know that too many glyphs, like in Chinese, slow down learning too, as the effort to remember them all takes lots of practice.

So just like Scalaz's operators are so arcane that us mere mortals are better served by using words instead of <=o=>, a world of s-expressions makes it harder to find your way precisely because of excessive syntax homogeneity.

Still, I think Lisps are worth learning, it's just that I think the ideal language steals much from Lisp, including most of what s expressions are used for in practice, but it doesn't go all the way.

At a fairly superficial level, the :keyword syntax seems reminiscent of Ruby. But I'm neither an expert Rubyist nor Clojurist (Clojurian?) so I would defer to those more familiar.

They both have same roots, the :keyword syntax comes from Common Lisp and others:

    From Matz (creator of Ruby):

    Ruby is a language designed in the following steps:

    * take a simple lisp language (like one prior to CL).
    * remove macros, s-expression.
    * add simple object system (much simpler than CLOS).
    * add blocks, inspired by higher order functions.
    * add methods found in Smalltalk.
    * add functionality found in Perl (in OO way).

    So, Ruby was a Lisp originally, in theory.
    Let's call it MatzLisp from now on. ;-)

If you remove macros and s-expressions from a simple lisp.. what remains?

Genuinely curious. If I'd had to guess I say just the spirit of the language, the macros being reincarnated as the highly dynamic smalltalk method system. The s-expressions being reincarnated as the blocks.

It remains something that people living on a strict OOP+procedural+Algol-like-syntax only are willing to swallow.

...otherwise they'll just go "yuuuck!" or "wtf?" or "this is weird" and walk back away to their cubicles. Ruby is great because it changed the culture by letting the kinds of people that wouldn't have dabbled in functional-ish programming or DSLs put their toes in the meta-water ...now hopefully, some of them will start to take swimming lessons :) (and a few will drown themselves and their friends, of course, but there are prices to pay for enlightenment)

> If you remove macros and s-expressions from a simple lisp.. what remains?

java script :)

Brendan Eich was hired to Netscape to "put Scheme in the browser", he ended up with Javascript.

see also: https://mxr.mozilla.org/mozilla/source/js2/semantics/

Put another way, Ruby is a Lisp implemented by someone who doesn't understand what makes a Lisp worthwhile.

* Start with Emacs Lisp [1]: Well, if you like, but in exchange for the perceived simplicity as compared with e.g. ANSI Common Lisp, you're also giving up extremely useful things like lexical scope, and that's going to hurt your users down the road.

* Remove macros and s-exprs: Why? They're a powerful feature, and if you're building a Lisp, then operating on the AST shouldn't be hard. Except that removing s-expressions costs you homoiconicity, which means you need to translate from source to AST, which means the difficulty of writing a macro just jumped by several orders of magnitude, so, fair enough, if you're throwing out s-exprs then macros have to go as well. I can see an argument for this decision, in that it lowers the barrier to entry for non-Lispers who have yet to get over the parentheses allergy.

* Add simple object system: Is it really that much simpler to do single inheritance + mixins (Ruby) than to do multiple inheritance (CLOS)? This is an honest question; I've never implemented an object system, so I don't know which is easier from the developer's perspective. From the perspective of the language user, though, I don't know that I see a lot of difference.

* add blocks: This decision strikes me as totally indefensible.

If you already have lambdas, why do you need this separate abstraction which looks and smells mostly like a lambda, but doesn't act like one except in certain circumstances, and which is also the only place in your entire language with lexical scope rather than dynamic? You've just unforgivably complicated your language's syntax and implementation, and your users' lives; you've made it necessary for people both to write, and to understand, documents like [2]. Why would you ever do that?

And if you don't already have lambdas, in what crazy world of paisley skies and ice-cream seas does it make any kind of sense to put yourself and your users through all these unnecessary mental calisthenics, when you can just add lambdas, and solve all these problems with a single simple abstraction that everyone either already knows or should?

I can't imagine how anyone could possibly defend this reeking farrago, but I'd sure like to see someone try.

* add methods found in Smalltalk: I'll concede this one; it was a good idea, and a lot of Ruby's power comes from being able to hang magic off method_missing. Of course, a lot of Ruby's headaches come from that, too, and it is a persistent source of subtle bugs and unexpected behaviors, especially in frameworks like Rails which make heavy use of such magic hooks. For Smalltalk developers, this isn't so much of a problem, because Smalltalk is so heavily self-documenting; Ruby developers are not so fortunate.

* add Perl functionality: Well, this makes sense, if you're trying to come up with a Perl killer, in the same way that Perl was explicitly intended to be an awk and sed killer. It seems lately to be working, too; there's what looks to be an increasing trend for people to use Ruby for the sort of tooling which, a decade ago, they would've done in Perl. On the other hand, and I say this as someone who grew up with Perl and will always have a soft spot for it, Perl is a giant ball of hair laced with fish hooks, into which only a true expert may plunge his hands and pull them back out without severe lacerations. If you let your Perl emulation anywhere near the conceptual or implementation core of your language, you risk infecting it with the same disease -- indeed, I'm inclined to wonder if that's whence came the brain damage that led to Ruby's mess of mutant lambdas.

Don't mistake me: Ruby is a cute, useful little language, and it has some interesting ideas which I think are worthy of wider consideration, such as the method system. Unfortunately, Ruby also has some grave drawbacks, such as the lack of a self-documenting capability to make the method system sane to use at scale, which in my opinion rather severely reduce its appeal.

[1]: No, I've never seen Matsumoto admit outright that he started with Emacs Lisp, but I think it's a reasonable surmise. Consider: Emacs Lisp descends from MacLisp, which is both simpler and older than Common Lisp; in both Emacs Lisp and Ruby, lexical scope is an afterthought, inflicting at least occasional headaches on users of both languages; prior to inventing Ruby, Matsumoto was an Emacs Lisp developer of considerable Japanese repute.

[2]: http://awaxman11.github.io/blog/2013/08/05/what-is-the-diffe...

There are quite a few things in Clojure that are similar to Ruby. nil? empty? and count all do in Clojure what you'd expect from Ruby. take-while, drop-while are a couple other examples.

The funny thing is that the reason for the similarity is that Matz "borrowed" most of those features from older lisps.

Rich Hickey (creator of Clojure) was/is a big Ruby user.

I am not, and have never been, a Ruby user.

Thanks for Clojure dude.

Sorry, I apparently have a false memory of that. Maybe I was mixing up your history with that of Stuart Halloway.

I'd like to learn Clojure. Any suggestions on how to get started? It's my first time using a Lisp dialect. I figured I'd tackle the Clojure Koans, and mix in a few Project Euler problems.

I'd also like to do some code reading. I know the Clojure source code is on GitHub, but maybe something smaller to start?

If anyone else is interested in getting started, here are a few links I visited over the weekend:





The last link is an hour-long interview with Rich Hickey - a fantastic introduction to the language and his design goals. It's probably the best technical video I've ever watched on YouTube.

> When I start using a language, there are usually some situations where I can't understand why my code isn't doing what I expect it to do. When that happens to me in a language like JavaScript, for example, finding out what the problem was is generally a very frustrating experience

This is a very weird paragraph to me because I've experienced the exact opposite. You can see my frustration in this stack overflow question I titled "How do I get better feedback from Clojure errors?": http://stackoverflow.com/questions/16901836/how-do-i-get-bet...

While I agree that JavaScript has tons of "Wat" quirks that shouldn't be there, I rarely run into them. And more importantly, when I get errors in JavaScript, the cause is relatively easy to track down.

With Clojure on the other hand, it is really difficult for me to figure out why I'm getting the error. Yes, I get the error because I "was doing it wrong", but the errors don't help me figure out what I was doing wrong.


> With Clojure your editor (be it Vim, Emacs, Light Table...) is permanently connected to a live REPL. You continually develop, test and modify functions with subsecond feedback. Continuously. All the cores in your brain are lit, as you have literally no time to think about anything else. That's not only deeply satisfying, but also leads you to certain thought paths that slow feedback and its inevitable lower focus would have simply blocked. That's one of my favorite parts of Clojure.

This is very useful when you're writing new code, but I found myself scratching my head when I had to go back and modify already existing code to add a feature. As a workflow, I don't "get" when/how you're supposed to add automated tests when you're using REPL driven development. But, once I went back to my code, I always wished they were there.

You see, I'd modify the code and break something and then the problem I described above made fixing it very time consuming. Usually the cause of my problem was my simple functions wouldn't integrate together the way I expected. The REPL gave me the quick feedback to say that "increment-number" worked, but I would accidentally pass in a String or a vector into the function.

I have been working in both clojure and javascript for a while. When I encounter bugs in javascript assuming it does not crash, it can become difficult to track down the source due to the lack of name-spacing, mutability of variables that allow for race conditions, and unintended changes upstream if you're not careful.

Where as in clojure, the scope of name spaces is generally smaller, while the errors are more cryptic, I agree. The line number that it points you to and use of the repl allows one to dissect the function in great detail and by checking the incoming data and outgoing data, the bug becomes much clear. At least in my experience.

shrug Just different experiences I guess. I should note this isn't exactly an apples to apples comparison. I am using a lot of discipline in my JS project. I'm writing the code test-first most of the time, and I only have one global variable in the whole project.

Some JS frameworks lend to more difficult debugging.

I've done a lot of Clojure. For iterative/REPL-driven development I find Haskell a lot more pleasant. The types drive how I think, provide way-way-way better feedback on mistakes, and provide a new modality for querying my code in the REPL.

As a bonus, the UX to ghci is better than using nrepl/cider in Emacs. Reload "just works" and works more quickly than reloading namespaces in Clojure. I was gobsmacked when I saw how much better ":r" worked in ghci than reloading in the Clojure REPL.

> With Clojure your editor (be it Vim, Emacs, Light Table...) is permanently connected to a live REPL. You continually develop, test and modify functions with subsecond feedback. Continuously.

Can anyone explain or point me in a direction where I can learn how the above functionality is actually used and useful?

I keep hearing about live-editing/hot-reloading, and in theory I believe it must be very useful, but I cannot concretely imagine how it would be used in practice. What kind of programs can work like that? Continuously running programs, like web servers/GUI programs? So what happens when you change a function? Do you manually simulate a web-request? Rerun unit tests? Would it work with command-based pipelined programs, such as compilers as well?

It's a side effect of decoupling. If you don't need to pass the world in to a function, then it is much easier to poke at.

I played with Clojure making a simple pong game, and used this to work on collision detection. I worked on a function called rect-intersects that took in two rectangles. It was much faster to work on than if I'd booted up the game each time.

The beauty of Clojure (and all functional languages) is that everything your app does is made of very small functions composed together. You wouldn't really simulate the round trip http request via the REPL but you can change and test idempotent functions independent of each other. Most Clojure functions are under 15 lines of code.

You can also mess around with transforming state that you may have stored in an atom...

> What kind of programs can work like that? Continuously running programs, like web servers/GUI programs?

I use Common Lisp and Hunchentoot to build RESTful web applications. I can connect to the Lisp image running on the server using Swank from Emacs on my development box. If there is a bug, I can change the function, recompile it, and test the change with curl, without rebooting the server or reloading the app. The same techniques work for adding new functionality and APIs.

I suggest just giving it a try. It'll change the way you think about building systems.

What do you do then, after successfully fixing the bug? Are the changes automatically reflected in files, or do you need to manually perform the same change locally and commit it, so that it's there when the server is next redeployed?

If you check out our meetup [1], we do Google Hangouts based demos of this in emacs as part of our SICP study group. It's all free and we are happy to help in person if you are in the Philly area.

[1] http://www.meetup.com/Clojadelphia/

I'm also mostly a Rails dev in my day job but have been exploring Clojure on my own. I've found myself writing out functions in Clojure first before porting them to Ruby. I'm very pleased with the quality of the Ruby code I've produced after doing this.

> the language tries to drive me to the cleanest solution

This is really appealing to me. I've hacked a bit with Ruby (One Month Rails and some other tutorials), but I'm not sophisticated enough to know instinctively how to refactor towards "clean" or "elegant." Most of my code is pretty ugly, and gets uglier the longer I work on it, since when I'm hacking on something without guidance I spend a lot of time just trying not to break things. Is there a good resource for a non-programmer to start learning Clojure? The syntax is a bit scary to me, but I just think back to when I first learned about programming and figure diving in will eventually make it read more sensibly to me.

Also, being connected to a live REPL seems pretty valuable for learning.

Clojure From the Ground Up http://aphyr.com/tags/Clojure-from-the-ground-up is a good resource, and there's also my own Clojure for the Brave and True http://www.braveclojure.com/ . I actually started by going through "Land of Lisp" first. Though it covers common lisp, not Clojure, it's a very fun book.

edit: Realm of Racket is also a good lisp book, and a lot of people like "the little schemer". It's hard for me to say how good these are for people completely new to programming, though.

Finally, there's the ClojureBridge curriculum, which is targeted at new programmers: https://github.com/ClojureBridge/curriculum

Thanks, I'll check them all out. I've been playing with languages for a few years now and built some really tiny, throwaway stuff. I'd say I grasp the basic concepts of programming pretty well (by basic I mean the very basic), but I still very much feel new to programming. I started with Ruby because it's accessible, but ever since I've learned about them, I've wanted to eventually learn a Lisp.

Clojure feels like a 'compromise' Haskell, but I mean that in a good way. Haskell really wants to pretend that everything is a pure function. But I think this is a case where the conceptually simpler thing (i.e. no state) is just too hard to reason about.

Clojure backs off the 'referential transparency ONLY' philosophy, and merely discourages mutability. In my (limited) experience, this gives almost all of the advantages of Haskell, but an environment that's easier to program in.

So yeah, I'm excited about Clojure too. I just wish we could port it off the JVM...

You can still do state using the state monad.

> this gives almost all of the advantages of Haskell

except one of the biggest ones - the type system. Obviously this is subjective though. Some people prefer dynamic typing :)

I'm a C# guy at work, I also do some front-end in javascript (with angularjs sometimes). For side-projects I like to use node.js. I want to learn another language, and I've been wondering wether I should go with Clojure or C++ ? My dilenma is "Do I want to learn more about programming style running on VMs (functional) or do I want to dive into barebone high performance code ?"

I've done C and Java at university, but that was a while ago.

Anyone has a comment?

I'm a C# guy at work too. I can't say I've touched much C++ outside of college also a while ago, but I've been studying functional programming for a while and really enjoying the new concepts it teaches. It can be a bit humbling at times though.

I got some good perspective with https://www.coursera.org/course/proglang and you could do worse than taking grossman's excellent course. It helps to have some structure and a schedule when starting imho.

I will admit at times I wish I had more chops (closer to the metal i.e. C or C++), but I think I was eventually just more interested in new ways to think about programming, and I'm not sure I'd get the same pleasure out of digging back into C++.

Obviously, if you know something more about your intended use case (i.e. you want to program games), you can make a more informed decision.

For some reason the Programming Languages class is offline now.

That sucks, sometimes the just let you watch all the videos even if the course isn't running. Wonder why different courses have different policies

Did you take a look at F#?

Yes, but I'd like to get off the CLR.

> Plus, whenever some interface I've built feels awkward or there's some duplication, often times I find that, while thinking and trying to refactor it, the language tries to drive me to the cleanest solution

Yes, this is my exact feeling when I'm still learning it :)

I'd heard from other Ruby developers that learning Clojure is difficult but ultimately rewarding. That was my experience as well. All of my side projects are written in Clojure.

The reason I end up with Python, CoffeeScript or Ruby and not a Lisp is the prefix notation and the parentheses.

The parentheses can decrease readability and the prefix math expressions can make the order in which you think up a solution awkward.



The benefits of lisp 'syntax' are legion, to the point that I've come to feel that your position is unprofessional. Why wouldn't you try to get passed something as superficial as syntax, in order to better _make_ stuff?

1) Easier to learn and remember syntax for polyglots. No more Googling, shit like "what was the syntax for try-with-resources or the new multi-catch feature in java"?

2) The language tooling is so much easier to get right. The parser for Ruby is 10k lines. What the actual fuck? How can you expect people to make good tools if they can't get past the parse step?

3) Macros!

4) No fucking precedence rules. I don't want to memorize that the precedence for 'and' and && is different in Ruby and how 'and' interacts with the precedence of other operators like assignment.

5) Structural editing.

I might have forgotten a few, but 2) and 3) alone are killer features.

Julia [1] has 3 and 5, and almost 1 (it has very few built-in syntax sugars and a uniform way of invoking macros). It's targeted at scientists, so 4 is not an option, as infix syntax is a hard requirement for mathematics.

[1] http://julialang.org/

Edit: Elixir [2] is homoiconic as well, with even more uniform syntax (though it doesn't have special matrix syntax).

[2] http://elixir-lang.org/

Elixir is not homoiconic. They used to claim that based on a very unusual definition of homoiconicity, but they have removed those claims from their materials.

But Julia is, or not? If yes, why? (The only difference, as far as I can see, is that Julia AST is considerably simpler than Elixir's (a Julia struct with 3 fields, only two of which need to be present: head and args). Though admittedly, that counts a lot.

+1 for Elixir, really excited about it. Especially knowing it is built (like Clojure) on a very solid battle tested VM.

I have done quite a bit of Python hacking, as well as Javascript and Ruby. You really do get over the parentheses thing. In fact it more or less becomes a non-issue after a few days. It just is not something that should make you decide against a language.

The only time it becomes a major issue is if you are nesting many functions, but in that case the threading function is both utilized often and quite elegant.

Instead of:

    (fun3 (fun2 (fun 1 "string")))

    (-> "string" fun1 fun2 fun3)

I'd argue they're only "awkward" because you aren't used to them.

I don't know about Clojure, but you can usually use an infix reader in common lisp to get around that.

What's more, because one can macroexpand on the fly, you can actually see the code that it transforms into.

Man. I know Lispers hate hearing about it, but I was so on board with this until the sample ClojureScript code and all the parens. I just… don't wanna write code like that.

Something that may make it easier to accept all the parens is that that very thing is part of what enables some of the good stuff. You're essentially writing your programs directly as an AST (abstract syntax tree, http://en.wikipedia.org/wiki/Abstract_syntax_tree). That is what makes it so natural to write macros that manipulate your own code on the same level that a compiler does.

That realization may not make the code any easier to read at first, but it may make it easier to accept it.

I felt the same way as you until I actually tried Clojure. In a few hours all my rejection of the parens dissapeared because I finally understood.

Try solving a small problem in Clojure (a code Kata, or a problem from Project Euler) and you'll see those aprehensions against the parens will go away.

Nowadays I'm having trouble to accept the syntax of other languages, eg. Scala :-)

Everything in life a tradeoff. You should watch this video: http://www.infoq.com/presentations/Simple-Made-Easy

The parens are annoying, until:

a) You build that fully composable library that you always wished you could have written in X language, but it neeeeever quite worked the way you wanted.

b) You realize that by keeping your data immutable, it allows you to write less tests, be more confident in your code, and you stop worrying "is that value is what I think it is?"

c) By building on top of the JVM, you are able to use java interop to save yourself a day of coding a custom library for something that exists and is well tested.

d) Deployment becomes a breeze because you just export a jar/war file and load it up into any of the existing app servers.

e) You get phenomenal speed increases for "free" if you're coming from dynamic languages like ruby/python/PHP

f) When you need to dip into async code, you can write your async code, in a synchronous fashion, which (for me) is much easier to think about then keeping track of callbacks in my head.

Good luck, if you decide to give it a shot, I think you might realize the parens isn't such a big deal in the long run!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact