What about common lisp

LOOP is a DSL, the options of which I still don’t really know even after pretty broad exposure. Peter Seibel has a whole section just on loop recipes in Practical Common Lisp. Clojure just has loop / recur, or more simply, recur. I don’t see how something that is 1 special form that’s not a DSL takes longer to learn. Maybe the recursive aspect inherent to FP, as opposed to imperative looping?

1 Like

Why not call them out. It can help others know what to expect with those libraries, and it could inform their maintainers that they might want to be more careful with breaking changes if it causes real pain to their users.

Even if I did, other people would no doubt have other opinions. And this topic was about common lisp and not really suitable. I had some great years with Common Lisp, I’m having some great years with Clojure. Both have parts of the core language/runtime that I like, and that are different from each other. My original reply was a contrary opinion to another poster on the value of standards. Wielding the original CLTL silver book and programming in CL was a joy. Standards made that possible across multiple implementations of CL.

3 Likes

CL LOOP vs clojure iteration.

Back in the CL heyday, and I remember some of these moments decades later, I had times where I’d be coding madly expressing gnarly loops with CL’s loop, and thinking at the time how insanely great LOOP was while I was coding with it. Like many tools, it takes a bit of getting used to, and certainly there were a lot of people in the CL community who hated it as some kind of impure construct. But for me it was pure gold.

Fast forward to clojure, and if you’re using Clojure’s loop/recur, chances are you’re doing it wrong (IMO of course), speaking from personal experience. For example, many simple iteration tasks can be solved more simply with reduce. It took me some years to ease into that perspective though.

Having used Clojure for some years now I suspect I would look at looping in CL differently if I returned to it. Still, if I look at how quickly I can code complex iterations in either language, I was far faster using CL’s LOOP. Maybe it had more to do with youth than anything about the language :slight_smile:

4 Likes

Re: java.jdbc, Sean, I’m happy to report I have zero issues with it, and I use it all the time.

And now I must fold my reply to the OP here, because Clojureverse won’t let me post another as a new user.

  1. Common Lisp saved my bacon many times, making things possible that simply weren’t tractable with other languages (for many reasons.
  2. I used CL for real work and pet projects. I made money with CL solutions. There are people who still use CL for production solutions, though not many.
  3. The biggest pitfall of CL is that the language is ignored and won’t evolve. There’s every possibility that could happen with Clojure too someday, certainly there’s less traffic about it than when I started with it 7-8 years ago, or so it seems to me. These days languages come and go a lot more quickly.
  4. I’m not using CL now, I deliberately stepped away from it 20 years ago for my own reasons. I am definitely a bit nostalgic for it though, and for the right sort of task I might revisit it.
  5. Hmmm. Clojure nostalgic. Sure! I think if you’ve become proficient enough in either language to appreciate its strengths, you’ll be nostalgic for them when you move to another language that doesn’t have those strengths. I’m nostalgic for CL’s stuff, but I’d greatly miss Clojure’s fine points, as well as those coming from the JVM (I like java.util.regexp, for example, and clojure’s syntax for regexps).

Try it out, have some fun :slight_smile:

5 Likes

That’s fair. Sorry didn’t want to put you on the spotlight if you’d rather not cause debate. That said I do feel the topic of backward breaking changes is specifically one where it’s not a matter of opinion, a backward breaking change is very much a provable fact, show a test that worked before and is now broken with the new version. I guess you can argue if a backward breaking change was worth making or not, and that’s often opinion, but I fail to see how an actual breakage can be a matter of opinion… Though I guess one could argue some usage was never the intended use and thus it was an undefined behavior the client shouldn’t have relied on.

I have learnt Common Lisp, from a Clojure background.

Common Lisp has a good story with the compiler. You can disassemble a function with the logically named (disassemble function-name). Different settings are available with a declaration. On the safe setting the code is pretty good. On the speed setting the code, on SBCL, is not too far from what a C compiler can do.

Common Lisp has a different story on macros to Clojure. Common Lisp is a Lisp-2, and macros are culturally more of a thing than Clojure. If a mass of macros brightens up your life, then Common Lisp may be for you. Personally, having hacked through ‘Let Over Lambda’, I’m not so convinced.

People coming from Clojure should find Common Lisp OK. People who are parenth-phobic should try something else, because everything is parentheses.

Common Lisp has a comparatively poor story for deployment. Clojure can produce JAR files, Chicken Scheme transpiles to C before compiling to native code, but SBCL, for example, uses a dump of the compiled code, before adding even more code to make it executable.

Chicken Scheme’s “Hello world” is 140 KB on my computer. Common Lisp’s “Hello world” weighs in at 40 MB. The book ‘Practical Common Lisp’ suggests that the way to do Common Lisp deployment is to send them the source code.

You can use core compression and tree shaking to get that down to around 11mb supposedly. Bearing in mind that the resulting binary in sbcl will have the compiler and the full lisp environment available (in the non-tree-shaken version); I don’t think the chicken scheme example will (are you including the runtime, is there an interpreter or compiler bundled?).

1 Like

Sure, when you deploy a jar you expect a JVM for the host. So it’s not self-contained executables. Well since JVM is that much popular it is “as if” it was self-contained, but it’s unfair comparison for SBCL.

I’m pretty happy in Common Lisp land for now.
On one hand, sometimes you write some stuff and it is blazingly fast compared to my Clojure experience. On the other hand, you are just sad not having the hashmap syntax from Clojure when you have to deal with data (alist and plist seems archaic, CLOS class are cool but over verbose for simple use cases…). Another missing part it the stability and omnipresence of the Clojure sequence abstraction.
A Common Lisper will argue that I can have these features using libraries or writing some reader macros. As I’m doing side toy projects for now, I’m trying to stick to vanilla CL (except for cl-ppcre, once again clojure.core has a great regex facility).

I’m not a the deployment stage yet, but it seems to be a recurring issue in CL.

I really feel at home, SBCL, asdf and quicklisp are really sweet and lovely pieces of software, even if things are quircky sometimes, it’s OK, things are quircky in Clojure sometimes too.

3 Likes

With GitHub - clojure-goes-fast/clj-java-decompiler: REPL-integrated Clojure-to-Java decompiler you can do the same in Clojure. Though it’ll disassemble to JVM byte code.

1 Like

Thanks. I’ll give the compression thing a go.

Chicken Scheme, as I understand it, just produces the minimal amount of C to do the execution, here “Hello World”. This is then compiled with mingw. The only problem that I had was when I downloaded an old Chicken Scheme which was 32 bit, and my mingw was 64 bit, so it didn’t work. I guess that you need to get a modern chicken, or your goose is cooked (etc).

Thanks for the suggestion of compression as a way of reducing executable sizes. I’m using SBCL on Windows, and it doesn’t appear to have compression. Is there a way to add it back in, please?

Compression

You need to build sbcl from source, which is an interesting process from what I hear. I imagine that requires a zlib for windows to link to which is what’s used for compression. Hmm.

Another option is to load up WSL or WSL2 and try it there. related issue thread with suggestions

1 Like

Re: Francisking comments on deployment, I’m not sure you have really captured the essence of the packaging alternatives, but here’s some food for thought:

$ time lein repl <<< '(println "Hello world")'
nREPL server started on port 38455 on host 127.0.0.1 - nrepl://127.0.0.1:38455
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by mranderson049.orchard.v0v4v0.dynapath.v0v2v5.dynapath.defaults$eval4007$fn__4008 to method java.net.URLClassLoader.addURL(java.net.URL)
WARNING: Please consider reporting this to the maintainers of mranderson049.orchard.v0v4v0.dynapath.v0v2v5.dynapath.defaults$eval4007$fn__4008
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
REPL-y 0.4.4, nREPL 0.8.3
Clojure 1.10.1
OpenJDK 64-Bit Server VM 11.0.9+11
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (println "Hello world")
Hello world
nil
user=> Bye for now!

real    0m4.754s
user    0m6.316s
sys     0m0.396s

Vs:

$ time sbcl --no-userinit <<< '(print "Hello world")'
This is SBCL 2.1.6, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* 
"Hello world" 
"Hello world"
* 
real    0m0.009s
user    0m0.006s
sys     0m0.003s

Re: CharlesHD and regular expressions

Having been using clojure a lot in recent years, I just ported all Clojure’s regular expression functions to Common Lisp (it was rainy, I needed something to do).

Since both java.util.regex.Pattern and cl-ppcre both are based on perl regular expressions, it was pretty easy to port the clojure behavior. The only difference I found was on the string splitting edge cases. Otherwise they’re just about perfect clones of functionality with respect to the regular expression patterns, at least the the extent I worked toward in the port.

You can find it here, it isn’t up on quicklisp yet. https://git.io/JCItd

2 Likes

That is very much an apples to oranges comparison. You suppress userinit when you run sbcl, but with Leiningen you’re going to get two JVMs starting up and for lein repl you’re also getting the entire stack of nREPL starting up a server process and then, finally, it starts a REPL and reads the input…

A much better example would be:

$ time clojure -M -e '(println "Hello, World!")'
Hello, World!

real    0m0.659s
user    0m1.539s
sys     0m0.124s

Or, if you really want to compare an actual REPL reading and evaluating input:

$ time clojure <<< '(println "Hello, World!")'
Clojure 1.10.3
user=> Hello, World!
nil
user=>

real    0m0.794s
user    0m2.064s
sys     0m0.157s

Sure, it’s still “slower”, but you’re working with a platform – the JVM – that is heavily optimized for performance in long-running processes, not startup, but as you can see, lein repl's near-five-second time is not really representative of what actually needs to be executed.

3 Likes

What I suppressed was all the goodies my .sbclrc normally loads. So on that particular point it’s apples to apples in that neither clojure nor sbcl is using any “user content”, it’s just the base systems.

But yes, as I said, there are ways to cut down the amount of work each system is using. Since I never bother to start clojure via anything but lein, that’s how I did the example. [Correction, I thought I said it in my originally, but apparently I didn’t. I meant to say that both clojure and sbcl have ways to cut down the size of the system being startted].

I wasn’t really striving for apples to apples or pears to oranges or anything else. I was just showing that sbcl can be pretty lean and mean relative to jvm systems. In neither case was I attempting to optimize them. I was attempting to frame the discussion with a different perspective since it seemed to me the person I was responding to was framing the sbcl images as being somewhat unwieldy, and without chopping anything out of the image with the system build tool, it really isn’t that unwieldy, in my opinion.

The whole discussion is kind of funny to me. In 1986 when a 16 megabyte memory machine to run lisp was considered a major system, people complained about the slow startup time of lisp. Fast forward and now it seems like nothing, while at the same time people point fingers at java systems for startup time (so… not too many command line tools in java). In another 20 years no doubt we’ll laugh at how we felt about jvm startups.

1 Like

I’m going to spend 8 hours messing with a long running process, but dammit that extra 2s to get started just grinds my gears lol.

The flip side is the plethora of unixy command line infrastructure where people expect small instantaneous utilities that they can invoke zillions of times. You can still work around with special compilation (like native-image, save-world-and-die, lisp image stuff), but it’s sliding into a legitimate pain point. Either that, or adapt the utilities-first world view toward something compatible with long-running processes (like the old nailgun approach, of having a clojure server sitting around ready to eval, which is a hack but not a terrible one).

On the gripping hand, the view from Chuck Moore’s foxhole is that we are incredibly wasteful with our cycles. So we should be ashamed of how we’re blowing through resources instead of living within our means better (I would say exploiting existing resources even better though). There’s something to that.

2 Likes

Although I think that @Decweb is entirely correct that standards are good in the sense they make it clear how the language is supposed to behave, that’s consistent with @bsless’s point that specifications can be bad because they can retard improvements. It’s a tradeoff. A couple of years ago I wanted to work in a statically typed, type-inferencing functional language. I wanted to use Standard ML, which I had used years earlier and still feel very warmly toward. But I ended up using OCaml instead, because unlike SML, OCaml has an active community of users (though quite a bit smaller than Clojure, I’d say), and the language continues to improve, with development of new and old libraries. A recent history of SML by some of the authors of the language suggested that SML’s lack of popularity is at least partly due to challenges to changing its formal specification (section 9.3, “The non-evolution of SML”). It could be that if the SML designers had made different choices, the language could have continued to evolve, but I think this illustrates the tradeoff point.

(Clojure does have a sort-of, partial language specification; it’s composed of the docstrings. They’re not intended as a language specification, though, and they don’t go into the kind of detail that would specify all of the behavior of functions. Occasionally they are wrong, though about obscure functionality.)

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.