Erick Tryzelaar wrote:
Well, we need the MutableMap-style traits, but we could fold the ImmutableMap-style "insert into a copy" methods to Map. I don't think we can rely on "&mut self" helping us out because it could be a source of bugs. For example, if w forget a hashmap is currently immutable and do "m.remove(x);" nothing actually happened.

One idea regarding remove and friends would be to structure the traits something like this.

First there would be your basic `Map` trait that assumes operations take effect "in-place":

    trait Map<K,V> {
        fn add(&mut self, k: K, v: V);
        fn remove(&mut self, k: &K);
        ...
    }

In a persistent map, there must be some other operation that returns a new map, let's call them plus and minus:

    trait PersistentMap<K,V> : Map<K,V> {
        fn plus(&self, k: K, v: V) -> self;
        fn minus(&self, k: &K) -> self;
        ...
    }

In that case, add and remove can be implemented in terms of plus and minus fairly easily:

    trait PersistentMap<K,V> : Map<K,V> {
        ...
        fn add(&mut self, k: K, v: V) { *self = self.plus(k, v); }
        fn minus(&mut self, k: &K) { *self = self.minus(k); }
    }

Here I am assuming an impl something like:

    impl<K,V> PersistentMap<K,V> for @PersistentHashMap<K,V> {
        ...
    }

Note that `@` sign in the impl. I think this would be required for this scheme to work out.

The neat thing about this is that persistent maps can be used anywhere a "normal" map is expected. In fact, you'll note that *persistent maps* and *freezable maps* work pretty similarly. That is, if I have a function like this:

    fn do_something<M:Map<int,int>>(m: M) { ... }

If `m` is a freezable map, like send_map, then `m` is *consumed* by `do_something()` and thus the caller of `do_something()` can never see the changes that `do_something()` made. If `m` is a persistent map, the same is true, except that the caller may hold on to its original copy of `m`---but in any case the caller cannot see what `do_something()` has done. If `do_something()` wants its changes to be visible to the caller, it should be declared with a borrowed pointer:

    fn do_something<M:Map<int,int>>(m: &mut M) { ... }

Basically what I'm getting at here is that both *freezable* and *persistent* maps share the property that they *act like immutable values*. This is true *even though* freezable maps are modified in-place, because *at the time of modification* no aliases exist, so who's to say you didn't swap in a new map?



Niko
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to