How can I change a "context" with is shared between closures?


#1

Hi,

I have some closures stored in a hash map. They get the same param (a vector). In certain cases I’d like to switch my concrete vector, so that every closure get the same new vector when they are called. Can someone help me with that?

My example is here (a Rust port of The Super Tiny Compiler). I set my vector here initially and would like to use a new vector here. This doesn’t work because arguments does not live long enough. But I’m not sure how to fix this. I tried to box my vector somehow, so that the box is always the same and I only change its value. But it doesn’t seem to work.


#2
  1. You could try std::mem::swap(), which I think would work since it takes &mut args, https://doc.rust-lang.org/std/mem/fn.swap.html

At the end of closure:

    std::mem::swap(context, &mut arguments);
  1. If it is more like a global state that is being operated on, which sounds like what a compiler does to me, then a RefCell() might not be a bad way to keep that as a model.

  2. If the closures are supposed to be getting called in a pipeline, that is, one is really expecting to have the output of another, then maybe the Vec is really the return value of the closure, to be passed to the next closure in the chain. That would make the signature for the closures something like:

| node: &Node, parent: Option<&Node>, context: Vec<TransformedNode> | -> Vec<TransformedNode>

So a visitor that doesn’t do anything just gives ownership a back of the passed in context.


#3
  1. Thank you, I’ll check this out! :heart:
  2. I guess this will not be possible. I really try to map a tree structure into a different tree structure.

#4

Doesn’t seem to be enough, because arguments is used later here. I tried several ways, but it didn’t seem to work.

I’ll try RefCell now.


#5

Hmm… Is it even possible to change the inner value of a RefCell later on? Can’t find an example for that :frowning:


#6

You have use borrow_mut() to be able to change its value.

https://doc.rust-lang.org/1.6.0/core/cell/struct.RefCell.html#method.borrow_mut

This would mean that you would then have to make sure it is not being modified at the same time manually, instead of being able to rely on the borrow checker.

Trying to save a reference to a value that is expected to change in the future while ownership is not explicit is unsafe, something that rustlang tries to prevent, with things like RefCell<Rc<>> being a way to get around those limitations, so I’m not sure the first 2 options I gave would be considered idiomatic, where option 3 would make the code easier to reason about because there is less shared mutable state.


#7

@donaldpipowitch, have you considered using references to the Vec inside your nodes rather than some of them (like the one in the snippet you linked) trying to own it? It seems like it should work from a lifetime perspective: you start the transform phase of your compiler with an allocated Vec, run the closures passing them a ref, and then get the “filled out” Vec at the end.