While you are right that there are a lot deeper topics, the point of this primer was to be a primer, not a language design piece. It was also to show off one of the more powerful pieces of Lisp/Scheme: that metacircular evaluators (or, as you say, tree walking interpreters) are trivially easy to write partly because of how the language works in a way that is fairly unique to those languages.
If you read SICP, chapter 4 is basically a long-form introduction to the tree walking interpreter I introduce in the document, and chapter 5 gets into how to write a register VM with the lower level details you describe. However chapter 4 is where the most important unlocks of demystifying how programming languages work. Much design of programming languages in lisp has happened within metacircular evaluators first, and the efficient implementation later. Within a few tweaks, you can change your language to a logic programming language like Prolog, or switch from lexical scoping to dynamic scoping. This is power. And it isn't possible in most other programming languages. SICP was recently ported to Javascript, and it's an amazing conversion, but there's an extra step for parsing the source text which turns it into something that doesn't look like javascript anymore, whereas a lispy evaluator looks just like lisp.
Again, this is a primer. Showing off that you can do such a thing in 30 lines of code is something that few primers which are less than 30 pages would dare to do. It's possible to demonstrate in lisp/scheme partly because of lisp's language choices. And it's hopefully useful: I know when I wrote my first metacircular evaluator at the end of reading The Little Schemer, it demystified programming languages for me in a huge way. I hope a bit of that demystification shows up here for others too.
Haha, thanks! Going from nothing to some of the deeper ideas of SICP and friends was definitely a goal, glad to hear it landed that way for some people. Hope it's helpful for your students... if it is, let me know! :)
Author of this blogpost here. I think the post is good, though it's mostly aimed at the perspective of "Racket is a very practical Lisp, for getting things done, akin to how Python is a very practical lisp" and also "DrRacket gives an accessible entry-point for Lisp for newcomers." Unfortunately I don't think Racket quite took this to be the rallying cry I hoped them to, to embrace Racket's lispiness as "The Python of Lisps" (which was the other alternate title I was debating between when I wrote it).
But in the comments here and as with most articles about Lisp, the conversation moves to... can newcomers understand Lisp's syntax? My spouse and I gave a talk about this very topic: "Lisp but Beautiful; Lisp for Everyone". https://fosdem.org/2022/schedule/event/lispforeveryone/
There's a lot in there (including demonstrations of representations of lisp which don't have parentheses at all). But the biggest point in the talk is that lisp isn't scary for new programmers... it's scary for experienced programmers. As we talk about in the video, my spouse and I co-ran introductions to programming using Racket aimed at humanities students with no required prior programming experience whatsoever.
What we found was that the students who had no prior programming experience, after just a few minutes, had no problem with the syntax (and DrRacket made it easy enough to pick up the language). But we did have complaints in the class about lisp's syntax... from those who already knew how to program. They already had a frame, and within that frame, lisp's syntax looked alien. Without a frame, students just accepted it and did fine with the syntax... great, even. (Many of them praised its clarity; like any decent lisp editor, DrRacket helps identify the kinds of parentheses-oriented errors that users think they're going to encounter.)
Anyway, I do more work in Guile these days than Racket, but both are really great systems with great communities. The thing I miss most about Racket though is that DrRacket gave an easy entry point for students which wasn't "and now start learning Emacs". (Guix is pretty great, however.)
Lisp syntax is pretty rough if you want to prioritize maintainability. I can look at blurry C code and know generally what things are and what’s going on without a single character being legible. Lisps don’t typically have the same convenience. Given that code maintenance is usually about poring through thousands of lines of code quickly, I’d say this is a significant advantage for C.
However, Lisps have unparalleled macro flexibility. It’s a clear trade-off that Lispers often have trouble admitting is a trade-off.
I'm kind of curious how much of this is the problem with parens, and how much of this is the conventions that Lisp programmers seem to mostly adopt. For instance, here's the concise 99-bottles from Rosetta Code for Racket:
(define (sing bottles)
(define (plural n) (~a n " bottle" (if (= n 1) "" "s")))
(printf "~a of beer on the wall\n~a of beer\n~
Take one down, pass it around\n~a of beer on the wall\n\n"
(plural bottles) (plural bottles) (plural (sub1 bottles)))
(unless (= 1 bottles) (sing (sub1 bottles))))
(sing 99)
And even with a snippet this short, it's not quick for me to scan. Lispers generally like hanging parens, the indentation varies depending on what construct you're in, and that example uses recursion instead of a for-loop [0].
Ok, so let's turn the concise Python one into a hypothetical Lisp:
(for i in (range 99 0 -1)
(let b = "bottles of beer")
(let w = "{b} on the wall")
(print "{i} {w}, {i} {b}\n")
(print "Take one down and pass it around, {(- i 1)} {w}.\n")
)
I think you could "know generally what things are" with that version even if it was blurry. And of course, this "hypothetical lisp" is legal Racket/Scheme after implementing a few macros.
[0] I know Racket has for loops, but they didn't choose to use them in that example. Which is my point.
1> (defun bottles-verse (n)
(flet ((bottles (:match)
((0) "No bottles")
((1) "1 bottle")
((@x) `@x bottles`)))
(put-line `@(bottles n) of beer on the wall\n\
@(bottles n) of beer\n\
Take one down; pass it around\n\
@(bottles (pred n)) of beer on the wall\n`)))
bottles-verse
2> [mapdo bottles-verse 5..1]
4 bottles of beer on the wall
4 bottles of beer
Take one down; pass it around
3 bottles of beer on the wall
3 bottles of beer on the wall
3 bottles of beer
Take one down; pass it around
2 bottles of beer on the wall
2 bottles of beer on the wall
2 bottles of beer
Take one down; pass it around
1 bottle of beer on the wall
1 bottle of beer on the wall
1 bottle of beer
Take one down; pass it around
No bottles of beer on the wall
nil
3>
Why does 5..1 go from 4 to 1? Because 1..5 goes from 1 to 4; it's a half-open interval.
5..1 goes over the same values in reverse.
:match is a "parameter list macro", which is something I invented. flet knows nothing about pattern matching; it transforms to a lambda, which also knows nothing about pattern matching, but :match takes the parameter list and body, transforming the code using the pattern expander logic.
String literals and quasiliterals can go across multiple lines, but with the permission granted by a continuing backslash. Being explicit about this lets us catch errors when a literal is left open accidentally. All unescaped whitespace before a continuing backslash, and leading whitespace at the start of
the next line is deleted:
"abcd \
efgh" -> "abcdefgh"
"abcd \
\ efgh" -> "abcd efgh" ;; escaped space counts
"abcd\ \
efgh" -> "abcd efgh" ;; on either side of \
I think I must be really bad at communicating, because you aren't responding to any point I was trying to make. Let me try again :-)
I think Racket, Scheme, and some Lisps are conceptually elegant, but they don't read well to people like me (or apparently the poster above).
In particular, your snippet of code has 3 different indentation strategies, and you hang your closing parens the way almost all Lisp programmers do. To me, it all looks so organic and arbitrary.
So, for those of us who don't like to read other people's Lisp - is it because of the parens? Or is it because the conventional Lisp style is alienating to us?
I really think it's the style. I'd rather read your example like:
(defun bottles-verse (n)
(flet
((bottles (:match)
((0) "No bottles")
((1) "1 bottle")
((@x) `@x bottles`)
))
(put-line
`@(bottles n) of beer on the wall\n\
@(bottles n) of beer\n\
Take one down; pass it around\n\
@(bottles (pred n)) of beer on the wall\n`
)
)
)
That's still not quite as nice as I'd like, but maybe you can see where I'm coming from.
I think most Lispers would say, "You get used to it." But, well we don't get used to it because we just stay with whatever our curly braced or indentation language is instead.
It's more like an experienced user of a bicycle will not use stabilizer wheels. For any person who can ride a bicycle they look weird, unneccessary and actually hindering them. After a short learning phase few people will need them any more and will be happy to get rid of them.
Lisp has quasi-standard indentation styles. They make code more readable and writable. The differences between Lisp and most other programming languages: Lisp code is written/read/manipulated as a data structure.
What you wrote has also different indentation styles, but dangling parentheses are seen as not helpful: Lisp users don't count parentheses, they don't match parentheses like that, their code is indentation heavy, code can get very long and code can be generated. Lisp macros are an example of generated code. That means Lisp users also might look at generated code, for example when they check the code a macro generates or when one users a Lisp interpreter during debugging. The Lisp interpreter directly executes Lisp source data structures.
Lisp users read by indentation of lists.
The parentheses in Lisp have a different purpose as curly braces in other languages. In Lisp the parentheses are used to denote a data structure: lists. The syntax for lists (or more correct s-expressions) has its own syntax. Programs are written as nested lists of other objects. Thus the programming language Lisp is defined on top of lists. It's possible and not unusual that code is not written to a file, but generated in memory or by typing to a Lisp read-eval-print-loop, where some will directly treat the input as data, not as text.
We we want to write lists as compact as possible and use indentation to make groupings visible, where necessary.
The Lisp programmer learns to write/read/manipulate lists as a base. Programs are then written as lists.
You aren't telling me anything I don't already know.
> Lisp [...] indentation styles. They make code more readable and writable.
This is a matter of opinion, and you're free to ignore the majority or programmers who don't like Lisp. Trust me though: there are a lot of smart programmers who reject Lisp, and it's not because they "just haven't learned to ride a bike" yet.
My only question is whether the people who don't like Lisp dislike it because of parens (which is the conventional wisdom) or because of the arbitrary indentation and closing brace style.
> Trust me though: there are a lot of smart programmers who reject Lisp, and it's not because they "just haven't learned to ride a bike" yet.
You aren't telling me anything I don't already know - to quote your remark from above.
The questions of code formatting and Lisp syntax has been discussed since the early 1960s. I've taking part in such discussions myself since the mid 80s.
My take: people don't like Lisp or reject Lisp because of MANY different factors - and many are justified, based on what they are looking for - not everybody needs to like or use Lisp - if there are better programming languages with their eco-systems for many programmers, that's totally fine for me.
Syntax is a factor why people don't program in Lisp. The standard formatting rules are a minor factor. More important is that the syntax&semantics is difficult: the consequences of code as data is confusing them - for example they have to deal with quoting/evaluation rules, they see that there are macro expansion phases which make code understanding and debugging harder, etc.
> ... because of the arbitrary indentation and closing brace style.
Lisp does not have an 'arbitrary' indentation and closing brace style. There are clear rules and these are supported by tools in various ways.
'being older is not a virtue in itself' (using one of your phrases), more interesting would be the experience of actually seeing people and helping them trying to learn Lisp in different settings. For example: at the local university we had several hundred students each year who had to learn Lisp and/or Scheme (and other programming language) as part of their extensive computer science introductory courses - most students had no prior knowledge of Lisp. That was at a time when we used printer terminals or vt terminals to edit code. Later one could see students who could do programming homework on their personal computers or with UNIX workstations at the University...
A few years back, both my brother and father wanted to learn to program. Actually, relearn in the case of my dad. He was doing assembly programming for fun when I was a kid, and he taught me Basic. So really, he wanted to re-learn after a 30 or more year hiatus.
I tried to turn them both on to DrScheme (PLT wasn't named Racket yet). I figured the language is elegant, the tool is friendly, it's got libraries for tons of things, and the syntax is really simple. Kind of the "learn the language in the first part of the first chapter" approach in SICP, and then get to doing something fun. It's a much better language, environment, library, and implementation than Python. But it really didn't pan out.
I'm sure we can blame me for being a poor teacher, but my brother got turned off completely, and my father seemed pretty annoyed it wasn't anything like he remembered. After that, I showed him Python, and he ran with it for a few months before he switched back to doing his pet projects in Excel. He's older than both of us, so he can do whatever he wants :-)
Anyways, I kind of like Scheme, and I've been installing various implementations of it on my computers for the last two decades. Of course I must not like it that much, because I almost never use it for my pet projects. Maybe that's because I like numerical stuff and am too lazy to sort out an infix macro that makes me happy. It's just easier to use Python or C++ (or lately, Rust).
Elsewhere, you made the comment "The Lisp version looks similar to the Python code, plus parentheses". Apparently it wasn't obvious, but that was intentional :-) I just wonder why people (like my father) find Python so accessible, when you can make Scheme look nearly identical if you ignore the parens. In every way that counts, Scheme is at least as expressive and has much better implementations than Python... Yet people prefer Python.
If I ever make my own compiler, I'm inclined to use parens as delimiters for expressions. I'll spare you the details, but it won't really be a Lisp, and it would be more block structured. I only bring this up because in your first reply above where you were proselytizing and pontificating, you were already preaching to the choir. Since that OP way up there made a comment about it not scanning well (looking at it with blurry text), I wanted to hear from someone who doesn't like Lisp what it would take to make it likable.
And of course all my comment did was draw attention from two people that want to defend Lisp. :-)
But, it turns out, it basically isn't. In the Lisp world there is a tremendous consensus about it; nearly everyone does it in nearly an identical way to everyone else. This is in stark contrast to the way, say, C or C++ people lock horns over formatting.
Even if you might not like the particular way it is done, the dogged consistency has to count for something.
> arbitrary indentation and closing brace style.
Lispm demonstrated how this style is reproduced by a Lisp system's printer. It's codified into a documented algorithm, and one that isn't hugely complicated.
> But, it turns out, it basically isn't. In the Lisp world there is a tremendous consensus about it; nearly everyone does it in nearly an identical way to everyone else.
Yes, and that's self selecting. If someone hates that style, that might be one reason they don't stick around in the Lisp world.
Besides, something being a consensus has little to say about whether it's an opinion or not.
> Even if you might not like the particular way it is done, the dogged consistency has to count for something.
Lol, no! Just like consensus, consistency isn't a virtue on its own. You could be consistently doing it wrong. :-)
No, people could just use their style. We've seen that in some subgroups. Often for example with AutoCAD users scripting in AutoLisp / VisualLisp.
> consistency isn't a virtue on its own. You could be consistently doing it wrong. :-)
Consistency is a virtue on its own. Consistent coding standards improve readability for a wider group, even if the coding standard would be slightly less optimal according to some other metrics.
Helping people cooperate is a virtue. You're confusing the means with the ends, and it's very likely that the OP I first responded to above does not find the Lisp-consistent style very readable, so it didn't enable his cooperation.
They made a point of saying, "I can look at blurry C code and know generally what things are and what’s going on without a single character being legible." That sure seems like their problem with Lisp is layout/formatting.
"I can look at blurry C code and know generally what things are and what’s going on without a single character being legible. Lisps don’t typically have the same convenience"
> in particular, your snippet of code has 3 different indentation strategies, and you hang your closing parens the way almost all Lisp programmers do. To me, it all looks so organic and arbitrary.
In Lisp we don't align Lisp code according to only the parentheses.
A Lisp programmer looks at the symbol in front and based on that there are one or more strategies for indentation. On my Lisp Machine I can cycle through different indentations or I can completely layout the code (called 'grinding' in old Lisp).
There are different lists:
a definition macro
(defun name (arg1
arg2)
a
b)
a function call
(foo bar baz)
(foo bar
baz)
(foo
bar
baz)
a special form:
(if a
b
c)
(if a
b
c)
(when a
b
c)
Property lists:
(:name foo
:age 23)
and lots more. Each macro has a simple implementation style but typically an editor may have custom layout rules, depending on the macro and its syntax.
I write Lisp mostly in the same I write C, and the way I wrote C before learning Lisp. (Except for not closing braces on the same line; though I experimented with that style and it was fine.)
printf("Hello, %s\n",
get_user_name());
In C, it is common to close parentheses together though. Look at the alignment in the tm_diff function in glibc:
371 int days = (365 * years + intervening_leap_days
372 + (a->tm_yday - b->tm_yday));
373 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
374 + (a->tm_min - b->tm_min))
375 + (a->tm_sec - b->tm_sec));
Vim does this alignment; I'm confident I could visually select these lines, hit = and they would stay the same.
The author put extra parentheses around the initializer for days, and around the return expression. I almost certainly know the reason; doing so encourages the editor to do the alignment of the + operators with the interior of the parenthesis.
Vertical alignment is important because if you violate it, it leads the eyes astray:
`@(bottles)
@(bottles)`
Both expressions are inside the quasiliteral: they are parallel elements. Why has one de-indented, as if the literal had already closed in the previous line?
There could be another argument after the quasiliteral:
(put-line `@(bottles n) of beer on the wall\n\
@(bottles n) of beer\n\
Take one down; pass it around\n\
@(bottles (pred n)) of beer on the wall\n`
output-stream)
If you have it like this:
(put-line `@(bottles n) of beer on the wall\n\
@(bottles n) of beer\n\
Take one down; pass it around\n\
@(bottles (pred n)) of beer on the wall\n`
output-stream)))
you're pepetrating a trompe l'oeil. The transition out of the literal is masked, making it look like output-stream is still part of the literal.
I see you like four space indents, and I've used them in C in years past.
Even if I wanted to experiment with four space indents in Lisp, the editor I use wouldn't support it. Believe it or not, the two space indentation is a hard-coded behavior in Vim's Lisp indent mode.
Vim doesn't support the quasiliteral formatting I'm doing; I had to make the one space adjustment by hand.
In short, there is almost nothing arbitrary about the way I'm formatting anything.
Without a doubt, C programmers have different styles. And there's disagreement about what to do when an expression gets too long.
However, almost no C programmer would stack and hang their closing curly braces the way Lisp programmers do with closing parens. And for the few exceptions you'll find, they're almost certainly Lisp programmers making a point about not doing what the Romans do when they're in Rome.
> In short, there is almost nothing arbitrary about the way I'm formatting anything.
Heh, I didn't mean it as an attack on you. I meant it how the rest of us perceive it. Forgive me :-)
I guess it's only natural that you should defend your own style. I'm just curious if maybe part of the reason Lisp is so objectionable to most programmers is because that style is so different from block structured languages.
Many people here seem to like Python. So they think this is fine:
def doit(n):
for i in range(n):
print(i)
Many fewer people seem to like Lisp. So maybe this is less likeable for some reason:
(def (doit n)
(for i in (range n)
(print i)))
Ok, so is this more likeable?
(def (doit n)
(for i in (range n)
(print i)
)
)
Just curious.
> Even if I wanted to experiment with four space indents in Lisp, the editor I use wouldn't support it.
That's pretty circular though... Lisp programmers expect a certain indentation, so editors provide it.
The Lisp version looks similar to the Python code, plus parentheses. As a Lisp user I would read the Lisp code just like the Python code, by largely ignoring the parentheses, looking at the indentation and blocks of code. As a Lisp user working with code manipulation I then profit from that Lisp can be pretty printed by a tool, since the indentation is not The dangling parentheses then don't add any value. Actually they waste space and are getting in the way when typing to a read-eval-print-loop (REPL).
I haven't seen anyone typing to a REPL dangling parentheses.
CL-USER 23 > (defun foo (a)
(list
(list
a b c
)
)
)
FOO
> I guess it's only natural that you should defend your own style.
I have reasons for writing things that way, that can be documented, if necessary. The style is not my own, though.
> However, almost no C programmer would stack and hang their closing curly braces the way Lisp programmers do with closing parens.
But they do it all the time with parentheses, which is the normal thing to do.
By the way: spotted lots of this in the Zstandard compression code base a few days ago:
void fun()
{
if (...)
{
for (...)
{
...
} } }
Yikes; the closes braces line up with the opening ones, but not their corresponding matching ones. I hope that wasn't a Lisp coder (and don't suspect it).
> I'm just curious if maybe part of the reason Lisp is so objectionable to most programmers is because that style is so different from block structured languages.
But it isn't. Almost all the indentation and alignment strategies you see in canonically formatted Lisp code have counterparts in everyday code in mainstream languages.
Found this in Linux's kernel/sched/core.c:
WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
lockdep_is_held(__rq_lockp(task_rq(p)))));
^ Lisp disease?
^ gee what is this "arbitrary" alignment?
Would C be more popular if it was more typically like this?
All of these examples use pretty much identical formatting logic as what I'm following when I'm coding in Lisp; except that a more pure version of it occurs.
This is a predominant style used in writing "curly-braced C-likes"; you see it everywhere and examples can be found readily. You simply don't seem familiar with this subject area.
Heh. I see we've gotten to the point where you switch from arguing the point to questioning my qualifications. Gross.
I guess that means I should return the insult: Showing a few examples of ugly formatting doesn't prove that curly-braced languages are that way "everywhere". And besides, other than the one silly example from Zstandard, which many people would agree is unusual, you didn't even show examples of curly braces. Even with all the different styles of C people use, the block structure is pretty consistent. You're either being deceptive or you need work on your logic skills.
Go ahead and grab the last word if you want it, but I think we've gotten away from anything good in this discussion.
I read your article when it was first published and agree with the sentiment.
Off topic (sorry) but one thing Racket is missing is great Python interop to mix in deep learning and other libraries. Common Lisp and Clojure have this support. Years ago I tried saving trained Keras weights and using them in Racket with the Matrix support: it works, but not very fun to use.
Couldn't this go the other way too? People who have no experience with programming languages have no basis for evaluating the comprehensibility of a language's syntax. I didn't have any complaints about BASIC until I tried Pascal, etc.
Yes, Goblins' "vat" model descends from E, which supports the "hybrid worldview". http://www.erights.org/
I have a tendency to call Goblins objects "actors", though some people in the community like to point out that "distributed object" is preferable since synchronous call/return is not supported in actors. But yeah.
Or the reverse: today's AI research is missing large components of what would be necessary to achieve sapience. A conversation with Gerald Sussman half a decade ago had a big influence on me in this area:
I had some further conversations with Sussman and some other oldschool AI researchers from MIT later, the shortest summary of their comments would be that "We knew that neural nets could do this kind of thing, we didn't have the power to do it yet though. But an artificial intelligence system that can't explain why it's doing what it's doing doesn't seem very intelligent." Sussman and his students' work on propagators provide a very interesting alternative direction where explanations are a key part.
And yes it's true, humans also construct imperfect versions of their own thinking. That's because these systems are combined: the fast gut-feel type neural-network'ish systems and the slower symbolic reasoning systems that are associated with language. And probably the right design combines both of these.
Hi! So, first of all, I think I need to make the description of Goblins clearer. It says "A transactional, distributed actor model environment", but "transactional" and "distributed" are two separate components. This follows the "vat turn" communicating event loop model of E, where every message handling in an event loop is done in a transaction. It isn't meant to say distributed transactions. You can build distributed transactions a couple of ways though: as an abstraction on top of the distributed object system provided, or as a consensus model where a quorum of nodes agree on the order of messages for a deterministic vat/event loop.
By the way, the "open source version of E" does do distributed garbage collection, but it can't collect cycles across a network barrier. However, the original version of E did collect cycles across the network too: http://erights.org/history/original-e/dgc/
However, you needed hooks into the garbage collector for it to work, since you had to do some introspection of how things were rooted iirc. Mark S. Miller told me that originally they thought this could be fixed because Sun had promised to make Java open source, but they took a damn long time to do it. In the middle period, apparently the E folks said "please! just take this patch... you can have it even!" but Sun didn't merge it.
But Mark also told me that he learned not to push for this, because the cycles-across the network stuff turned out to not be common enough to bother, and you could build distributed acyclic gc using just weakrefs (and weak maps) and gc finalizer hooks, which are much more common than the rooting-introspection stuff.
Not sure if I got all that right, but there you go.
Anyway, I'll fix the tagline for Goblins for next release to make it clearer. Thanks for the feedback.
If the version of CapTP we have is ported to other languages, then you could do some of it, but probably not all. Haskell might be better up for some, but Python won't be able to do some of the more interesting parts (like the time-travel support) quite as easily since it's a much more mutation-oriented environment. Still, you could get systems talking to each other over the network if a compatible CapTP was implemented.
Oh hey neat, some coverage. Actually I'm right on the verge of the next big release (v0.8) which should make doing the networked programming significantly easier.
But here's some more background: I'm co-author/co-editor of the ActivityPub specification, which might give you some idea that I have some experience with trying to build networked systems. Goblins is part of the Spritely project, or even more accurately, the foundation for it: https://spritelyproject.org/
Spritely has some pretty wild ambitions... I won't go into them in detail, the video near the top of the above site explains better. But achieving those in a feasible timeframe means we need some better tooling. Goblins is the foundation of that; it's implemented as a Racket library, but can/will be ported elsewhere. The docs linked above explain some of the core ideas, but honestly I think the video linked from this section of the site explains it better: https://spritelyproject.org/#goblins
In general, people tend to realize that something interesting is happening when they see a cool shiny demo. So here are two pages that might give you an idea with some cool shiny demos:
What? How can the last one be only 250 lines of code? (And a mere 300 more for the GUI!) Well, that's because we're implementing a peer-to-peer distributed object programming protocol called CapTP (which includes wild things like distributed garbage collection over the network (for acyclic references), "promise pipelining", and is object capability secure). The next release will be advancing that work significantly. The Agoric organization is also implementing CapTP, but their stuff is in Javascript instead of Racket; we plan to have our CapTPs to converge. Thus it shouldn't really matter whether you write your code in Javascript or Racket, your code should be able to talk to each other.
Anyway, new release coming out soon. Hope that answers some things since the docs page might not convey what's fully interesting about it (and indeed, neither does this text, but the videos mentioned above do a better job).
Thanks for setting me off on a wonderful trail tonight! After a couple of hours of reading, I finally appreciate how useful, simple and coherent the capabilities+actors part of the story is! I particularly enjoyed the analogy/application [1] with federated social networking -- Seeing how easily they are modeled by ocaps actually makes capabilities much easier to understand! :-)
That's neat; the ability to move state backwards is a powerful tool. I'm building my own language around reactivity and state management ( http://www.adama-lang.org/ ), and I'm getting to the point where I could demo replaying a board game backwards.
When I started working on standardizing ActivityPub in the W3C Social Working Group, the main thing I heard from everyone (including here on Hacker News was): "You're wasting your time. There's no way you're going to get all these projects to talk to each other, everyone building distributed social software is too stubborn to do that."
Now ActivityPub is the most widely adopted federated social network standard on the web ever, with dozens of projects using it, thousands of servers, and millions of users.
I did sometimes feel like giving up when I heard that kind of feedback then, but I'm glad I didn't. I'm not going to give up here either.
The project is ambitious. It's broken into many subprojects so that even if the larger goal doesn't succeed, we might still get a number of useful pieces out of it.
But I've learned not to let comments like this dissuade me. If I had, ActivityPub wouldn't have happened. We might fail, but more likely, we'll have a partial success, which is still useful. And it's worth trying.
ActivityPub is indeed a W3C standard; it's what connects together what's called the "federated social web" today. (Mastodon, Pleroma, Peertube, etc etc etc...) I am co-author of the standard. Spritely is a series of subprojects, ultimately building on top of, and extending the capacities of, the federated social web.
But my point was that when beginning work on ActivityPub as a standard, the kinds of comments on here were similarly negative. Of course you're not going to get a universal social network standard! Nobody's been able to do it, it's just out of reach. Might as well give up now.
Of course, now that ActivityPub has succeeded, people take it as a given that it was going to succeed. Criticism instead moves to certain design decisions, and that's fair and warranted. But hindsight makes those things that have been done seem as if they were always going to be done.
But at a time, it looked like ActivityPub itself, the thing we do have, could not possibly succeed, and people told me as such in many places, especially on here. Nobody questions that it happened now of course. So now I am proposing a multitude of layers in which we can make things better.
But it hasn't happened yet, and so of course the response is going to be, once again, that of course it's not possible...
So, Spritely isn't just an end-user thing because it's multiple layers, though a few of them are end-user layers (it's more of a laboratory for advancing the federated social web). It's true that it isn't a web standard itself, even though it aims to enhance the ecosystem that uses that web standard. But the point is: it's really demoralizing to get these kinds of comments, but they're the most common kinds of comments one gets on HN. Sometimes I did think about giving up on ActivityPub standardization. Ultimately I'm glad now that I didn't. So I think we can do cool and interesting things here with Spritely, and my lesson from the past is to not give up now either.
This is all well and good, but it's not really the right response to the person you're replying to. There's about as much connection between this response and the comment you're replying as there is between that comment itself and what Spritely actually is.
They're not coming at it from a place where they grok what you're trying to do and saying that you're doomed. The issue is that they've failed to satisfy the precondition of understanding things well enough to have an opinion about whether you're doomed. They think that whether "mainstream users would go for this" is somehow in scope.
That's all true and well, and the Spritely website does explain what it's going to do, but it's in a lot of words and I think that this isn't easy for people to absorb. I did put together a video which does a better job: https://conf.tube/videos/watch/18aa2f92-36cc-4424-9a4f-6f2de...
But I think part of the problem is that it's very hard to explain to people in words how something is going to work. In general people better understand from experiences. That's why Spritely is actually taking a demo-centric approach... people understand better from experiences than from being told. I wrote about this more here recently: https://dustycloud.org/blog/if-you-cant-tell-people-anything...
... which has a really interesting quote in it about how baffled people were about the idea of hyperlinks:
> Years ago, before Lucasfilm, I worked for Project Xanadu (the original hypertext project, way before this newfangled World Wide Web thing). One of the things I did was travel around the country trying to evangelize the idea of hypertext. People loved it, but nobody got it. Nobody. We provided lots of explanation. We had pictures. We had scenarios, little stories that told what it would be like. People would ask astonishing questions, like “who’s going to pay to make all those links?” or “why would anyone want to put documents online?” Alas, many things really must be experienced to be understood. We didn’t have much of an experience to deliver to them though — after all, the whole point of all this evangelizing was to get people to give us money to pay for developing the software in the first place! But someone who’s spent even 10 minutes using the Web would never think to ask some of the questions we got asked.
I think that the level of incredulity that we're seeing here is understandable then, in that sense... human beings are better equipped to understand something in retrospect than to think ahead and try to join you in envisioning it. Oh well... as more demos come out (we've already done a few, a couple are shown in the video but not all), maybe people will believe more and more. When it gets in peoples' hands, even more so.
My comment wasn't really about Spritely, it was about a comment about Spritely and your response to it.
> I think that the level of incredulity that we're seeing here is understandable
Another issue, I think, is that in your reply the the previous commenter, you're not really replying to their comments so much as you are responding to the gestalt of the overall discussion here and about HN in general.
If you read SICP, chapter 4 is basically a long-form introduction to the tree walking interpreter I introduce in the document, and chapter 5 gets into how to write a register VM with the lower level details you describe. However chapter 4 is where the most important unlocks of demystifying how programming languages work. Much design of programming languages in lisp has happened within metacircular evaluators first, and the efficient implementation later. Within a few tweaks, you can change your language to a logic programming language like Prolog, or switch from lexical scoping to dynamic scoping. This is power. And it isn't possible in most other programming languages. SICP was recently ported to Javascript, and it's an amazing conversion, but there's an extra step for parsing the source text which turns it into something that doesn't look like javascript anymore, whereas a lispy evaluator looks just like lisp.
Again, this is a primer. Showing off that you can do such a thing in 30 lines of code is something that few primers which are less than 30 pages would dare to do. It's possible to demonstrate in lisp/scheme partly because of lisp's language choices. And it's hopefully useful: I know when I wrote my first metacircular evaluator at the end of reading The Little Schemer, it demystified programming languages for me in a huge way. I hope a bit of that demystification shows up here for others too.