Proposal: Extend unnamed let variable scope


(Jason Pollack) #1

I was experimenting in Swift with RAII, a technique I find very useful from
C++. In general it works well, but there is something I found unexpected.

Consider this class:

class RAII {
    init() {
        print("some resource acquired")
    }
    deinit {
        print("some resource released")
    }
}

And this sample code:

        let b = true
        if (b)
        {
            print("Entered scope")
            let raii = RAII()
            print("Going out of scope")
        }
        print("Left scope")

As expected, I see the output:

Entered scope
some resource acquired
Going out of scope
some resource released
Left scope

However, the compiler gives me a warning on the 'let raii = ' line:
"Initialization of immutable value 'raii' was never used; consider
replacing with assignment to '_' or removing it"

If I change that line to:

let _ = RAII()

the warning goes away, but I get the unexpected output:

Entered scope
some resource acquired
some resource released
Going out of scope
Left scope

It appears the object instance is being destroyed immediately after being
created, because the compiler correctly sees that nobody needs it.

Therefore, I propose that such instances stay referenced until the end of
the scope they are declared in.

(As an aside, I would like to see a deinit on a struct to support this
technique as well.)

Thanks,
-Jason-


(Joe Groff) #2

I was experimenting in Swift with RAII, a technique I find very useful from C++. In general it works well, but there is something I found unexpected.

Consider this class:

class RAII {
    init() {
        print("some resource acquired")
    }
    deinit {
        print("some resource released")
    }
}

And this sample code:

        let b = true
        if (b)
        {
            print("Entered scope")
            let raii = RAII()
            print("Going out of scope")
        }
        print("Left scope")

As expected, I see the output:

Entered scope
some resource acquired
Going out of scope
some resource released
Left scope

However, the compiler gives me a warning on the 'let raii = ' line: "Initialization of immutable value 'raii' was never used; consider replacing with assignment to '_' or removing it"

If I change that line to:

let _ = RAII()

the warning goes away, but I get the unexpected output:

Entered scope
some resource acquired
some resource released
Going out of scope
Left scope

It appears the object instance is being destroyed immediately after being created, because the compiler correctly sees that nobody needs it.

Therefore, I propose that such instances stay referenced until the end of the scope they are declared in.

ARC does not normally guarantee scoped lifetimes; the optimizer will shorten lifetimes so that objects get released after their last use, not when their variable goes out of scope. If you don't use the result of a computation at all, it will likely be immediately released. You can use `withExtendedLifetime` to set a minimum bound for the lifetime of a reference:

withExtendedLifetime(RAII()) {
  print("Going out of scope")
}

(As an aside, I would like to see a deinit on a struct to support this technique as well.)

If structs support destructors, then they potentially also need to support copy constructors and all the other complexity of C++ to describe what happens when they get copied. Resources really do have referential identity in practice; classes are the appropriate way to model them.

-Joe

···

On Dec 10, 2015, at 8:46 AM, Jason Pollack via swift-evolution <swift-evolution@swift.org> wrote: