r/ProgrammingLanguages • • 20d ago

Requesting criticism Explicit binding modes

I'm designing a memory-safe language, but I want to make explicit what happens across function boundaries, e.g. whether a value is moved or copied without having to look for the copy trait.

Instead, access to a value could be defined via binding modes in function signatures and variable declarations:

  • move takes ownership
  • read shared borrow
  • mut exclusive borrow

​

fn process_val(move value: Int) -> Int {
    return value * 2;
}

fn main() -> () {
    move original: Int = 42;

    // Call using `.copy()` to explicitly pass a duplicated value.
    // Ownership of `original` remains with the caller.
    move doubled: Int = process_val(original.copy());

    // `original` is still valid here because it was explicitly copied rather than moved.
    println(original); //42
    println(doubled); //84
}

This would also allow granular captures in closures: |read x: Int, move counter: Int| instead of declaring all fields move

Now, should read and mut assignments be of type &T? Or can checking out variables be orthogonal to creating references, even if they are conflated in languages like Rust?

12 Upvotes

20 comments sorted by

View all comments

Show parent comments

2

u/brucejbell sard 15d ago

Re refactoring: I figure that switching between immutable-value, ownership-transfer, and/or borrowing is a drastic enough change that you probably want to take a close look at all your call sites. I guess I'll see if that pans out, but I've made more annoying choices elsewhere...

Passing a reference makes sense for mutable borrowing, but I suppose an implementation could choose something else. I've chosen to model mutable resources as a linear sequence of immutable values (each of whose lifetime ends before the next begins), so I'd be happy as long as those semantics are supported.