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

Property Wrappers

Eeb061c8b2816b771920da1b3e7904a3?s=47 Swift India
November 16, 2019

Property Wrappers

Eeb061c8b2816b771920da1b3e7904a3?s=128

Swift India

November 16, 2019
Tweet

Transcript

  1. Property Wrappers From IDEA to INDUCTION G ABHISEK Product Engineer

    @ GoJek
  2. Scope of Discussion • What are Property wrappers • Motivation

    behind Property wrappers • Glimpse on the evolution • Some uses of Property wrappers • Frameworks where they are used today • Future proposals
  3. Property Wrapper? • Property Wrapper is a generic data structure

    that wraps a property and specifies its access patterns. • Intended to remove boiler plate code that we write for custom getters and setters.
  4. Story behind Property Wrappers

  5. Proposal • Proposed as Property Behaviours. • Remove boiler plate

    code written for access patterns. • Remove inconsistencies of @NSCopying. • Aimed at addressing problem of repeated property patterns like lazy. Dec, 2015
  6. Our code Third party Frameworks and Libraries Standard Library Language

    Compiler
  7. • Proposal rejected sighting immaturity of Swift. • Swift was

    changing rapidly with changes in core APIs. Feb, 2016
  8. • Pitch #2 was submitted in March 2019. • Inspired

    and refined with inspiration from Delegated Properties in Kotlin. • Known as Property Delegates. • Pitch #3 was submitted in May 2019. • Initializer renamed. • Name was changed to Property Wrappers. • Syntax refined.
  9. Syntax @propertyWrapper struct PropertywrapperName<T> { var projectedValue = Something //

    Additional API that can exposed additional data var wrappedValue: T { get { // Custom logic for getter } set { // Custom logic for setter } } init(wrappedValue: T) {...} init(wrappedValue: T = Initial Value, additional params) {...} }
  10. Properties Setter/Getter Wrapper Structure

  11. • Minimum Value • Current value • Flexi interest Current

    value = current value + (interest)% * current value Growth = (current value > min value) ? Appreciating : depreciating
  12. struct WalmartFoodBond { var bondValue: Int { set { bondCurrentWorth

    = newValue + (newValue * flexiInterest/100) growth = bondCurrentWorth < minimumValue ? .depriciating : .appreciating } get { bondCurrentWorth } } private (set ) var bondName: String private (set ) var growth: BondGrowth = .appreciating private var bondCurrentWorth: Int private var flexiInterest: Int private var minimumValue: Int init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) { self.bondName = bondName self.minimumValue = minimumValue self.bondCurrentWorth = value self.flexiInterest = flexiInterest self.wrappedValue = value } }
  13. @propertyWrapper struct BondValue { private var bondCurrentWorth: Int private var

    minimumValue: Int private var flexiInterest: Int var projectedValue: BondGrowth = .appreciating // The projected value projects the growth for the bond var wrappedValue: Int { get { return bondCurrentWorth } set { bondCurrentWorth = newValue + (newValue * flexiInterest/100) projectedValue = bondCurrentWorth < minimumValue ? .depriciating : .appreciating } } init(wrappedValue: Int = 0, minimumValue: Int, flexiInterest: Int) { self.minimumValue = minimumValue self.flexiInterest = flexiInterest self.bondCurrentWorth = wrappedValue } }
  14. struct WalmartFoodBond { var bondName: String @BondValue(minimumValue: 0, flexiInterest: 0,

    value: 0) var bondValue = 0 init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) { self.bondName = bondName _bondValue = BondValue(minimumValue: minimumValue, flexiInterest: flexiInterest) } } struct WalmartCommerceBond { var bondName: String @BondValue(minimumValue: 0, flexiInterest: 0, value: 0) var bondValue = 0 init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) { self.bondName = bondName _bondValue = BondValue(minimumValue: minimumValue, flexiInterest: flexiInterest) } }
  15. var foodBond = WalmartFoodBond(bondName: "Walmart Food Bond", minimumValue: 200, flexiInterest:

    10, value: 200) print("Walmart Food Bond current worth - \(foodBond.bondValue)") print("Walmart Food Bond growth - \(foodBond.$bondValue)”) var commerceBond = WalmartCommerceBond(bondName: "Walmart Growth Bond", minimumValue: 200, flexiInterest: 10, value: 200) print("Walmart Commerce Bond current worth - \(commerceBond.bondValue)") print("Walmart Commerce Bond growth - \(commerceBond.$bondValue)”) commerceBond.bondValue = 50 print("Walmart Commerce Bond final growth - \(commerceBond.$bondValue)”) OUTPUT: Walmart Food Bond current worth - 220 Walmart Food Bond growth - appreciating Walmart Commerce Bond current worth - 220 Walmart Commerce Bond growth - appreciating Walmart Commerce Bond final growth - depriciating
  16. Use cases of Property Wrappers • Accessing user default values.

    • Implementing custom lazy and NSCopying wrappers. • Guaranteeing access of properties from a particular thread. • Lots many ……
  17. Current uses in Swift • Swift UI • Combine

  18. Swift UI • @State • @Binding Combine • @Published •

    @ObservedObject • @Environment
  19. Alternate Proposals • Single protocol 
 protocol PropertyWrapper { associatedtype

    Value var wrappedValue: Value { get } } • Kotlin like by- syntax. • Alternative spellings for the $projection property.
  20. Cavets • Code base can be messy with lot of

    “@“ syntaxes. • “@“ is not a Swifty convention. • Not a developer friendly readable format.
  21. Future Proposals • Finer grained access control
 @SomeWrapper public public(storage)

    private(projection) var foo: Int = 1738 • Referencing the enclosing `self` in a wrapper type. • Delegating to an existing property.
  22. Thank you