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

These are some excellent questions!

No. A contextual parameter can be more private than the realm in which it's contained.

Removing a non-public contextual parameter from the realm is a non-breaking change since external crates can't observe the change. That is, of course, unless the borrow sets of public functions also change in tandem.

Removing a public contextual parameter from a realm is a breaking change, however, since users may attempt to access that parameter using that realm.

Adding any contextual parameter (whether public or private) into a realm also isn't a breaking change by itself.

It is a breaking change to add usages on additional contextual parameters. That's why #[borrows_only] exists. It is, however, always fine to remove usages since this can only allow new code to compile that didn't compile before. You don't have to worry about inadvertently weaking these sets, though, since #[borrows_only] also defines to the actually borrowed set.

This is always a compile time error—just as it was in the prototype AuToken.

If parameters which aren't actually used are not supplied, it's not an error.

Yes. Changing actual borrow sets has to be a breaking change anyways so we might as well permit users to provide partial context.

Ah, I see why you asked additions to and removals from existing realms. Yes, my answers to those two questions still hold.

Nope! Even with the AuToken prototype, I tried my hardest to keep behavior consistent between inter-crate and intra-crate scenarios.

The only exception is that you can't define new context parameters in realms defined by an upstream crate since there really isn't a reason to do that. Also, I think I'm going to adopt the new realm definition syntax you proposed to avoid this problem entirely.

Requiring this would break the bounded refactors principle. But, yes, users are encouraged to explicitly declare actual borrow sets for functions in their public interface by a warn-by-default rustc lint.

There's a lint force this. It's not on by default because I've heard opinions that other users who don't want to have to use the annotation. This is probably going to be a source of bike-shedding.

Thanks for the feedback! I was under the impression that the rules about generics would be intuitive since they're mostly defined by what the feature doesn't support. Are there specific things that are confusing or is it just generally difficult to follow?

It isn't supported because it creates a lot of hazards for semantic versioning. See the "semantics of generics" section of the AuToken README and my first design comment in this thread for details on how I got to this rule-set.

To pass context parameters to closures, so long as the closure does not have to live for 'static, you can do:

// Acquires a bundle with a fresh inference set.
let cx = infer_set!();

use_closure(|| {
    // Binds the bundled variables in the current function's scope.
    // The inference set is automatically extended to include everything
    // needed by this function.
    bind cx;

    ...
});

There's no way to make this work if the closure has to live for 'static, regardless of the rule-set chosen, since contextual parameters are all references.

Sorry, I'm going to need to enlist the help of a backend person to help me answer than question. :sweat_smile:

Good suggestion!

These do actually have a pretty significant difference: the former syntax with the : denotes a realm that can contain context items of its own whereas the latter with the = denotes a realm that cannot contain context items of its own. This is important because, in the following example:

// Upstream crate
realm Foo;

realm Bar;

// Downstream crate
fn foo() use Foo {
    bar();
}

fn bar() use Bar {
    foo();
}

It's desirable that Foo and Bar unify by name rather than by their sets of contextual parameters since, otherwise, adding any context becomes a breaking change!

However, sometimes, you do actually just want to refer to the union of realms Foo and Bar without having to write that every single time. That's why aliases exist:

realm Foo;
realm Bar;

realm MyAlias = Foo, Bar;

Realm aliases can't have context parameters of their own since it's unclear what that means.

I think we can keep the = syntax so long as we use the...

realm RealmAlias = Foo, Bar;

realm CompositeRealm1 {
    use MyRealm1;
    use MyRealm2;
    // possibly more `ctx` declarations here
}

...syntax you recommended.

Good suggestion. I think I updated it for bundle binding syntax but forgot to update it for individual context parameter binding.