I want to expand a little on how the rust pointer types relate to the corresponding BitC binding types. I think Rust is confusing data types and region types in its current description of the semantics.
BitC started with by-reference parameters, and soon added something that we initially called "ref" bindings. What happened was that we had a rewriting pass anticipating Henderson-style safe GC that created a local on-stack binding for every parameter, and we needed a way to record the fact that this binding must not get captured. The result is very similar to - and strictly more general than - a Rust borrowed pointer. Internally, we never bothered to introduce (by-ref 'a) as a first-class type. We treated those as being of type 'a with a marker bit indicating that the final code emitter needed to add an extra dereference. This ultimately created a problem, because it meant we couldn't check type class method type agreement when we went to do input streams, but that's a story for another day. The point is that until we hit the method overloading problem we didn't care, because by-ref parameters and by-ref bindings were guaranteed to be non-escaping by virtue of their lexical and syntactic structure. So on a parameter, BY-REF implied NOESCAPE, where in the internal let bindings LET REF would probably have been labeled better as LET NOESCAPE x = <intiializer> in .... Now here's the point: when a LET NOESCAPE binding is bound to a new allocation, it is necessarily the point where the allocated object must go out of scope. Further: objects allocated in this fashion necessarily obey a strict stack discipline in their allocations and deallocations. Further, if the underlying initializer can handle it and the size of the target object is know, the object can be stack allocated. And then the constraint is that such a binding can only be passed as a non-escaping parameters, and can only be captured by bindings that we know will go out of scope sooner than the dominating binding. In fact, the only time you *can't* stack-allocate the value is when the size of the target type is unknown. Or when the target system imposes constraints on overall stack size or introduces stack red-zone problems, but those are problems of implementation that can be solved with a separate allocation stack. Very shortly thereafter it became apparent that something a bit more flexible than non-escape was needed. I decided we needed regions, but we never got to them. The point I think I'm trying to make is that NOESCAPE is actually a region constraint, and region constraints are strictly more powerful than the owning pointer notion. But more importantly, NOESCAPE and OWNED describe the *region type* of a binding rather than the *data type* of a binding. The other thing you get when regions are introduced is the ability to name, bind and pass regions as first-class types. At that point you can allocate objects within specific regions of the heap, and you can do both local GC's of that region and bulk deallocation of the region. Regions aren't a cure-all. It's very common for objects within a region to become unreferenced in real programs, and there are examples of obvious real-world programs in which automatically inferred regions grow without bound as a result. But if you're going to add them, I think it's better to do them in a first-class way, not as a bolt-on side effect of an unusual pointer type annotation *or* an unusual binding type annotation. Jonathan
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
