On Tue, Dec 23, 2014 at 12:14 PM, Jonathan S. Shapiro <[email protected]> wrote: > > 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.
This example is shallow immutability, but it would become deep immutability if error was a field in a captured struct. Scala's "by name" parameters are just sugar for passing a parameterless closure. For purposes of this discussion, the code is really just bad(() => error). > 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: > > A reference may not escape the region of it's creation. > The region of a return value is necessarily the outermost region associated > with a procedure. > 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. Yep, sufficiently powerful effect types solves all these problems. Sufficiently powerful might be hard to arrange in some cases, but that's a different question. Not sure if this is the right time to discuss it, but the canonical example would be: will the effect system be able to implement a lazy data structure that seems pure from the outside? Feel free to ignore/table that question. Geoffrey _______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
