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

Closures in API design

Closures in API design

Avatar for Hermes Pique

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.