On Tue, Dec 23, 2014 at 11:30 AM, Geoffrey Irving <[email protected]> wrote:
> On Tue, Dec 23, 2014 at 10:51 AM, Jonathan S. Shapiro <[email protected]> > wrote: > > On Tue, Dec 23, 2014 at 9:20 AM, Geoffrey Irving <[email protected]> wrote: > > > Actually, it's way worse than that. It's not as simple as shallow vs. > deep. > > There are valid use cases for deep partial mutability, and genericity > over > > that presents some interesting challenges. You very rapidly get into the > > const vs. non-const vs. generic-over-mutability methods sort of problem. > > A lot of my C++ code looks like const Array<const ...>, so I'm very > aware of the pain of mixing different kinds of mutability. :) > That's actually a great example to throw at C++ programmers that should have jumped out at me. When you've had a chance to see the inductable mutable list case you'll appreciate that it gets worse from there if you really want to deal with mutability typing in a first-class way. > I don't see why lazy closures require deep immutability. They may or may > not > > require shallow immutability. Actually, I'm not sure why we're getting > into > > lazy closures at all. > > They don't *require* deep immutability, but one runs into screwy bugs > without it. The Scala error I was referring to looked like > > var error = ... > ... > val x = bad(error) > error = null > > It looked fine, but bad took its argument by name, so it was really > bad(() => error). The correct code was > > var error = ... > ... > val e = error > val x = bad(e) > error = null > > so that the implicit closure accessed an immutable value. If you > don't have language support for ensuring deep immutability, tracking > down bugs in closures becomes significantly harder. > Hmm. I still think this is shallow immutability, but I'm starting to see the problem. I'd argue that the *real* problem here is that bad() takes its argument by name. I'm not sure whether Scala actually means to be saying 'pass by name" (in the sense of Algol) or "pass by reference". The difference is subtle, and there are tricky security implications to pass by name. Whether your case is deep or shallow depends (I think) on whether "bad" and/or "error" are boxed. In BitC, the argument passing options are "pass by value" or "pass by reference". But note that we're taking a reference to a potentially stack-allocated thing here, and that makes for an unholy mess when we start talking about closure capture. but the real issue here is the combination of taking a reference with poorly chosen escape constraints. The relevant rules in BitC are: 1. A reference may not escape the region of it's creation. 2. The region of a return value is necessarily the outermost region associated with a procedure. 3. Absent an explicit region annotation, every LET binding forms a new region. In your case, the closure escapes via the return, which means that it's region is *outside* the region of the by-reference parameter, so capturing the reference violates [1] and is diagnosed as an error by the compiler. In BitC v0 a simpler rule applies: by-reference parameters cannot escape, and therefore cannot be captured by continuations. > We're saying the same thing, except that I'm using the wrong words. > By "unboxing support", I mean the ability for the language to express > things that are by definition unboxed, not the ability of the > optimizer to notice that a boxed thing can be unboxed. > Ah. That makes more sense to me. Thanks for clarifying. In Scala, you can reference vars in closures without complaint (see > above), but there's no support for warning you if the resulting > closure isn't pure. > Sounds like the absence of effect types is biting you here. shap
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
