Interesting because of the difference between what other people believe about Racket the artefact/language/community - and what I believe.
While there are many great comments, I also saw what I believe are common misconceptions about Racket:
What others believe
What I believe
PL research dominates the Racket ecosystem
The Racket artefact, infrastructure, libraries and community are mostly dominated by practical problem solving. In the last Racket survey, over 50% of users identified as professional developers. The only exception is the inclusion of Redex, but I don't feel the inclusion of this one tool has had a negative effect on my experience with Racket.
development workflow/repl behaviour
hot-reloading from the repl is only one way to get this sort of interactive development. My understanding is it is possible to build a repl with that capability, but no-one has wanted it enough to build it. Sometimes I feel this is the only thing stopping a whole lotta CL users from switching to Racket?
'I had a bad experience in CS classes'
Just as many - if not more in the comments seemed to have a good experiences learning. Maybe this is people confusing the HTDP languages, with the Racket language(s)?
You can send expressions and definitions to the REPL one at a time in both Emacs (natively) and DrRacket (with a quickscript). Is there something else in the Common Lisp / SLIME workflow that's missing here? If so, I'm curious to know what that might be.
I can at least understand where the impression might come from. To me it seems that compared to many programming language ecosystems, Racket has much more "language tooling" in relation to other features/libraries. For example, sometimes I wonder if it's worth it to have so many for forms instead of providing a base for the most common uses and leave the rest to the language users in case they need more. (This could be by combining simpler for forms with other code or use named let.)
I think part of the reason for all the language tooling is that macros and #langs make it relatively easy to write such tooling. So people attracted by this possibility turn to Racket and write more and more such code, which again attracts more people interested in that and so on.
I can imagine that some of the professional developers do much more "PL research"-ish things than in other language ecosystems even if they're not being paid for PL research and hence might not be seen as PL researchers.
This topic actually reminds me of some of the discussion in this thread.
I could be wrong, but I think that the issue here is that (a) quickscript and repl-sending behavior is not well-known, and (b) it's not the default. Indeed, I think it's fair to say that the design of DrRacket's REPL was more or less explicitly designed to block the persistent-REPL-focused development pattern of other lisps, because of the panoply of opportunities for errors that it creates, especially with beginning programmers. But also especially with non-beginning programmers... I appreciate not having to worry about that family of errors.
My guess is that many persons only saw Racket in one of the first courses of the university, and they were forced to use a rectricted part of the language, like car, cons, if, ... and they never see the complete language or the libraries.
Last year I had to program a bot to reply emails, and I was gladly surprised that racket has a library for imap, smtp, and also http. For another project, I used the libraries for gzip and xml. Perhaps the solution is to add a blinking sign in https://racket-lang.org/ that says "bateries included" and links to a few cherry picked libraries.
I think this is exactly right btw -- and even up there as one if not 'the biggest' hindrance from a CLers adoption standpoint; It's def stopped me for years for seriously considering it even though there is a LOT in the Racket ecosystem I find compelling.
And there are def ways to at least "locally max" an interactive workflow without doing the full image-based x call-the-compiler-in-runtime hot-code-reloading magic CL implementations tend to do ... but it's just not focused on and seems to really not even be in the Scheme 'dialectic' / culture at all -- even though ironically MIT Scheme did all of this originally afaict? lol
Even and/or especially regarding Racket, there's an almost ideological dictate against it (referring to the top-level-is-hopeless obviously) ... well at least in the way CLers would be most comfortable.
A "LISP" tight iteration-loop through said interactive-workflow is what "saved me" from Art-School; And I feel very strongly the benefits outweigh any lack of technical soundness*. And I'm hoping over the next few years as I dip deeper into the language / ecosystem -- that there is space (upstream) to explore this much deeper.
As Sid said above, Emacs plus Racket accommodates exactly this workflow (send pieces, incrementally update the state of the language system). I haven't tried this in VSCode, but I would guess you can do it there too. Is it perhaps the case that you don't want to switch to one of these IDEs?
[[ It just so happens that we don't think middle school students or even college freshmen benefit from such a REPL, which is why DrRacket (the IDE, not the language) accommodate this work flow. We want them to see a programming language not a programming system so that some of what they learn applies in downstream courses. ]]
I'll need to look into it, but at the very least it sounds promising; At a certain-point I'll admit it becomes a bit of a moving goal-post because even if it was "at the level" I'd hope it to be -- then it very quickly becomes a game of "where's the interactive debugger?". LOL
I mean, tbh there are a lot of interesting education friendly / proxy domains that I think would actually benefit a fair-bit if there was a deep lean-in to 'just works' interactive-programming in Racket; Notably the amount of graphical libs integrated (draw, pict, gui, etc) and not (sketching) that are part of the ecosystem.
I can only speak to personal experience (ie: I'm not an educator), but environments that let me really lean into that (Garry's Mod & Computercraft were the two biggest for me) they were (and in many ways still are) magic in my eyes. And magic = engagement.
Past initial buy-in, actual long-term retention and personal investment (especially for kids) is a problem that's obviously really-REALLY hard to solve; And I guess my vision of "what I wish I had when I was a kid" (started programming around 15, so a midpoint between the tent-poles of middle-school and college here) was something that heavily played into this.
So much so, that said ideal educational environment I don't think I'd even want a student to even know what Racket was for sometime until after they were using it pretty comfortably -- where they were outright 'seeing the system' and the language was just something to get something done in said-system. But I'm also SUPER sold on (/ biased towards) the "edutainment" route that something like Codespells tried to do.
I don't know, I have a lot of thoughts about this (and I'm currently falling asleep as I type this LOL; So hopefully coherent "enough") -- but I plan to go through a fair amount of the Racket coursework over the next few months and I guess we'll see where I come out on the other side. :%)
I'm not sure it's related to the CL workflow, but in a recent project I had to compare the output of different runs of a program. (Run it, make a few tweeks in the definitions panel, run it again, fix something, run it again, ...) I wanted to compare the outputs and sometimes to copy&paste parts of them later.
It would be nice that DrRacket has an option to not erase the previous output like Python's IDLE (see /drracket/issues/671). I agree that it can be confused for beginers, so I'd not enable it by default.
Just to make it explicit for any future readers of the thread.
Among the reasons this feature is confusing for beginners is that Racket structures are generative. An instance of a structure foo created by the first run is not "compatible" with an instance of foo generated by a second run.
Assume these definitions are in your file and you're sending them over to the REPL with your favorite 'send-s-expression' command. (I do this in Emacs on rare occasions still.)
Now assume that the seconddefine for f is actually an edit to the file, not a new definition. You're sending over f because it's the only thing you changed.
Do you really want (g 1) to return 2 now?
This is a rhetorical question. FWIW, Dan and I were burned by this kind of problem time and again while we wrote some Little books, which is why we decide that we'd restart the REPL in Emacs for every chapter evaluation.
My years-long observations of beginners suggested that they had similar problems, before we created PLT Scheme/Racket (with generative structs) and the teaching languages. It just made sense to tackle this problem (which I did in a very different way back then with dependency graphs).
For people who need program comparisons, I recommend a slightly different sub-module structure. I have just again gone through this for the past two weeks working on Leetcode 'stuff'. It's doable and quite smooth.
I don't think the suggestion is for something with weird semantics. Instead, I think the idea is that you would have a run button that worked the same as today, and a REPL that worked the same, just with all the output from the previous REPL session above it.
@samth You're correct. What I wanted to do here is supplement @soegaard 's reply with concrete examples of the problems that have bit people badly. The proximity to @gus-massa 's reply makes the last paragraph bad. What I meant to explain was that comparisons are usually only half the game. You really want tests that capture things ... and using submodules with two variants of the same program helps a lot here, and my guess would be more than a plain manual comparison.
RE comparisons, working in a non-GUI editor my inclination would be to racket program.rkt > output-$(date -Iseconds) or similar. Then use {vim}diff and other tools to compare. MF's suggestion to use submodules for the different variants makes me think of a pattern like
#lang racket
(module one …)
(module two …)
(module+ main (command-line #:args (version) (dynamic-require (string->symbol version) #f)))
(where one, two, are valid versions and run the different programs).