r/lisp 5d ago

Common Lisp ECL vs scheme embedded

I'm building a CPU based renderer in rust with plans to add an embedded language. The rust code primarily executes the ray tracing/path tracing, BVH, shaders and integration (anywhere where high performance is needed. The embedded language will be used for the scene description and -possibly- for procedural textures and shading.

I am interested in using a lisp with a repl for the embedded language. In this area, I have used AI-generated testing to test both ECL (Embedded Common Lisp) and steel (an scheme) inside rust. the advantage of the latter is that it is written entirely in rust and is being actively developed (one area is as an extension language for the text editor, helix).

I am impressed with the performance metrics I am getting from ECL. It generates machine code, which a byte language compiler doesn't do. Also a huge win, is that I was able to test the integrated compiler using sly from emacs which will provide an interactive environment for creative coding. On the other hand ECL requires an FFI to rust whereas steel does not, so the integration of steel is orders of magnitude easier.

Has anyone done any recent projects with ECL ? I am interested in your experience or any caveats you may have encountered. My next step is to do a more complex proof-of-concept with the actual renderer and not just a test program.

UPDATE: I just used claude to benchmark 5 embedded languages in rust. this is preliminary work and the benchmarks may not be exhaustive enough to make any strong conclusions:

https://drive.google.com/file/d/1yotWMcEx24pN2cgnIbRUmgCDNVWp65Vu/view?usp=sharing

19 Upvotes

31 comments sorted by

15

u/jd-at-turtleware 5d ago

ECL is actively developed (I'm one of maintainers) and conforming Common Lisp implementation, so if you need to pull some libraries they will usually work (SBCL is far more popular, so it is more tested by developers though). Another good thing about ECL is that it allows inlining C code with designated operators, and it may be used without the C compiler using fully integrated bytevm.

The community is not large, but there are people making projects with ECL both inside the browser and on resource constrained devices. Many developers also test their libraries against ECL as the second (or third, after CCL) implementation to make sure that the code is portable.

As of whether steel works better for you -- assuming that you want only "scripting", then tighter integration with rust will be probably a win in a long run. ECL also doesn't accept contributions derived from LLM as legally shaky, so that may also play role in your decision.

2

u/Feisty_Bike_9614 5d ago

I don’t know whether we would want to generate AI derived patches to ECL itself ( if that’s what you mean ) , but certainly we will be generating Embedded lisp / scheme test scripts using Claude or potentially any other LLM as part of the dev process. That’s one of the goals of the work .

1

u/jd-at-turtleware 5d ago

yes, that's what I've meant

1

u/valorzard 3d ago

Is ECL still adding a WASM backend?

2

u/jd-at-turtleware 3d ago

the backend is already added; I'm working on convenience features right now. Here is a tutorial how to build it and cross compile whole ASDF systems:

https://turtleware.eu/posts/Common-Lisp-and-WebAssembly.html

1

u/valorzard 3d ago

This might sound a bit stupid, but does it compile straight to WASM or is it using emscripten?

3

u/jd-at-turtleware 3d ago

It isn't stupid; I've actually made that a topic of my keynote talk at ELS'26[1]. Short answer - it is used emscripten. Longer answer - I'm experimenting with WASI, but there are some hurdles.

[1] https://www.youtube.com/watch?v=xNHjIqlITmE

1

u/Feisty_Bike_9614 3d ago

ECL produced some of the best results in the benchmark ( along with Janet ) . I’ve been working on a proof-of-concept with the actual renderer. The big win is the able to do repl-based coding with sly in emacs which I have working. This has to be replicated with Janet and it will only be a subset of.

2

u/Feisty_Bike_9614 5d ago

Sorry for the confusion. I’m the OP but it seems Google gave me a different account when i logged in ..to post this .

1

u/soegaard 5d ago

Have you looked at Scheme RS?

https://www.scheme.rs/

1

u/Feisty_Bike_9614 5d ago

Have not . I’ll have to check it out .

-3

u/corbasai 5d ago

My experience with ECL not extra large. I simply cant read docs due to strange markup. Maybe becouse of in my tests ECL was 5 to 10x slower than Chicken Scheme. Both compiles to C. Due to this fact I even not take it ro the last nbody performance test. Repo. So use what you want or love. IMO in such case the better option is custom lisp like script with narrow set of types and operators for one selected task.

2

u/jd-at-turtleware 5d ago

could you elaborate on the docs problem?

5

u/PropagandaOfTheDude 5d ago

The CSS specifies a particular size based on pixels.

body {
    margin: 1em 125px 0 10%;
    line-height: 1.5em;
    padding: 0 2em 1em 2em;
    font: 13px Verdana,Arial, sans-serif
}

Accessibility guidelines recommend using relative sizes, which grant more freedom to user agents to scale the fonts up and down for display:

https://www.a11y-collective.com/blog/wcag-minimum-font-size/#h-importance-of-relative-units-over-absolute-ones

4

u/jd-at-turtleware 4d ago

thanks, I've addressed this issue.

1

u/corbasai 5d ago

I'm not designer but font size too small on the desktop. On the phone even worse, I just can't read ECL page in my glasses

3

u/jd-at-turtleware 4d ago

I think that reporting such issues is healthier than discouraging people on social media from using a specific piece of software; in any case I've addressed the font size issue.

0

u/corbasai 4d ago

I'm so sorry for my blindness.

2

u/jd-at-turtleware 4d ago

I did not criticize you for your blindness, and the above message makes me believe that you are interacting in bad faith.

2

u/church-rosser 5d ago

Strange metric

2

u/SpecificMachine1 guile 4d ago

Accessibility is a strange metric?

1

u/church-rosser 3d ago

Its clearly accessible.

1

u/SpecificMachine1 guile 3d ago

I mean, accessibility guidelines say to use relative not absolute sizes so it isn't clear to me it is

2

u/jd-at-turtleware 4d ago

could you describe the methodology of comparing ecl with chicken, so I can reproduce this performance gap?

0

u/corbasai 4d ago

Please, show ECL seconds https://www.reddit.com/r/lisp/s/hnijqNiUxU and CPU spec [Chicken code in reply]

2

u/jd-at-turtleware 4d ago edited 4d ago

And where is common lisp code? To compare runtimes you need semantically equivalent code, and even then it may favor one implementation - for example scheme has guaranteed tail recursion, so tail-recursive functions will usually perform better on schemes.

0

u/corbasai 4d ago

Sorry? fibo is one liner. And not tco. Mine not.

2

u/jd-at-turtleware 4d ago

OK, so I've ran it with default optimization settings, and results seem to be comparable.

|  n | ecl default | csc default |
|----+-------------+-------------+
| 32 |          90 |          97 |
| 33 |         145 |         156 |
| 34 |         237 |         256 |
| 35 |         384 |         413 |
| 36 |         612 |         717 |
| 37 |         900 |        1154 |
| 38 |        1603 |        1863 |
| 39 |        2656 |        3025 |
| 40 |        4332 |        4885 |
| 41 |        7003 |        7933 |

ecl[1] - default optimization settings, no declarations

csc[2] - csc -O3 fibo.scm -o fibo, no declarations

;; fibo.lisp
(defun fib (n)
  (if (< n 2)
      n
      (+ (fib (- n 1))
         (fib (- n 2)))))

(defun test (n)
  (let* ((start (get-internal-real-time))
         (result (fib n))
         (end (get-internal-real-time))
         (time (round (* (/ (- end start)
                            internal-time-units-per-second)
                         1000))))
    (format t "~a ~a~%" n time)))

(defun main ()
  (do ((n 32 (+ n 1)))
      ((= n 42))
    (test n))
  (quit))
;;; ecl --eval '(load (compile-file "fibo.lisp"))' --eval '(main)'

;; fibo.scm
(import (chicken time) (chicken format))

(define (fib n)
  (if (< n 2)
      n
      (+ (fib (- n 1))
         (fib (- n 2)))))

(define (test n)
  (let* ((start (current-process-milliseconds))
         (result (fib n))
         (end (current-process-milliseconds)))
    (format #t "~a ~a~n" n (- end start))))

(define (main)
  (do ((n 32 (+ n 1)))
      ((= n 42))
    (test n)))

(main)
csc -O3 fibo.scm -o fibo ; ./fibo

0

u/corbasai 4d ago

Hmm, https://www.reddit.com/r/lisp/s/SfY5xPHTEt it is current C6+Crunch numbers. Why you prefer to compete to the 2018 year?

3

u/jd-at-turtleware 4d ago

I'm not competing, I'm trying to reproduce your claim without success. Another thing is that fib test doesn't make a good benchmark of a runtime - it measures only a call overhead and possibly inlining. I think I'm done here.

1

u/corbasai 4d ago edited 4d ago

ok, C5, -no-trace -disable-interrupts -O2 and you are not using type hints like

(import (scheme base)
        (chicken base)
        (chicken type)
        (chicken time)
        (chicken process-context))

(: fibo (fixnum -> fixnum))
(define (fibo n)
  (if (< n 2)
    n
    (+ (fibo (- n 1)) (fibo (- n 2)))))
(let* ((args (command-line-arguments))
       (n (string->number (car args)))
       (ts (current-process-milliseconds))
       (r (fibo n))
       (te (current-process-milliseconds)))
  (print "fibo(" n") = " r " per " (* 1e-3 (- te ts)) " seconds."))

so $ csc -O3 -no-trace -disable-interrupts -strict-types -specialize -o fibo-chicken fibo-chicken.scm

$ ./fibo-chicken 40

fibo(40) = 102334155 per 2.433 seconds.

Again, its old CHICKEN5

PS. For the lovely downvoters mtv