Fennel has actually convinced me that Lua and lisp have more in common than one might think. I don't know what the above comment was referencing, but I've always found beauty in lisp languages for having a primary datastructure that all others can be abstracted to. Lisp, classically, has list, clojure has sequences, and Lua/fennel has tables.
> Javascript is Lisp in C's clothes? On what basis?
On a lot of bases. Javascript has real lambdas, a sort of homoiconicity of code and data (hence JSON as a data format), also has the same dynamic take as lisps on "types belong to data". Rather than variables types belong to values. Brendan Eich's original idea was literally to "put scheme in the browser" and you can in fact pretty easily convert the Little Schemer to JS.
Saying two languages don't have much in common because they don't have the same syntax is a bit like saying we don't have much in common because we don't have the same hair color.
> a sort of homoiconicity of code and data (hence JSON as a data format)
I get that "sort of" was an attempt to hedge, but really, this isn't even close. Homoiconicity here would be if all javascript source files were valid JSON documents. A weaker version would be if it were common to use JSON to represent an arbitrary javascript program, but I've never heard of that, either. (For a good explanation of this weaker sense of homoiconicity, this stackoverflow page [1] is pretty good.)
To use Clojure as an example of a language that is homoiconic, you can take any Clojure source file, send it to an EDN parser (EDN being Clojure's equivalent of JSON), and not only will parsing succeed, but the result will be a complete representation of the program (you could execute it if you wanted to). In contrast, if you try to send JS to a JSON parser, you'll get an error as soon as it hits a function definition, or a for loop, or an operator, or whatever.
But MacCarthy's original LISP 1 and LISP 1.5 do not have real lambdas. The lambda feature parametrizes a piece of code as a function literal, but doesn't capture anything.
What they have is code parsed to a data structure, which is then susceptible to manipulation by the program before being executed. JS has some dumb textual eval, like the Bourne shell.
Javascript hotloading development setups are about the closest you can get to the REPL development loop outside of lisp. I'd imagine lua is similar if the embedding is set up for it.
Revise.jl in Julia (https://docs.julialang.org/en/v1/manual/workflow-tips/#Revis...) also gives a really neat REPL development experience. It allows tracking changes to any source code file, module, even standard libraries or the Julia compiler itself!
I hate to be that guy but a ton of languages have REPLs. The whole collection of smalltalks out there are basically an interactive environment. All of them forth languages do it too. Factor, Racket, LiveCode, there are so many. And for most of them, watching files and hotreloading is not how they do it.
Lisp killer features were GC, good data representation, first class functions. Lua has all that and more. But its being a "thin" library over the C runtime shows through the clothes.
Also, I do want to point out that despite very recognizable syntax, that's not the only thing that makes lisp lisp. Primary example of lisp-y syntax on a non-lisp would be Janet [0]
I have an intuition that the comment you're responding to has a lot of truth to it, but I am going to have to educate myself to give you an answer.
One thing I do know is that JS and Lisp both treat functions as first-class citizens, allow some degree of meta-programming, and rely heavily on hierarchical (e.g., nested objects in JavaScript vs. s-expressions in Lisp).
Passing functions by reference enables both LISP and JS to compose higher-order functions and, as suggested in another commented, both Lisp and JavaScript's "dynamic stack frames" somehow live updates to running code without requiring a complete restart of the application. The only clear example of this I can find, however, is Bun's --hot mode, which performs a "soft reload," updating its internal module cache and re-evaluates the changed code while preserving global state.
I have some vague notion that this is a favorite feature of Lisp, but it's not clear to me that it's unique to these language families.
---
Edit: Lexical scoping, closures, some tail-call optimization...
---
Edit 2:
> Programming language “paradigms” are a moribund and tedious legacy of a bygone age.
(Dave Herman)[0]
---
Edit 3:
> The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."
> Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
> On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
0x3444ac53|10 months ago
https://fennel-lang.org/
creata|10 months ago
Fennel is more popular than I expected! It's in the official repositories of Arch, Fedora and Debian.
cmdrk|10 months ago
Barrin92|10 months ago
On a lot of bases. Javascript has real lambdas, a sort of homoiconicity of code and data (hence JSON as a data format), also has the same dynamic take as lisps on "types belong to data". Rather than variables types belong to values. Brendan Eich's original idea was literally to "put scheme in the browser" and you can in fact pretty easily convert the Little Schemer to JS.
Saying two languages don't have much in common because they don't have the same syntax is a bit like saying we don't have much in common because we don't have the same hair color.
alex-robbins|10 months ago
I get that "sort of" was an attempt to hedge, but really, this isn't even close. Homoiconicity here would be if all javascript source files were valid JSON documents. A weaker version would be if it were common to use JSON to represent an arbitrary javascript program, but I've never heard of that, either. (For a good explanation of this weaker sense of homoiconicity, this stackoverflow page [1] is pretty good.)
[1]: https://stackoverflow.com/questions/31733766/in-what-sense-a...
To use Clojure as an example of a language that is homoiconic, you can take any Clojure source file, send it to an EDN parser (EDN being Clojure's equivalent of JSON), and not only will parsing succeed, but the result will be a complete representation of the program (you could execute it if you wanted to). In contrast, if you try to send JS to a JSON parser, you'll get an error as soon as it hits a function definition, or a for loop, or an operator, or whatever.
kazinator|10 months ago
What they have is code parsed to a data structure, which is then susceptible to manipulation by the program before being executed. JS has some dumb textual eval, like the Bourne shell.
They also have the concept of a symbol.
And only one value that is false.
galaxyLogic|10 months ago
ES6 JS has nice syntax for calculating with lists:
After the above 'car' has value 1 and 'cdr' has value [2,3].behnamoh|10 months ago
tcfhgj|10 months ago
nateglims|10 months ago
sundarurfriend|10 months ago
soapdog|10 months ago
johnisgood|10 months ago
gavmor|10 months ago
xonre|10 months ago
Lisp killer features were GC, good data representation, first class functions. Lua has all that and more. But its being a "thin" library over the C runtime shows through the clothes.
flavio81|10 months ago
Lisp's killer feature is procedural macros that are extremely easy to write and debug.
Lua doesn't have such a thing, that's why Fennel was created.
Erlang also doesn't have such a thing, that's why LFE was created.
0x3444ac53|10 months ago
https://janet-lang.org/
cy_hauser|10 months ago
behnamoh|10 months ago
gavmor|10 months ago
One thing I do know is that JS and Lisp both treat functions as first-class citizens, allow some degree of meta-programming, and rely heavily on hierarchical (e.g., nested objects in JavaScript vs. s-expressions in Lisp).
Passing functions by reference enables both LISP and JS to compose higher-order functions and, as suggested in another commented, both Lisp and JavaScript's "dynamic stack frames" somehow live updates to running code without requiring a complete restart of the application. The only clear example of this I can find, however, is Bun's --hot mode, which performs a "soft reload," updating its internal module cache and re-evaluates the changed code while preserving global state.
I have some vague notion that this is a favorite feature of Lisp, but it's not clear to me that it's unique to these language families.
---
Edit: Lexical scoping, closures, some tail-call optimization...
---
Edit 2:
> Programming language “paradigms” are a moribund and tedious legacy of a bygone age. (Dave Herman)[0]
---
Edit 3:
> The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."
> Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
> On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
-- Anton van Straaten 6/4/2003 [1]
0. https://cs.brown.edu/~sk/Publications/Papers/Published/sk-te...
1. https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/...
timewizard|10 months ago
Dynamic dispatch and the Object System are bolted onto the side and are still unparalleled by any language that I'm aware of.