I have been experimenting with Racket for quite a while and I appreciate the effort that went into making the language extensible. That being said, I wish that the community would have embraced "object-oriented" techniques for building the VM - Ian Piumarta's COLA (Combined Object-Lambda Architecture) comes to mind [1]. I think this would have saved them a lot of performance troubles (but this is mere speculation) and would make the system far more flexible and pleasant to use.
While it's comforting to have a very powerful macro system at your fingertips to change the semantics of the language when needed, many of the macros in the base language and libraries could be eliminated with a more convenient default notation for closures and message-passing (to objects simulating control structures like in Smalltalk).
Racket has one of the best module systems I have worked with but modules cannot be (easily) parameterized. Research on systems such as Self and more recently Newspeak [2] gives ample of demonstration of the benefits (conceptual integrity, security) of having modules as objects.
What Racket also lacks is a good meta-object system with highly reflective capabilities (of say a CLOS or Smalltalk system). This makes it difficult to build tooling such as inspectors or browsers.
I hope that in the future these issues will be addressed.
From my understanding, Piumarta's main trick with COLA is fast dynamic dispatch through a uniform interface (putting pointers to vtables at offset -1), and implementing vtables via interface (so they can be replaced). It's a cool approach, but it's also a case of 'everything can be solved by adding a layer of indirection'; and I've not sat down and thought through how these ideas might apply to different paradigms, and what might be unique or common to them all.
On the other hand, I believe that when it comes to low-level "machine" work, objects are a good abstraction to model components such as activation records such that they can be uniformly explored and modified (on the fly). But this is perhaps a moot point.
Over the years, I have studied many object/component-oriented systems and come up with a sizable catalogue of message-exchange patterns, plumbing and machinery. My hope is that at some point, this can be crystallized into a language or calculus for specifying systems; and Scheme/Racket is certainly a good language to think about these issues from another perspective (which is worthwhile to preserve).
So I guess, I understand your point. Thanks for raising it, much appreciated.
I've been very slowly trying to combine the work in Maru with Composita to yield a modular and deterministic lisp (Composita uses managed memory without GC).
http://concurrency.ch/Content/publications/Blaeser_Component...
Naturally you'd want to layer something like Shen or Maude on top of this, to provide the equational proof-checking. The K language is a good example - it provides facilities to model new languages and semantics like racket.
http://fsl.cs.illinois.edu/index.php/K-Maude:_A_Rewriting_Ba...
So, multiple dispatch as a library yes (and racket has that), but probably not ok in the core language?
I had no idea I was using Racket already, via this website! Makes me wonder if Terraform's HCL could be re-written using Racket.
Why did Chez and Racket embrace R6RS, a standard widely rejected by the rest of the Scheme community?
Also, why did Racket choose Chez over some other high-performance Schemes, like Chicken?
Finally, how many Racket and Chez users are there compared to those of other Schemes?
https://ecraven.github.io/r7rs-benchmarks/ is an ok comparison between Scheme implementations; you can see that Chez is much faster than Chicken in general. Chez also already supports many features beyond Chicken that were needed to implement Racket (for example, internal support that made delimited continuations easy).
It's hard to know exactly how many people use what, but it seems likely that Racket is the most widely used Scheme derivative.
I built a Chez Scheme backend for Idris (and Idris2 uses Chez as the default compilation target). I used it because it's so much better than the other compilers, and what's the point of being compliant with a standard that provides no interoperability anyway because it is so meager?
Why wouldn't they? The usual rationale for rejecting R6RS is that it's somehow "too big". But Racket already has a library whose size blows R6RS out of the water. So this rationale is irrelevant in this context. Also, Chez Scheme is an implementation detail. R6RS is only one of many languages that you may use through Racket.
And what is this "Scheme community" that rejected R6RS? It's always been my impression that it was rejected by authors of toy implementations. Is there actually any data on what portion of people who use Scheme (as opposed to write another implementation of it) reject R6RS?
No one begrudges Racket for having a huge library. The Racket team have obviously had enormous success building large, comprehensive real-world systems.
But Racket is an implementation -- not the Scheme standard. The historic value of the Scheme standard is its smallness and ease of implementation -- a small base upon which to build large systems. Large, comprehensive implementations -- such as T -- have been built on top of this small basis for almost as long as there's been an RnRS.
R6RS represented a fundamental shift in philosophy for what is Scheme. It de-emphasized the "small language kernel" approach and emphasized a comprehensive, software-engineering approach for building "real world systems". But the Lisp community already has a comprehensive, software-engineering-oriented language, Common Lisp (which borrowed some of its best features, like lexical scoping, from Scheme). So what's the point of building Scheme into a large software-engineering language to compete with Common Lisp?
It's a bit hard to fathom today, when most modern programming languages -- excluding ECMAScript but including, for example, Rust -- are defined in terms of a single reference implementation, but there are advantages to keeping the language standard small while allowing implementations to grow to arbitrary size and accrete features. Advantages which Scheme has turned into its own little niche among the family of Lisp programming languages.
> And what is this "Scheme community" that rejected R6RS? It's always been my impression that it was rejected by authors of toy implementations.
Of course, because Gambit, Chicken, and Gauche -- among others -- are mere toys.
A toy implementation that implements all of R5RS is at least possible. You can't build a toy implementation of Common Lisp, Python, or Rust, that covers even a small fraction of the core language. But you can build a Scheme that's nearly or entirely R5RS-compliant in maybe a few thousand lines of C, and from there build out the language to incorporate Python- or Rust-like features. "Toy" Schemes can even be useful in production, as an embedded scripting layer to a larger system.
Neither R6RS nor any other RnRS standard contain a reference implementation, so whether it's in R6RS or not, the Racket developers have to implement it. RnRS standards do tend to have a description of Scheme's formal semantics, and SRFI documents, by convention, contain a reference implementation of the proposed API where possible.
2. Some rewritten parts of the system, such as IO, were initially slower, but have now been improved to catch up to the previous implementation.
3. Chez Scheme didn't support some performance features that Racket BC had, such as unboxed floating point arithmetic, parallel GC, or continuation marks. Those have been added to (Racket's variant of) Chez Scheme.
4. Racket's prior compiler was somewhat more competitive with Chez Scheme than we expected, particularly for larger and more Racket-idiomatic programs.
[0] https://blog.racket-lang.org/2018/01/racket-on-chez-status.h...
Mostly, we did reimplement the C stuff in Racket. The I/O
subsystem, the concurrency subsystem (which includes the
scheduler for “green” threads, Concurrent ML-style events,
and custodians), and the regexp matcher were all rewritten
in Racket. Those pieces followed the rewrite of the macro
expander in Racket.
So there was a slowdown until those pieces matured. But now they get the benefit of having all those pieces in higher level of abstraction and more accessible to Racket programmers.> For example, Racket BC makes dormant code relatively cheap, so Racket libraries generate a lot of code. Future Racket libraries will likely shift to take advantage of Racket CS’s cheaper function calls and dramatically cheaper continuations. One day, probably, Racket BC will no longer be a viable alternative to Racket CS for most programs.
[1] https://blog.racket-lang.org/2020/02/racket-on-chez-status.h...
Preferences->Colors->Racket->Parenthesis (Underline)
You can set Dr. Racket to "system" DPI scaling (by accessing the .exe or .lnk properties), at the cost of rendering at 96dpi and being blurrily upscaled. The program is not good, the result sucks, but it technically works.