Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Closures in API design

Closures in API design

Hermes Pique

March 21, 2015
Tweet

More Decks by Hermes Pique

Other Decks in Programming

Transcript

  1. Using closures func showButton() { UIView.animateWithDuration(0.5, animations: { self.button.alpha =

    1 }, completion: { finished in if finished { self.button.enabled = true } }) }
  2. func showQuestionAlert() { questionAlert = UIAlertView(title: "Question", message: "Pigeons are

    the new cats?", delegate: self, cancelButtonTitle: nil, otherButtonTitles: "No", "Coo!") questionAlert.show() }
  3. // MARK: UIAlertViewDelegate func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {

    if (alertView === questionAlert) { switch buttonIndex { ... } } } func alertView(alertView: UIAlertView, didDismissWithButtonIndex buttonIndex: Int) { if (alertView === questionAlert) { questionAlert = nil } }
  4. func showQuestionAlert() { let controller = UIAlertController(title: "Question", message: "Pigeons

    are the new cats?", preferredStyle: .Alert) let no = UIAlertAction(title: "No", style: .Default) { _ in ... } controller.addAction(no) let yes = UIAlertAction(title: "Coo!", style: .Default) { _ in ... } controller.addAction(yes) self.presentViewController(controller, animated: true) { ... } }
  5. Short-circuit with closures func and(left: Bool, getRight : () ->

    Bool) -> Bool { if !left { return false } return getRight() } let result = and(false, { return getExpensiveBool() }) >
  6. Adding @autoclosure func and(left: Bool, @autoclosure getRight: () -> Bool)

    -> Bool let result = and(false, getExpensiveBool()) >
  7. @autoclosure in the Standard Library func &&<T : BooleanType>(lhs: T,

    @autoclosure rhs: () -> Bool) -> Bool func assert(@autoclosure condition: () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = default, line: UWord = default)
  8. Using loop class MYView: UIView { func animate() { loop(duration:

    0.5, reverse: true) { self.scale(1.25) } } func scale(scale: Double) { ... } }
  9. What does loop do? loop(duration: 0.5, reverse: true) { self.scale(1.25)

    } 4 Call animations on every cycle? 4 Call once, take snapshots and animate between them?
  10. No need for self class MYView: UIView { func doAnimations()

    { loop(duration: 0.5, reverse: true) { scale(1.25) } } func scale(scale: Double) { ... } }
  11. Forward compatibility 4 Removing @noescape might break user code 4

    Only add if sure that the function will never call the closure asynchronously
  12. Swift translation func fetchImage(success: (UIImage -> Void)?, failure: (NSError ->

    Void)?) fetchImage(success: { image -> Void in save(image) }, failure: nil)
  13. nil as default func fetchImage(success: (UIImage -> Void)? = nil,

    failure: (NSError -> Void)? = nil) { ... if let success = success { success(image) } } fetchImage(success: { image -> Void in save(image) })
  14. No optionals func fetchImage(success: UIImage -> Void, failure: NSError ->

    Void) fetchImage(success: { image -> Void in save(image) }, failure: { _ in })
  15. Empty closure as default func fetchImage(success: UIImage -> Void =

    { _ in }, failure: NSError -> Void = { _ in }) { ... success(image) } fetchImage(success: { image -> Void in save(image) })
  16. Defining noop func noop() {} func noop<T>(value: T) {} func

    noop<T>() -> T? { return nil } func noop<T, S>(value: T) -> S? { return nil }
  17. Compensating with documentation /// Fetches an image. /// /// :param:

    failure Closure to be called on failure. Default: noop. /// :param: success Closure to be called on success. Default: noop. func fetchImage(failure: NSError -> Void = noop, success: UIImage -> Void = noop)
  18. Closures encourage code locality Use @autoclosure for parameter values that

    might not be used Use @noescape for closure parameters that will not outlive the function call
  19. Prefer no-op closures as default values for closure parameters Consider

    the trailing closure when defining parameter order Be mindful of how consumers will discover your APIs
  20. BCPL: the origin of {} GET "libhdr" LET start() =

    VALOF $( writes("Hello, World!*n") RESULTIS 0 $) Created by Martin Richards in 1966.