Wellll not two years, no, a couple-few weeks of initial work and then, embarrassingly, it sat idle for two years. As to why: at least in part because one of the best ways to learn is to do.
In many benchmarks, Racket is significantly faster than many other Scheme implementations, including Chicken: https://ecraven.github.io/r7rs-benchmarks/ This is because it is now based on Chez.
Racket may be significant faster than many, esp since transitioning to Chez, but its still very hard/problematic to compile to a binary, and if wrapped into a binary still very bloated in size.
FWIW: I enjoy working with Gambit, especially since it can compile to C and standalone binaries and also scores even higher than Racket.
New? It stretches back industrially to the WS-* stuff in the early 00s (this is where the term originated), and on the academic side has roots in process calculi from the 90s and session types from the late 00s and early 10s.
Absolute slop. Interesting that the end result, the place where Claude ended up, is similar to a (human-authored, windmill-tilting) project of mine, https://preserves.dev/ . Though with a much prettier website and far, far, far more words.
I unfortunately agree, this reads heavily AI generated. I was not able to follow the reasoning, e.g. management of backward and forward compatibility seems broken.
Is .map specialcased or do user functions accepting callbacks work the same way? Because you could do the Scott-Mogensen thing of #ifTrue:ifFalse: if so, dualizing the control-flow decision making, offering a menu of choices/continuations.
For any other function accepting a callback, the function on the server will receive an RPC stub, which, when called, makes an RPC back to the caller, calling the original version of the function.
This is usually what you want, and the semantics are entirely normal.
But for .map(), this would defeat the purpose, as it'd require an additional network round-trip to call the callback.
I don't think you could make filter() work with the same approach, because it seems like you'd actually have to do computation on the result.
map() works for cases where you don't need to compute anything in the callback, you just want to pipeline the elements into another RPC, which is actually a common case with map().
If you want to filter server-side, you could still accomplish it by having the server explicitly expose a method that takes an array as input, and performs the desired filter. The server would have to know in advance exactly what filter predicates are needed.
But you might want to compose various methods on the server in order to filter, just like you might want to compose various methods on the server in order to transform. Why is `collection.map(server.lookupByInternalizedId)` a special case that doesn't require `server.lookupCollectionByInternalizedId(collection)`, but `collection.filter(server.isOperationSensibleForATuesday)` is a bridge too far and for that you need `server.areOperationsSensibleForATuesday(collection)`?
* Looking up some additional data for each array element is a particularly common thing to want to do.
* We can support it nicely without having to create a library of operations baked into the protocol.
I really don't want to extend the protocol with a library of operations that you're allowed to perform. It seems like that library would just keep growing and add a lot of bloat and possibly security concerns.
Couldn't this be done in some way when validation exists, that the same validation is used to create a "better" placeholder value that may be able to be used with specific conditional functions? (eq(), includes(), etc.)