Blog post: Contexts and capabilities in Rust

Also, use case for capturing contexts is async fn: the resulting future is probably preferred to be polled with singular context instance. Also there are impl level with bounds with similar reasoning.

It looks like there is convergent evolution in this new Scala proposal.

4 Likes

What's about context defaults? Being able to declare a default context value may allow the likes of this:

enum LookUpOrder {
   InOrder,
   PreOrder,
   // others
};
capability TreeTraversalOrder = LookupOrder;

// some tree data structure...

impl Hash for SomeTreeDataStructure with (TreeTraversalOrder = const {LookupOrder::InOrder}) { // `const` here for clarity
   ...
}

The example may not be great, but the idea must be clear.

Also, what about with bound impls of special traits (like Drop or Derefs)?

One interface that would be possible with this proposal is:

static LIBRARY: LibraryHolder<"lib name">;
...
impl<const NAME: &'static str> Deref(Mut) for LibraryHolder<NAME> with alloc::library::Library<NAME> {...}
...

// and the usage would be 
with alloc::library::Library<"lib name"> = load_library("path/to/lib")? {
   ...
}

Then, code from with bounded glue modules can be easily called.

The closure moment:

let a = impl Fn(u8);

with logger: LoggerMut = &mut ... {
    a = |byte| { logger.log("boom") };
}

The problem is this code threads a mutable context reference through closure - forbids it from being impl Fn. It may be a problem for existing code; what can be done to mitigate it is to say that closures also can declare explicit with bounds (to support the case from example) and they don't capture contexts that contain mutable references.

Also, we can make implicit with bound on closures to be based on its captives:

  • if closure is Fn then it threads only immutable context;
  • if closure has mutable captures - both, immut and mut context;
  • move closures thread all the context
  • if closure has no captures - it threads no context.
1 Like

Very promising news on this topic.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.

Sorry if I'm reviving an old discussion, but on the "infer by name" vs "infer by type" question, is it necessary that with clauses be able to declare variables? What if it was import-only and not inferred at all?

Borrowing an example from the blog, the alloc here could be an unambiguous import of super::alloc and not an associated variable that we might have trouble binding.

context alloc: impl Allocator;

impl Deserialize for Foo {
    fn deserialize<'a>(bytes: &[u8]) -> Result<&'a Foo, Error>
    with
        alloc,
    {
        /* ... */
    }
}

I don't know if it would still be possible for deserialize to specify additional bounds on alloc if alloc is simply an import, but IMO even this kind of "shadowed static variable" form would be very useful.

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.