Mutabiity inference is probably the most complex thing we attempted in BitC, and we got it wrong. I think the *issues* aren't hard to summarize:
1. When a constituent field of an object is "immutable", but the entire object is not, what does that mean? The choices are: (a) it prevents any assignment that would cause the corresponding *location* to change, or (b) the property holds only for the lifetime of the containing object. In the presence of unboxed types and concurrency, these two definitions are very, very different. 2. Is mutation a property of a location, or a type, or is the thing we really care about more a statement about behavior? In hindsight, I now think that the property I was really trying to grapple with might be described more accurately as "invariance". We have some object that is evolving, and at some point it becomes desirable to say two kinds of things: 1. Certain parts of the object will not change for the remainder of the object's lifetime. The cases that seem *useful* seem to be closely related to notions of typestate. 2. Certain parts of a (passed) object will not *be* changed by a given procedure. As a naive example, it can be useful if the *value* in a list element is mutable but the next pointer is not. This guarantees that if you hold a pointer to a list, the length of that list does not change. This notion of invariant seems to me to have much the same "metaconstructor" feel that the current const/mutable notions have in BitC, except that it seems to me that we want to be able to use explicit labels here to support unification. In particular, *some* lists want to have unchanging length, but not all of them. Should this be two distinct types, or should the list type be designed in such a way that we can specify at construction time whether the value field is invariant? I'm very much at a loss about how to think about this. I would appreciate input. The cases that are compile-time invariant [shallowly or deeply] seem pretty straightforward. The cases that involve mixed invariance seem more complicated. So some questions: 1. Is this worth it? It seems to be driven by the desire to mix imperative and pure programming without an explosion of type definition variations (due to case analysis getting embedded at the type level). 2. How do we think about object sharing across concurrency *without* some ability to talk about this? 3. Any pointers on things I might read? Jonathan
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
