
@sachi.d.addweb has joined the channel

Yes but not like LLVM (C++) is. You can fairly easily implement high level features like type systems but you can’t (afaik) implement more low level stuff like JIT or get rid of the GC.

@cperivol you certainly can: you just have to write or integrate with a code-generator for whatever your target is. That’s just not what most people do because making #langs is more fun and inter-operates with the rest of racket.

Your compiler would be a racket program that takes source and outputs code to some target. Most languages are capable of doing that

That program would have all of racket, like the gc, but the resulting code and runtime need not necessarily.

I’ll look into this, thank you very much!

That sounds nice and actually very useful.

Do you know of any projects that have followed this approach?

Not off the top of my head. But any compilers class could do it, if they wanted. Racket and lisps are often seen to be “interpreter languages,” whereas my compilers class used java. But you could flip that without real issue.

They are? All lisp books/tutorials/advocates/articles bang on about how sophisticated the compilers are and how you can do so much at compile time etc.

I believe they are seen as dynamic languages as opposed to java. But in any case that is beside the point. I guess in principle you could build a compiler in latex.

Would you say that racket equipped to make your life easier when building a language like rust?

Lisp compilers are sophisticated. Then, so are most industrial compilers. I think youre mixing two parts of the process. It is true that compile-time programming (macros, in lisp world) are pretty awesome.

As for building rust… you still need a runtime or code-generation target. AFAIK they use LLVM, which you could in principle do from racket, too, with the ffi libs. Then the rest is parsing (racket is pretty good at that) and analysis/dataflow/etc. Racket is also pretty good at that, though im not an expert on how you would do that in racket. (Someone step in here and correct me, please! Esp if i am making unfounded claims, which happens)

Again the gc is a separate issue: i can write a compiler in a gc’d lang like racket that compiles a non-gc’d lang like C or Rust. The output need not be related to the transformer; or, if you like math, the properties of f(x)
need not have anything to do with the language used to describe f
; only its definition.

btw, I learnt about this library from https://github.com/syntax-objects/Summer2021/issues/19

When racket advertises itself as a language-oriented language it doesn’t mean “we can easily ffi with LLVM” or “we have tools to help you build your memory management framework” or “we let you make exotic linking policies”. All these things are possible but they are not any easier in racket than they would be in any other language. If anything they are all much harder considering that LLVM (that does a lot of that stuff) was designed to work well with C++. As far as I can understand racket is instead good for building languages that experiment with syntax and semantics.

…well, that’s language-oriented? A compiler is an implementation of a specific language via an executable target. Technically the standard LOP techniques in racket let you do that—but your executable target is the racket platform. “Experiment” is maybe the wrong word—some of the langs built in racket go far beyond simple experiments and into full fledged daily drivers. Some are dsls with multi-faceted utility. (But yes, i admit, the kind of things youre talking about may need more tooling. Good ideas for projects :))

I was actually bit by this, I wanted to build a language that takes the code/data duality to the lowest level, where machine code is data and visa versa and I very soon hit a fairly thick wall with racket. Lisp over SBCL was slightly better but really the language that came the closest was forth. I didn’t end up with much more than disappointment…

hi folks, there is something where my understanding and the racket cs runtime & FFI system diverge and I would like to understand which is wrong. When running this program (require ffi/unsafe)
(let ([x 9]) (register-finalizer x (lambda (v) (writeln "duh"))) x)
I expect the output to be 9
duh
But I never have the duh
printed to the console. Is that the way it is supposed to be? If so, why? Should the finalizer not run when the 9
goes out of scope?

9 is an immediate value (a fixnum) that doesn’t need to be allocated, so it is never GCed.

Id be curious on more details of that, if you want to share, but (a) we should maybe stop polluting Job’s thread and (b) i had similar goals once, but i think you would have to build that lisp from scratch because of the deep integration with machine code. And it wouldn’t necessarily be portable without a lot of abstraction

Thanks Matthew, that is exactly what I was looking for.

Would wrapping it in a box change that? i.e., do boxes always always allocate?

Yes, box
is obliged to allocate when it is called.

hmm, so here is the output I get when using box: hlgr@pteranodon Sanitize % racket
Welcome to Racket v8.2 [cs].
> (require ffi/unsafe)
> (let ([x (box 9)]) (register-finalizer x (lambda (v) (writeln "duh"))) x)
'#&9
> (exit)
hlgr@pteranodon Sanitize %

it still does not seem to call the finalizer

You can force a garbage collection with (collect-garbage)
. If you need something that is called before exiting, then a finalizer is not enough or maybe not the right idea; see register-custodian-shutdown
or register-finalizer-and-custodian-shutdown
.

hmm, interesting, (collect-garbage)
does the trick. Do you think it was called on exit but the output simply was not written or was it not called?

I doubt that a garbage collection was needed before exiting in your earlier try. But finalizers do run in a thread, so it’s also possible for there to be a GC but an exit before the finalizer gets to run.

I see, the actual problem is that in a more complex application involving a bunch of FFI calls, clang’s address sanitizer reports loads of memory leaks in the wrapped C/C++ library. Now, some of those might be in the C code but I suspect that a lot of them are due to finalizers not being run.

For now, running (collect-garbage)
before exiting works but this might be a more fundamental problem

(i.e., affecting more people)

In the intro to compilers course I sometimes teach, students can pick C++ or Racket. I am not very subtle at steering them toward Racket in general, and typed/racket in particular. Nested lists are a very concise way to represent the parse tree and AST (and match
is just glorious for this kind of tree traversal)

What about the custodian APIs above? The docs says that finalizers are not guaranteed to be run when the program exits

yeah, I saw that it says that it is not guaranteed to run when a place exits but I (overeagerly) assumed it would still run when the process exists

I’ll look into the custodians

I am thinking of this message: https://racket.slack.com/archives/C06V96CKX/p1632495514441800?thread_ts=1632493854.436900&cid=C06V96CKX It looks like finalizers are associated with the garbage collector instead of the Racket-level resource management abstraction (custodians). That’s why when there are no garbage collections they won’t run.

got it. I’ll see how far I get and report back

sighs wishing i’d had that… i did successfully get one iteration of our PL class (interpreters, really) to use racket instead of java for making lisps to explore different ideas. But i’m not sure if it will stick or not, and i’ve since left, so

Is it normal for bindings within chunk
s in a scribble/lp2
file not to be hyperlinked to their documented forms in the resulting HTML?

How very poetic!

Here’s a Gist that shows what I mean: https://gist.github.com/otherjoel/74a16dd9d27a9dc3b3db2f59bbcf33e6 — in the resulting HTML, neither instance of racket[analyze]
is hyperlinked to the defproc
for the analyze
function.

IU Bloomington’s course on compilers is taught in both Racket and Python. You can get a PDF of the book from the course webpage https://github.com/IUCompilerCourse/IU-Fall-2021/blob/gh-pages/index.md It describes how to compile a subset of Racket down to x86.

Posted this in #beginners earlier, but maybe it’s not a beginner question. I’m dipping my toe into typed racket and was surprised to learn that it doesn’t work out of the box with the generic collections data/collections
(collections-lib). Is there a commonly used typed version of it or is data/collection
simply not all that popular, or what’s going?

I searched a bit in the typed racket code base and found this. Not sure what is the status quo. https://github.com/capfredf/typed-racket/blob/rfc-typing-generic/rfcs/text/0003-typing-generic-interfaces.md#prior-art

> PR draft > Prior art > As of Racket 8.0, generic interaces are not supported in Typed Racket.

I think that document is up-to-date. TR doesn’t support generics. capfredf’s work on struct properties is one step along the road https://github.com/racket/typed-racket/pull/1124

Interesting, so is there a general recommendation? Is to use typed racket? To not data/collection
?

what do people do popularly?

I think collection-lib is not as widely used as it could be, and probably people don’t use it with typed racket