
Switching from Common Lisp to Julia - fanf2
https://tpapp.github.io/post/common-lisp-to-julia/
======
reikonomusha
1\. The standard doesn’t guarantee double float arrays will be efficient.

Most implementations do it (CCL SBCL CMUCL ECL LW ACL SCL ...), except for a
few unpopular implementations. Seven do what you want, but a couple don’t.
What gives? Julia has neither a standard nor more than one implementation.

2\. No efficient parametric/ad hoc polymorphism.

You can get far with inlining. You can also use libraries specifically built
with this in mind. But you’re right, it’s not a built-in feature. But
scientific codes are generally not super polymorphic anyway. Look at all the
FORTRAN.

But besides that, Lisp let’s you build the language you want to use, and have
it interoperate for the rest of the ecosystem. If you are surprised that
building a language is work, then Lisp may not be the choice for you. If
you’re willing to design the language you want for numerical computing, Lisp
has the essential data types and primitives to allow you to do that, even
portably.

If you want off-the-shelf features of Julia, then using Julia is more optimal
than Lisp. If you want a language that will readily adapt without changing
under your feet, without risking your programs not working 2, 10, or 25 years
from now, then Lisp might be a good choice.

~~~
shiro
> Lisp let’s you build the language you want to use, and have it interoperate
> for the rest of the ecosystem.

I suspect this strength of Lisp could have undermined improvement of Lisp
compilers in long term. That is, the fact that programmers can customize the
language to run efficiently for their applications put less pressure to make
the existing compiler better, compared to the languages that don't give
programmers such flexibility.

I've worked on performance-sensitive commercial Common Lisp applications. We
employed heavy macrology so that optimal instructions were generated in the
performance critical regions. Effectively, it was reimplementing part of the
compiler to deal with out domain-specific meta information such as
parameterized types. It worked, but came with the cost of maintenance--as if
we were maintaining another layer of the compiler. It was a burden. I'm sure
there have been such effort spent in many other places and eventually
abandoned.

Meanwhile, languages that give less power to the programmers, put lots of
efforts to improving the compiler and/or the language that work more
effectively with the improved compiler, and over a few decades, they have
quite sophisticated compilers.

I still mostly use Lisp-family languages at work, but sometimes wonder if the
power could have adverse effect in long term.

~~~
flavio81
This is an excellent reply and I think it goes to the crux of the problem you
were facing.

Perhaps, then, Julia makes sense in those cases.

Or, it's time for an enhanced Common Lisp implementation targeted specifically
for scientific computing. I agree that one thing is "extending the language"
and other is "implementing things that the compiler should have given me. "

~~~
reikonomusha
SBCL is already suitable for scientific computing. All that's needed are good
engineers who can write good libraries.

------
bluefox
The author mentions trouble with portability and reliance on standard
guarantees, and then goes on to talk about Julia, a single-implementation
language that is "rapidly evolving" with breaking changes and no standard to
speak of?

~~~
bitwize
Single implementation > standard clusterfucks. Look at Java, Perl, Python,
Ruby, Php, etc., vs. CL, Scheme, C, C++...

~~~
pjmlp
Any language that actually matters in the market reaches a point where it has
multiple implementations.

~~~
sgt101
I don't remember Java going down this path. Also the Julia license is very
permissive which undermines the commercial case for, and removes the community
imperative for alternate implementations.

~~~
pjmlp
Java always had multiple implementations since the early days.

That was one of the ways how Sun made money with it, by certifying
implementations for the trademark symbol.

------
varjag
> The standard does not guarantee that this gives you an array of double-
> float: it may (if the implementation provides them), otherwise you get an
> array of element type T. This turned out to be a major difficulty for
> implementing portable scientific code in Common Lisp.

Wouldn't sticking to say SBCL (that does give you specialized arrays) be
equivalent to using a one-implementation language that does the same?

~~~
frivoal
For yourself, maybe. If you intend to share the code you write (or use code
written by others), then implementation differences start to matter.

~~~
varjag
In case with lack of specialized float arrays, the worst that is going to
happen is performance degradation. It's not like they are some non-standard
extension.

------
nextos
Slightly off-topic, but what's your preferred stack for developing data-
intensive applications that involve a lot of preprocessing, heavy statistics
and machine learning plus a web front-end?

Julia sounds quite appealing as a replacement for MATLAB or R with some Dylan-
like semantics plus types and really efficient code generation on LLVM. I wish
the Racket - Chez merger lead to something that targeted LLVM to be able to do
front-end and back-end stuff using Scheme.

A JVM-centric stack is one of my preferred alternatives. Clojure is great for
data preprocessing and manipulation, plus ClojureScript for coding all front-
end. Datomic, core.spec, core.logic, anglican, plumatic.plumbing just to name
a few are a joy to use. Then there's Scala, which is also a great asset, and
tons of fantastic Java / Scala libraries like Stanford NLP, Markov Logic
Networks (Tuffy, RockIT...), Factorie, Deeplearning4j, etc. Sadly, Scala-
Clojure interop is not very good.

Python is the other obvious option, with tons of good libraries, including a
fantastic data analysis ecosystem built around NumPy, SciPy, Matplotlib and
Pandas. Plus most deep learning libraries targeting Python first. I just feel
the language doesn't scale that well, although things like Numba or Cython
help.

~~~
lasfter
Have you considered Lua? You can develop web apps with Lapis [1] and do your
data analysis with Torch [2].

The tradeoffs compared to Python: LuaJIT is much faster, which should ease
your scaling worries, but the ecosystem is not as developed.

[1] [http://leafo.net/lapis](http://leafo.net/lapis) [2]
[http://torch.ch/](http://torch.ch/)

~~~
aldanor
It’s really not fair to compare CPython with LuaJIT.

If you compare LuaJIT with PyPy or Numba, the “much faster” argument will
simply not be true. What’s different is that both of the above only cover a
part of the language, but for specialised (e.g. numeric) application that’s
often not a problem.

~~~
shakna
LUAJIT is often on par with C. How would that make it slower than Pypy?

------
flavio81
Note: I generally applaud Julia, it was designed taking many good choices.

However, I really don't understand how the author complains that CL doesn't
"have" certain features that in fact _are_ available by choosing a suitable CL
implementation. But no, he prefers switching to a language with no standard
(yet) and only one implementation...

~~~
baldfat
He mentioned that they have them it is that they are just not updated or
standardized since there are one person developing the library.

------
flavio81
_> "The standard does not guarantee that this gives you an array of double-
float: it may (if the implementation provides them), otherwise you get an
array of element type T."_

Well, many Common Lisp implementations, which includes most of the famous ones
like SBCL, CCL, and ABCL, will give you exactly...

... an array of double-float!!

So where is the problem?

 _> "However, this gets worse: while you can tell a function that operates on
arrays that these arrays have element type double-float, you cannot dispatch
on this, as Common Lisp does not have parametric types."_

Well, there are many options. First, let me reiterate that an array of a
certain element type, stays of that element type. Example:

    
    
        CL-USER> (defparameter *a* (make-array 0 :element-type 'double-float ))
            *A*
        CL-USER> (type-of *a*)
            (SIMPLE-ARRAY DOUBLE-FLOAT (0))
    

I'm going to give the simplest, quick&dirty options:

If you're using arrays of different element-types, option A is write your
function and just use the ETYPECASE function to do the dispatch according to
the element type, so you can ensure that you select the code correct to the
element type. Use the DECLARE declaration specifier so the Lisp compiler knows
which type is your array /array elements and thus the machine language code
produced is optimal.

Option B is simple, just define classes or structs, one for each array type
you intend to use; and then take advantage of CLOS dispatch so invoking the
generic function dispatches to the correct code for each array.

These are two options which don't even need any macro solutions; there are
many more options as well, i'm just proposing two.

Option C, more elegant, could be perhaps using Fare's "LIL" (Lisp Interface
Library)? [https://common-lisp.net/~frideau/lil-ilc2012/lil-
ilc2012.htm...](https://common-lisp.net/~frideau/lil-ilc2012/lil-ilc2012.html)

I really think Julia is a nicely designed language, and is a language I often
tell people to take a look at. However, if the author already has a program in
Common Lisp, and has good experience of Common Lisp (which, by the way, means
the author might be a quite skilled programmer), why not dig deeper into the
facilities that Common Lisp brings to solve those problems?

NOTE: This is an edited version of the comment i left on the page.

------
ACow_Adonis
Keeping in mind that Julia appears to be very very close to common lisp, some
minor differences that you appear to lose going over:

\- 1) lisp 1 vs lisp 2

\- 2) Matlab syntax (y tho?), infix, and sygils everywhere

\- 3) Clos and metaobject protocol and ability to adjust these as easily at
run-time

You do appear to gain some things though in all honesty. I'm trying to program
up an dataframe/analytics type program/library in Common Lisp as we speak, and
I'll admit, getting that stuff right and efficient is hard work. Gives you
immediate respect for anyone who has done the same in other languages.

Additionally:

\- 1) Parametric types and dispatch on them

\- 2) Potentially inlining and compiler optimisations and integration around
their generic functions. My gut says SBCL would need some compiler magic and
metaobject protocol type stuff to do the same, and it would no longer be
standard Common Lisp. That's not necessarily a bad thing, there are some warts
around in-builts/objects/generic functions in Common Lisp, but it would be a
fracturing of the community to update/change them.

~~~
nextos
MATLAB syntax is pretty convenient for linear algebra. It makes things very
readable.

Maybe Julia should be seen as an infix typed Lisp DSL for math. It'd make a
good stack (see my other comment) with Clasp or any other Common Lisp that
offers good bindings to LLVM.

~~~
reikonomusha
CL-INFIX [0] gives you infix syntax in Lisp a la carte.

[0] [https://github.com/rigetticomputing/cmu-
infix/blob/master/RE...](https://github.com/rigetticomputing/cmu-
infix/blob/master/README.md)

------
ChrisRackauckas
The problem I have with Lisp for scientific computing is that libraries
matter. You really want to standardize not only what you are calling but also
your notation because most of the people that you want to use the libraries
are scientific domain experts and not "programmers": they may know like 20
functions and that's it (and that's fine!).

Lisps tend to love the "you can build anything in it! You can make all of your
own syntax in it!" and I think that goes too far. Julia lets you do this with
macros, but then there's a good convention to not overuse this. There has to
be a balance between being too structured (which hurts innovation) and too
dynamic (which makes it hard to learn someone's new library because everything
is too different), and I think Julia strikes the right balance.

------
_ph_
It is my biggest complaint with Common Lisp, that while the language supports
efficient optimization based on type information, it is often a bit cumbersome
to provide them. However, if you target is to write high performance numeric
code, you should consider SBCL first of all. It is excellent in using type-
information and has a very good type-inferencer, so the task is a bit easier,
and it produces excellent code.

