Is there anyway to get a hold of a computed property's closure?

So computed property is basically the same as member func, but it's "call'ed" without the () postfix.

Is there anyway to "get" the closure of a computed property?

struct Foo {
    func bar() -> Int {
        444
    }

    // baz is baiscaly the same as bar()
    // but is there anyway to get a hold of this closure?
    var baz: Int {
        100
    }
}

func take(_ closure: () -> Int) {
    print(closure())
}

let foo = Foo()
take(foo.bar)
// now I want to give it baz as closure
take(foo.baz???)

You could just use the closure,

{ [foo] in foo.baz }
{ [a = foo.baz] in a }

computed properties are supposed to look like stored properties to begin with.

It's impossible to pass the accessor directly as a closure currently, but there's no inherent reason why it couldn't be allowed later with some special syntax.

Still, the question is why you would need it. As @Lantua mentiones, computed properties are meant to look and work like stored properties. Specifically, this allows them to change their implementation to stored properties and vice versa without affecting the call site:

struct Square1 {
    var sideLength: Double = 0
    var area: { return sideLength * sideLength }
}

struct Square2 {
    var sideLength: Double { return sqrt(area) }
    var area: Double = 0
}

— both these cases will look the same when accessing square.sideLength and square.area given a variable square of either of those types.

so I can use it in store property syntax and be able to get to its closure. Just like propertyWrapper: it's used just like any plain variable, but you can also get to its projection. Maybe we should be able to work it this way:

take(foo.$baz)

so we don't need to use boiler plate.

That syntax would be ambiguous if baz uses property wrapper. I'd refrain from using property-wrapper-related syntax since that'd be confusing even if it's unambiguous.

That is what you want, though, not why you want it. If the goal is brevity, then closure expression is the best you have at the moment. If your aim is to reduce the boilerplate, then I'd assume that you have a lot of similar boilerplates, to which I'd advise that you use functions instead of computed properties.

It's been a computed property already. Sometime later, I needed to refer to its closure and I just wish to minimize change.

I can simply add without affecting any existing code:

func bazClosure() -> Int { baz }

but better if the compile can do it for me...

Then use @Lantua's suggestion and wrap the property in a closure. If you are sure that foo won't change, you can even remove the explicit capture and the only change would be the replacement of round brackets with curly ones. The call site is almost the same:

take(foo.bar)
take{foo.baz}

If it's a let variable, then you wouldn't need capture list, so you only need an extra pair of {}, which is pretty hard to beat. And if it's a heavy computation, it'd be better to compute it before putting it in the closure:

let baz = foo.baz
{ baz }

One thing I can think of is @autoclosure, which is very limited, and I really suggest against using it unless you really know what you're doing. Those that are passed to @autoclosure should be guaranteed to remain constant, which is a tricky requirement for the caller.

2 Likes
Terms of Service

Privacy Policy

Cookie Policy