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.

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