1

I have a question for auto closure. For example, we can have a function that have an auto closure like this

func logHello(ifFalse condition: Bool,
         message: @autoclosure () -> String
    ) {
    guard condition else {
        return
    }
    print("Assertion failed: \(message())")
}

the reason why auto closure is used more of the time is because we wish to delay the execution of the closure to the body of the function, but what is the point of it?

I can have something like this

func logHello1(ifFalse condition: Bool,
              message: String
    ) {
    guard condition else {
        return
    }
    print("Assertion failed: \(message)")
}

not using a closure at all, but just the end result what the closure might produce. Isn't this better?

I have seen aotuclosures used in assertion and other implementations of swift native functionalities, but it just puzzles me why can't we just pass in aliteral in place of the closure?

What is the advantage of using auto closure in this case?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
progammingBeignner
  • 936
  • 1
  • 8
  • 19
  • Possibly a duplicate of https://stackoverflow.com/questions/24102617/how-to-use-swift-autoclosure. At least related? – rmaddy Jun 11 '19 at 00:26
  • @rmaddy I understand what auto closure is.. and the reason it is used.. I don understand why string literal is not preferred over it when it makes a lot of common sense. – progammingBeignner Jun 11 '19 at 00:32

1 Answers1

1

You seem to have answered your own question: "because we wish to delay the execution of the closure to the body of the function." The key point in this case is that you may never evaluate the string at all. If the assertion is true, there's no need to compute the string.

Consider as a concrete example:

logHello(ifFalse: true, message: expensiveString())

With an autoclosure, expensiveString() will never be called. Without, it will always be called, even though the result is never used.

In my experience this is often much more trouble than it's worth for modern mobile or desktop apps. But that's the goal of it. For server processes, logging performance is a serious issue that needs careful consideration, but I rarely run into logging performance issues on mobile or desktop that isn't best addressed by just removing the logging statement entirely.

You're correct that there's no performance advantage over a string literal, but if that's what you mean, the message parameter should be StaticString, not String.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thank you for the answer. But can i ask why the choice of closure over literal? For example, like assertion function. Isn't it more intuitive to have it as string literal than to have a closure (because closure will mean, to evaluate something, which in this case it does not). I just can't get over the confusion on this. – progammingBeignner Jun 11 '19 at 00:29
  • I don't think I understand what you mean here by "literal." That means StaticString in Swift, which I agree is what this often should be, but I don't think is your real question. Closures do not mean "to evaluate something." They mean "a function that can be evaluated." In your example, the function will likely never be evaluated. – Rob Napier Jun 11 '19 at 00:32
  • but if you look at the example i have provided, which i have used a string literal, it will perform the same functionality right? – progammingBeignner Jun 11 '19 at 00:33
  • Yes, but you *could* pass other things than a string literal. If you want to *require* that it be a string literal, you'd use `StaticString`, but often people mean something like `"failure evaluating: " + object.description` which is not a literal, and may be expensive to compute. – Rob Napier Jun 11 '19 at 00:35
  • yes, so either way.. why use auto closure? since the performance is the same? over staticString? Or, there is no particular reason, just a preference? – progammingBeignner Jun 11 '19 at 00:42
  • The performance is not the same. If calling `expensiveString()` is expensive, then it's much faster never to call it. In most cases, it will never be used, so it's a win not to call it; that's what autoclosure is achieving. You have to stop thinking of it as "opposed to static string." `String` is not "a static string." It can be a computed string. StaticString is a static string, but you can only pass it literal strings, not computed strings. That definitely is faster, but less flexible. – Rob Napier Jun 11 '19 at 00:44
  • That is not what i am asking. I am not asking autoclosure vs closure.. I am asking autoclosure vs string (or static string if you want to it to be static string). What is the benefit of having autoclosure vs static string? How is less flexible? When both of them are decided during compile time – progammingBeignner Jun 11 '19 at 05:01
  • A string can be the result of a function, and that function may take a long time to evaluate. In this particular code, it is very likely that there is no reason ever to evaluate it, so a closure (or autoclosure; there's no difference in this) is much more efficient because it never has to create the string. You seem to be thinking only in terms of `logHello(..., "message")`, but it can also be `logHello(..., someFunction())` where `someFunction()` returns a string. With an autoclosure, `someFunction()` will only execute if needed. If the type were String, it would always have to be run. – Rob Napier Jun 11 '19 at 12:06