Enforcing that a Fn(T) is pure - i.e. doesn't access 'static

I have an API where a user provided callback must depend only on its arguments, so that I can reliably rerun it when its dependencies change. Essentially I need to prevent it from accessing `'static'. Is there a way to enforce this in the type system?

I've been trying to make GhostCell style invariant lifetime trickery work with something like Fn(T) + 'id, but I haven't found a way that works yet. Can this be done?

No, I don't believe this is possible.
But I also believe to read an immutable static string is ok for a pure function. So I do not understand your use case.

There is no way to enforce that a function is a pure function. Lifetimes don't help because a Fn can have an Arc in it — and even a fn can call a system call to read the clock or file system.

That's true, a static string is ok. But e.g. reading from static foo: AtomicU32 = AtomicU32::new(0); isn't.

Yeah that makes sense, although it's unfortunate. So is is not possible to do any better than documenting that a passed closure should be pure?

In Rust it isn't possible to enforce function purity. A simple counterexample is that you can put a println!() in pretty much any fn and it'll compile fine.

That's correct, at least at this point in time.


Technically I have no problem with println!() style leakage. My goal is to have a set callbacks that get recomputed when their dependencies change, so I want to be able to know all of their dependencies.

Oh well, I guess documentation (and maybe a custom lint if I care enough) is the best I can do for now. It feels like a safety hole in the API, but I can live with it. Thanks.

I believe that documenting it is what has generally been done, for e.g. salsa if you want to go beyond documentation, you'll need to use an external checker/pure marker attribute. I know that at least prusti has this Pure functions - Prusti user guide but perhaps other checkers as well.

Edit: I guess I should mention that while I don't believe it is possible to add trait bound like Fn(T) + Pure you could maybe wiggle a FnPure(T) with an f: Fn(T) field I haven't tried though.

1 Like

In practice there is quite a bit of overlap between the abstract notion of purity and the actual mechanics behind const; so one can, for instance, require that something be pure by making the even more restrictive check of requiring it be const, currently by using a macro API which will feed the received body to an anonymous const or something :sweat_smile:

  • Maybe in the future impl const Fn… may, on the other hand, be a more serious approach to this idea :person_shrugging: