Lively Linear Lisp – 'Look Ma, No Garbage' (1992)
home.pipeline.com
home.pipeline.com
"However, linear logic's lack of sharing may introduce significant inefficiencies of its own."
"The sharing of data structures can be efficient, because sharing can substitute for copying, but it creates ambiguity as to who is responsible for their management."
These quotes foreshadow the goals of Rust 20 years later, whose eventual intent was to realize both the doesn't-require-a-garbage-collector property of linear logic with the efficiently-sharing-data-is-still-possible property of traditional systems languages by separating these concepts into ownership (covering the former) and borrowing (covering the latter, and built on top of ownership).
The idea of borrowing is not original to Rust in any way, and is found from the first application of linear logic to PL type systems in Wadler's "Linear types can change the world!" onward, including Vault, Cyclone, etc. Any system without it would be impractical for writing real programs.
This is why I think it’s important to get familiar and listen to Old Masters like Rob Pike, Brian Kernighan, John Ousterhout, and even war stories of Richard Stallman, and chase down their references and get familiar with them, too. It’s not that there’s nothing left to do, but an awful lot has been done. We can at least learn from it...
> and beyond Bell Labs walls
As I cite Pike, Kernighan, ... :)
I'm not claiming the techniques are novel (borrowing rules are similar to fractional permissions for example), but I'm not aware of their application to this specific problem prior to Rust. (I could be wrong though! There's a lot of work on substructural type systems out there.)
For a good overview of the prior art and how Rust relates, section 1.1 of the RustBelt paper goes into detail: https://plv.mpi-sws.org/rustbelt/popl18/paper.pdf
My point was more towards to future generations being unaware of such ideas that eventually came into Rust. For example, as you describe Cyclone had its issues. Still if Cyclone did not exist, probably Rust as idea would never happen. Same applies to ATS, and all other languages that served as inspiration for an idea that eventually became Rust, and then took a path of its own.
Then there's Alef, Newspeak, Bell Labs fork of C (separate from ISO C if mostly compatible), few other languages I believe, the whole original Unix phhilosophy often is forgotten as well...
I recall Brian Kernighan alluding to some of this in his humorous (but true!) mention of "first Go commit" (https://github.com/golang/go/commit/7d7c6a97f815e9279d08cfae...)
That paper is the most abstract, airy, 'ungrounded' paper I have ever read that will probably have a significant positive practical impact on human flourishing (via Rust's borrow checker).
To bring the discussion back to my first comment, it would've been less likely for anyone to have invented the borrow checker if programming-languages researchers weren't paying a lot of attention to use-once variables, and languages researchers would've been less likely to be paying attention were it not for Girard.
I haven't read Girard's paper in 20 years, but I would be extremely surprised if it contained any mention of borrowing or references, so Girard must share any credit for Rust's borrow checker with later innovators, and here I would be remiss not to mention Graydon Hoare.
The reference type is a separate type, but the & borrowing operator is a use of the original path. You can borrow (i.e. use) the same path multiple times before it is moved or implicitly destroyed.
Do you agree with my belief that it is significantly less likely the borrow checker would've been invented if programming-languages researchers hadn't paid a lot of attention to linear and affine types? Even though a Rust coder can take as many non-mutable references to a location in memory as he wants, there are certain operations (e.g., move) that the coder can only do once to it, and the inventor(s) (probably Graydon Hoare) of the borrow checker must have explored that part of the design space extensively, and it seems to me it would have been very non-obvious that it was worth exploring extensively to someone not influenced directly or indirectly by Girard.
As I mentioned in another comment, the concept of borrowing was already present in the earliest applications of linear types to programming languages. There was contemporaneous research into region systems for ML. Later languages like Vault and Cyclone combined these two ideas, using substructural types to manage regions.
From a language feature perspective, the biggest innovation of Rust was integrating the ideas from Cyclone and other research languages with the emerging C++11 style of programming with implicit destructors, move semantics, and smart pointers.
One outcome of that attention was a nice and blazingly fast for an FPL called Clean which offered a more modern Haskell/MLish syntax. Actually came across this previous discussion while searching for a link: https://news.ycombinator.com/item?id=15937597
See also Conal Elliott's "Compiling to categories" ( http://conal.net/papers/compiling-to-categories/ ) where he is converting Haskell automatically to point-free form (like a concatinative language but not quite) and then instantiating that over different Categories to get different correct programs from the same expression.
I've been working with Joy recently and I think this stuff is "the next big thing" for PLs. http://joypy.osdn.io/notebooks/Types.html
For typing combinators (Joy's higher-order functions) I tried making a hybrid inferencer and interpreter that just evaluated them and it worked. (Incidentally that's what drove home to me the categorical nature of Joy. When I read Conal Elliott's "Compiling to Categories" I recognized what I had done.) In Joy the higher order combinators "don't care" if they are working on e.g. values or types. In other words they only care about the shape or structure (structural typing) of the data on the stack.
When I wrote the interpreter in Prolog and then wrote the inferencer in Prolog I noticed they were the same code, so I deleted one of them. In Prolog, you can pass a stack and compute values or pass logic variables and it will tell you what kind of stack a given expression expects/generates. If you implement math ops with CLP(FD) you get a nice constraint compiler that get generate new Prolog implementations of Joy expressions. Sick, eh?
In both Prolog and Python I haven't yet closed the loop for recursive combinators. Meaning the type inferencer generates the base-case and then the case for recurring once, then twice, and so on. I know the answer is some simple application of fixed-point theory or something, but I'm an idiot, and I've been working on other aspects (because I'm sure the solution is like decades old in the "compiling FP languages" literature. "Somebody else has had this problem.")
In any event, I don't think I'll have to figure it out, because I just found out that the next steps I was going to take have already been done by the "Seven Sketches" folks and then some: https://news.ycombinator.com/item?id=20376325
I'm pretty sure most of that stuff would make great Joy combinators. And something in there would be the way to deal with e.g. genrec and x combinators.
If you're only allocating fixed-size cons cells, you won't run into fragmentation issues.
The "Carp 0.3.0 release" is being discussed today as https://news.ycombinator.com/item?id=20368969 .
Alternatively: The category of finite dimensional vector spaces over finite fields is a model of linear logic. http://www.cs.bham.ac.uk/~drg/bll/steve.pdf