
I think that’d be difficult. A value in #lang racket
can’t observe the fact that it’s being passed to more than one place, much less react with a run time error. (It can kinda react to being passed to less than one place using a finalizer/will, but that’s probably not reliable.)
I think a language could add this support by using variations of lambda
and if
that call methods on a value when entering a region of code that uses it more or less than once. I explored this a little in a toy language (Penknife, specifically the JavaScript-based version), but I can’t say my experiment was necessarily all that robust.

Perhaps there’s something that could be done in the vein of Racket’s parametric contracts. Those contracts wrap and unwrap a value so that effectively it can only be used in places that are mediated by the contract. I’m not sure how this would be built up into a full notion of linear typing, but there might be something there.

Might depend on what you want out of linear types. If you want to speed up vector operations by giving vectors linear types to ensure no one else will witness them being mutated, then it’s very likely a sophisticated contract will just make the program a lot slower instead. That kind of benefit is probably better off sought from static types than from contracts.

Reference counting seems like a related feature. Many languages that use it to track aliasing have pretty good performance, and the same might be true of languages that forbid aliasing of certain values. (My Penknife experiment had sort of dismal performance, but that might have been due to the fact I was doing a lot of method indirection and allocation on every alias of every value.)

I’ve made something approximately like linear contracts, but restricted to a specific data type https://docs.racket-lang.org/rebellion/Vector_Builders.html\|https://docs.racket-lang.org/rebellion/Vector_Builders.html

the performance overhead compared to plain mutation is even pretty low (at the expense of not checking linearity every time)

you might be able to do this more generically using impersonators that stuff a reference counter in an impersonator property


This is interesting, thanks!

Aside from performance, I know that linearity can be used to manage resources, like files, and can be used to implement purity. However, I suspect that adding a notion of purity to untyped Racket might use a different approach.

@kokou.afidegnon has joined the channel