"Type-safe metaprogramming in Swift? Let's talk about sourcery" by Krzysztof Zabłocki

"Type-safe metaprogramming in Swift? Let's talk about sourcery" by Krzysztof Zabłocki

Author's note: Swift has very limited runtime support and no meta-programming features.
Lets take a look at recently released Sourcery and how it can be applied in variety of different use-cases to make development more powerful and enjoyable, while at the same time limiting amount of human mistakes.
This talk was made for CocoaHeads Kyiv #12 which took place July 22 2017.

Db84cf61fdada06b63f43f310b68b462?s=128

CocoaHeads Ukraine

July 22, 2017
Tweet

Transcript

  1. Metaprogramming in Swift Krzysztof Zabłocki @merowing_

  2. What is metaprogramming?

  3. What is metaprogramming? » Metaprogramming means that a program can

    be designed to read, generate, analyse or transform other programs, and even modify itself while running.
  4. What is metaprogramming? » Metaprogramming means that a program can

    be designed to read, generate, analyse or transform other programs, and even modify itself while running. » But in reality the most common use case is to generate boilerplate code automatically
  5. Example of metaprogramming in Ruby from repetitions like this: class

    Developer def coding_frontend p "writing frontend" end def coding_backend p "writing backend" end end
  6. Example of metaprogramming in Ruby with metaprogramming: class Developer ["frontend",

    "backend"].each do |method| define_method "coding_#{method}" do p "writing " + method.to_s end end end
  7. Why would we want metaprogramming?

  8. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns:
  9. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality
  10. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality » Hashing
  11. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality » Hashing » Data Persistance
  12. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality » Hashing » Data Persistance » JSON parsing
  13. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality » Hashing » Data Persistance » JSON parsing » Writing and updating testing Mocks / Stubs
  14. Why would we want metaprogramming? Metaprogramming allows us to:

  15. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle
  16. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle » Write once, test once
  17. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle » Write once, test once » Ease maintenance costs
  18. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle » Write once, test once » Ease maintenance costs » Avoid human mistakes
  19. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle » Write once, test once » Ease maintenance costs » Avoid human mistakes » Experiment with interesting architecture choices
  20. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all
  21. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all » The problem isn't writing it.
  22. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all » The problem isn't writing it. » The problem is that when you change it e.g. add new variables
  23. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all » The problem isn't writing it. » The problem is that when you change it e.g. add new variables » You might not realize you forgot to update your boilerplate
  24. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all » The problem isn't writing it. » The problem is that when you change it e.g. add new variables » You might not realize you forgot to update your boilerplate » This can cause hard to track bugs
  25. Metaprogramming techniques in Cocoa

  26. Metaprogramming in Cocoa setValue(11, forKeyPath: #keyPath(MyClass.variable)) addObserver(self, forKeyPath: #keyPath(MyClass.updatedAt), options:

    .new, context: &context)
  27. Metaprogramming in Cocoa » Powerful runtime and reflection for Objective-C

    setValue(11, forKeyPath: #keyPath(MyClass.variable)) addObserver(self, forKeyPath: #keyPath(MyClass.updatedAt), options: .new, context: &context)
  28. Metaprogramming in Cocoa » Powerful runtime and reflection for Objective-C

    » Key Value Observing setValue(11, forKeyPath: #keyPath(MyClass.variable)) addObserver(self, forKeyPath: #keyPath(MyClass.updatedAt), options: .new, context: &context)
  29. Metaprogramming in Cocoa » Powerful runtime and reflection for Objective-C

    » Key Value Observing » Key Value Coding setValue(11, forKeyPath: #keyPath(MyClass.variable)) addObserver(self, forKeyPath: #keyPath(MyClass.updatedAt), options: .new, context: &context)
  30. Metaprogramming in Cocoa Not available for pure Swift objects

  31. What is available in Swift? Swift reflection Mirror(reflecting: object)

  32. What is available in Swift? Swift reflection » Allows you

    to learn a lot about types at runtime Mirror(reflecting: object)
  33. What is available in Swift? Swift reflection » Allows you

    to learn a lot about types at runtime » Read only Mirror(reflecting: object)
  34. What is available in Swift? Swift reflection » Allows you

    to learn a lot about types at runtime » Read only » Not very useful unless you start interacting with Objective-C runtime or KVC Mirror(reflecting: object)
  35. Will Swift add more powerful features in the future?

  36. Already in Swift 4

  37. Already in Swift 4 » New Key Value Paths

  38. Already in Swift 4 » New Key Value Paths »

    Deriving Equatable / Hashable
  39. Problems with metaprogramming

  40. Problems with metaprogramming » Usually untyped, mostly based on strings

  41. Problems with metaprogramming » Usually untyped, mostly based on strings

    » No compile time errors
  42. Problems with metaprogramming » Usually untyped, mostly based on strings

    » No compile time errors » Runtime evaluated » Easy to create inconsistent app state » Hard to debug
  43. Do we need to wait for Swift N to stop

    writing boilerplate?
  44. Sourcery

  45. What is Sourcery? Sourcery scans your source code, applies your

    personal templates and generates Swift code for you, allowing you to use meta-programming techniques to save time and decrease potential mistakes.
  46. Templates?

  47. Templates? Sourcery allows you to write AST aware code, that

    will generate more swift code (or anything you want really). We support three different templating engines:
  48. Templates? Sourcery allows you to write AST aware code, that

    will generate more swift code (or anything you want really). We support three different templating engines: » Stencil
  49. Templates? Sourcery allows you to write AST aware code, that

    will generate more swift code (or anything you want really). We support three different templating engines: » Stencil » Swift
  50. Templates? Sourcery allows you to write AST aware code, that

    will generate more swift code (or anything you want really). We support three different templating engines: » Stencil » Swift » EJS
  51. Templates? Stencil {% for enum in types.all %} {{ type.name

    }} {% endfor %}
  52. Templates? Swift <% for type in types.all { -%> <%=

    type.name %> <% } %>
  53. Templates? EJS - Effective JavaScript templating. <% for (type of

    types.all) { -%> <%= type.name %> <% } -%>
  54. Sourcery Features

  55. Sourcery Features » Powered by Apple own SourceKit

  56. Sourcery Features » Powered by Apple own SourceKit » Additional

    parsing on top of what SourceKit provides
  57. Sourcery Features » Powered by Apple own SourceKit » Additional

    parsing on top of what SourceKit provides » Generates regular Swift code » No runtime involved » Compiled » Typed
  58. Sourcery Features » Powered by Apple own SourceKit » Additional

    parsing on top of what SourceKit provides » Generates regular Swift code » No runtime involved » Compiled » Typed » Immediate feedback: Create new templates with real-time feedback.
  59. None
  60. Sourcery Features Source annotations Sourcery supports annotating your classes and

    variables with special annotations, similar to how attributes work in Rust / Java // sourcery: skipPersitance let transientValue: Int // sourcery: jsonKey = "user_name" let name: String
  61. Sourcery Features Inline code generation {% for type in types.all

    %} // sourcery:inline:auto:{{ type.name }}.TemplateName // sourcery:end {% endfor %} // it will add it at the end of your type definition: class MyType { /// code }
  62. How to integrate Sourcery?

  63. How to integrate Sourcery?

  64. How to integrate Sourcery? » Build phase for your project

  65. How to integrate Sourcery? » Build phase for your project

    » A lot of common templates are distributed with it
  66. How to integrate Sourcery? » Build phase for your project

    » A lot of common templates are distributed with it » When working on new templates use a daemon mode to get real-time feedback.
  67. Bundled templates Sourcery is already bundled with basic templates, that

    generate:
  68. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable
  69. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts
  70. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses
  71. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses » Mocks
  72. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses » Mocks » Diffing
  73. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses » Mocks » Diffing » LinuxMain
  74. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses » Mocks » Diffing » LinuxMain » Decorators
  75. Bundled templates Property level diffing for tests, meaning you can

    go from wall of text like this: To exact difference:
  76. Is it going to slow down my builds?

  77. Is it going to slow down my builds? » Fast

    parsing
  78. Is it going to slow down my builds? » Fast

    parsing » Caching
  79. Is it going to slow down my builds? » Fast

    parsing » Caching » Neglible cost in comparsion to Swift build time
  80. Demo

  81. Summary Sourcery available on GitHub: https://github.com/krzysztofzablocki/Sourcery

  82. Summary Sourcery available on GitHub: https://github.com/krzysztofzablocki/Sourcery » Eliminate boilerplate

  83. Summary Sourcery available on GitHub: https://github.com/krzysztofzablocki/Sourcery » Eliminate boilerplate »

    Write once, test once
  84. Summary Sourcery available on GitHub: https://github.com/krzysztofzablocki/Sourcery » Eliminate boilerplate »

    Write once, test once » Limit human mistakes
  85. Summary Sourcery available on GitHub: https://github.com/krzysztofzablocki/Sourcery » Eliminate boilerplate »

    Write once, test once » Limit human mistakes » Ease maintenance costs
  86. Summary Sourcery available on GitHub: https://github.com/krzysztofzablocki/Sourcery » Eliminate boilerplate »

    Write once, test once » Limit human mistakes » Ease maintenance costs » Create better architecture choices
  87. None
  88. None
  89. None
  90. None
  91. Questions

  92. Thank you for listening! Contact Krzysztof Zabłocki @merowing_ krzysztof.zablocki@pixle.pl