HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
marcoheisig
fast-generic-functions
Common Lisp2021–2026
marcoheisig / fast-generic-functions

fast-generic-functions

Seal your generic functions for an extra boost in performance.

5Distinct people
7Mentions
0Explicit recommenders
112GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Seal your generic functions for an extra boost in performance.

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 5:04:57 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year7 dated mentions

Observed mentions: 2021-04-11 00:24:05 UTC to 2026-02-25 08:49:57 UTC.

01232021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20212022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments20232024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC101
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC000
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC000
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC303
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC202
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC101

What Hacker News says

7 sources
>For example, it cannot specialize an element type for lists. Yes, but that would be a CL violation (or an extension to provide via something else than DEFTYPE), since DEFTYPE's body can't be infinitely recursive; cf https://www.lispworks.com/documentation/HyperSpec/Body/m_def... >if you attempt to (declaim) every function, you will immediately see how vague and insufficient the types come out compared to even Python. Indeed, but 1) it is used by the compiler itself while cpython currently ignores annotations and 2) runtime and buildtime typing use the same semantics and syntax, so you don't need band-aids like https://github.com/agronholm/typeguard But yeah, CL's type system is lacking in many places. In order of practical advantages and difficulty to add (maybe): recursive DEFTYPE, typed HASH-TABLEs (I mean the keys and values), static
Read the rest
typing of CLOS slots (invasive, like https://github.com/marcoheisig/fast-generic-functions), ..., parametric typing beyond ARRAYs.
In Steel Bank Common Lisp
> Thing is that you need a complex JIT like Julia's or stuff like https://github.com/marcoheisig/fast-generic-functions to offset the cost of constant dynamic dispatch. Julia is always the odd one out, when talking about dynamic vs. static dispatch, because its JIT compiler acts more like an Ahead-of-Time compiler in many regards. In the best case, types are statically decidable and Julia's compiler just produces a static dispatch and native code like e.g. a C compiler would. In the worst case, there are a big (or unlimited) number of type candidates. The grey area in between, where there are a limited number of type candidates, is interesting. As far as I understand, Julia does something similar to the link you provided. Based on some heuristics it will compile instances for a "sealed" number of candidates and fallback to a fully dynamic
Read the rest
dispatch, if there are two many type candidates. At JuliaCon 2025 there was an interesting talk about this topic: https://m.youtube.com/watch?v=iuq534UDvR4&list=PLP8iPy9hna6S... For the worst case scenario, Julia chooses what's in my regard the nuclear option: If the types are not decidable, it just ships the whole compiler with your code and tries again at runtime. But I guess, that's not the only possible solution. Presumably, it would also be possible to fallback to a Julia interpreter for dynamic code. That would be more similar to what JavaScript is doing, just the other way around. Instead of interpreting the majority if the code and optimising hot paths with a JIT, our alternative Julia would compile most code statically and use the interpreter for the dynamic parts.
In SPy: An interpreter and compiler for a fast statically typed variant of Python
Common Lisp doesn't use (expensive) CLOS dispatch in the core language, e.g. to add two numbers or find the right equality operator. That's one known pain point due to CLOS having been "bolted-on" rather than part of the language which makes the divide between internal (using typecase and similar) and external (generic functions) dispatch pretty ugly; and gave use the eql/equal/equalp/etc... hell. Thing is that you need a complex JIT like Julia's or stuff like https://github.com/marcoheisig/fast-generic-functions to offset the cost of constant dynamic dispatch. I actually had such a conversation on that comparison earlier this year: https://lwn.net/Articles/1032617/
In SPy: An interpreter and compiler for a fast statically typed variant of Python
> I'm sadly not very well versed with this alternative to OOP. But something tells me that a more "basic" and less dynamic scheme like that is probably best for performance reasons, since you'd either need a Julia-like JIT or a granular "dynamism knob" like https://github.com/marcoheisig/fast-generic-functions to truly amortize the cost of CLOS-like dispatch and polymorphism; though magic can be done, as the "Fast generic dispatch for Common Lisp" paper shows. You know, for someone who isn't "well versed" with it, you certainly nailed exactly why I chose it. Also, simplicity. The "as easy as Python" is only possible if I remove complecting [1] things like inheritance. > Huh! If this includes types deduced by compiler inference and not just user declarations (since Yao seems gradually typed, to my eyes), that'd be pretty impressive. It doe
Read the rest
s, actually. But Yao is not gradually typed, unfortunately. Too complecting. [1]: https://www.youtube.com/watch?v=LKtk3HCgTa8
In Rewriting Rust: A Response
> However, Yao will not have inheritance; instead, it will be more like Go: composition over inheritance. And interfaces. So I could be wrong, but without inheritance, I'm not sure the entire complexity of the CLOS is needed. Do correct me, though. I'm sadly not very well versed with this alternative to OOP. But something tells me that a more "basic" and less dynamic scheme like that is probably best for performance reasons, since you'd either need a Julia-like JIT or a granular "dynamism knob" like https://github.com/marcoheisig/fast-generic-functions to truly amortize the cost of CLOS-like dispatch and polymorphism; though magic can be done, as the "Fast generic dispatch for Common Lisp" paper shows. > if those are just for giving info to macros, Yao already has that Huh! If this includes types deduced by compiler inference and not just
Read the rest
user declarations (since Yao seems gradually typed, to my eyes), that'd be pretty impressive. Hope you'll be able to keep your spirits high, this is a lifetime's work you seem to be looking forward to ;)
In Rewriting Rust: A Response
(Talking about CL) Isn't gradual typing with a typed standard library enough? Because that's kind of what SBCL provides. Anyway, some other reasons: * Baby ducks who can't get over the parentheses (which quickly become invisible to the eye, you read Lisp via its indentation). * Baby ducks who can't get over too weird/big differences from C/C++/C#/Java/etc... like CL's compilation model. * ML typing being /the/ fad these days. * Low-level fetishism. I know a lot about this, since I've had my own C weenie phase (you know, the kind to spit on GC by principle) as a young university student, before turning smug lisp weenie ten years later; Tcl was actually my gateway drug into useful homoiconicity. * Some hard technical limitations: * No user accessible parametric deftype. * No recursive deftype (so no typed lists/trees). * Gimped hash
Read the rest
tables (untyped, lacking literals thus read/write transparency). * CLOS being bolted on instead of truly integrated in the language; would need a JIT and something like https://github.com/marcoheisig/fast-generic-functions on system classes to go fast enough, Julia kinda does this (but it hurts my eyes). * Lack of LSP; no, SLIME/Sly isn't the same, as you're lacking lexical information that allows to complete/rename stuff. * And hundreds of other rust spots sometimes fixed by extensions (e.g. gray streams, extensible sequences) or libraries (loop -> iterate, trivia), very often crutches in look and feel.
In If Lisp is so great
> SBCL has two interpreters, IIRC. You can configure SBCL to use an interpreter. SBCL's original "interpreter" is %simple-eval, which just calls the compiler. SB!EVAL was added sometime around 2008, but as you point out it is not used unless you set evaluator-mode to something other than :compile. The default code path goes through %simple-eval and the compiler. I have been using SBCL since before SB!EVAL was added, and I have never used the interpreter. > ECL has three ways to run code: an interpreter, a byte code engine and a Lisp-to-C compiler The confusing thing about ECL is that someone decided to call their bytecode VM an "interpreter." ECL has no interpreter - eval_nontrivial_form just calls the bytecode compiler. All that is irrelevant to the fact that ECL uses GCC as a JIT. > In theory one could use a JIT to compile the byte code
Read the rest
s to native code at runtime. Which would be completely pointless because GCC (or clang or MVCC, but the original question was about libgccjit) is already there and does better optimization. > Some experiments of improving CLOS speed at runtime (similar to what Julia does) might be considered to be a moral equivalent of a JIT Like half of the PCL is devoted to various kinds of caching that are in fact adaptive optimization. It is not a big step from that to inline caching. But again, why would you do that when you don't need to? https://github.com/guicho271828/inlined-generic-function https://github.com/marcoheisig/fast-generic-functions There is a reason Mozilla went from tracing (TraceMonkey) to inline caching (JägerMonkey) to type specialization (IonMonkey). JavaScript JITs have moved closer to Lisp compilers, not vice-versa. I have covered other misconceptions that you have listed elsewhere in this thread.
In GNU lightning: generates assembly language code at run-time

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.