Blog Post: Lifetime Parameters in Rust

Thanks for the reply.

I was arguing the same point as @Maledictus for Rust's current "lifetimes everywhere" design:

What does @steveklabnik1 mean by "silently putting things behind a pointer" below? I thought borrow was orthogonal to representation on the stack or heap as we discussed upthread, and was only signifying lifetime semantics checking.

@steveklabnik1's point reaffirms to me that "lifetimes everywhere" is complex. Taking borrows in the same code block feels like minutia (and then I need an artificial braces scope to handle some cases).

I was referring not to Rust's current "lifetimes everywhere" design-philosophy, but to a potential alternative design-philosophy which I am contemplating would be "GC everywhere except where we can get compile-time lifetimes at very low complexity" especially to improve upon GC's overhead with freeing temporary objects.

I've thought a little bit more about my idea and the following is where I am with it thus far:

  • let can only declare owned (including Copy) instances or GC instances. No borrows. The non-annotated default is GC instance. I'm thinking := instead of = for owned instances.
  • Functions take compile-time enforced borrows on those arguments which are not annotated. No compile-time checked moves are allowed.
  • The optional annotation on function arguments (perhaps :: instead : since it means the function is keeping a reference to the instance indefinitely) declares the argument to a GC instance. So use this to handle all cases that compile-time checked borrowing won't. Note GC instances can be input to either type of function arguments, but lifetime-checked instances can only be input to compile-time enforced borrowed arguments.
  • No lifetime parameters. Input lifetimes can't be transferred to outputs.
  • Function outputs are allocated as lifetime-checked or GC instances according to the function body, and lifetime-checked can be converted to GC instance (but not vice versa, because GC instance wouldn't have been forced to be borrowed within the function body) based on the assignment of the function output by the caller.

So essentially afaics I am encouraging the programmer to do compile-time borrowing as much as possible, so compile-time ownership can be used sometimes. For all other cases, GC is employed.

This seems much simpler. Afaics, there is nothing unsafe in terms of "use after freed" memory deallocation.

I am thinking mutability should not be compile-time checked at such a low level in terms of disallowing for example two mut references to same instance. Instead use higher level abstractions which enforce mutability when desired. I am contemplating to only allow mut on let and function arguments (and btw I would prefer val and var instead of let mut and let and make function arguments val by default and they can optionally been prefixed with var to make them mutable).

Radical brainstorming.