Pre-pre-RFC/Working Prototype: Borrow-Aware Automated Context Passing

Yes, and my belief is that that goal is an anti-goal. After all, you can program without function parameters, using static items for everything instead, and indeed, I've worked on systems where that was the norm (not in Rust). But it leads to hard-to-maintain code, because you break local reasoning; there's information being smuggled around out of sight of function parameters.

I would prefer to see the "no need for foo to explicitly know what context items bar and baz require" filled by a means to say "foo's context parameter is bar's needed context + baz's needed context". Opening up some syntax for bikeshedding, you'd put the context after the where clause in a using clause, and be able to write something like:

fn foo(a: Random, b: Parameters, c: Here) using bar() {
…
}

fn bar(a: More, b: Random, c: Parameters) using
    mut Cx1: Vec<Foo>,
    baz(),
{
…
}

fn baz<'a>(g: Wow, h: Even, i: More) -> &'a Cx3
using 
    mut Cx3: Vec<Baz> + 'a,
    mut Cx2: Vec<Bar>,
{
…
}

In this bikesheddable version, foo declares in its signature that bar's context is in play, but that it's opaque to foo (so I know that foo itself doesn't touch any part of the context, but does need a context set up for bar).

In turn, bar declares that it uses Cx1 from the context, and that Cx1 is a Vec<Foo>; it also needs all of baz's context available for passing through. And baz declares that it uses Cx3 and Cx2 from context, but nothing more.

I can also see from baz's signature that the lifetime 'a is related to Cx3 somehow. And, in this model, if baz needs read-only access to Cx1 now, its signature would change:

fn baz<'a>(g: Wow, h: Even, i: More) -> &'a Cx3
using 
    Cx1: Vec<Foo>,
    mut Cx3: Vec<Baz> + 'a,
    mut Cx2: Vec<Bar>,

This tells me that it can read Cx1 - and because of the baz() syntax in bar's declared context needs, it automatically picks up this requirement, even if baz didn't already need Cx1.

Also note in here that foo declares that it does not touch the context - it just passes through enough to be able to call bar. bar declares that it can modify Cx1, and passes through what baz needs. The modified baz says it reads Cx1, and modifies Cx3 and Cx2.

3 Likes