WWDC2022 - Swift

«  WWDC2022 - SF Symbols
Fix Repository Doesn't Have a Release File Error  »

Abstraction

<T> where T: Idea

  • Model with concrete types
  • identify common capabilities
  • build interface
  • write generic code

Polymorphism allows one piece of code to have many behaviors depending on how the code is used.

  • Overloads achieve ad-hoc polymorphism
  • Subtypes achieve subtype polymorphism
  • Generics achieve parametric polymorphism

A protocol separate the ideas about what a type does from the implementation details.

  • can use protocols with struct, enums, actors, etc.
func feed<A: Animal>(_ animal: A)
func feed<A>(_ animal: A) where A: Animal
func feed(_ animal: some Animal)

Opaque

  • underlying type for some
// local vaariable
// must have initial value
let animal: some Animal = Horse()

// CANNOT change type later
// X
var animal: some Animal = Horse()
animal = Chicken()
// parameters
func feed(_ animal: some Animal)
feed(Horse())
feed(Chicken())
// Results
// should have same return type
func makeView(for farm: Farm) -> some View {
    // WRONG, should return same type
    if condition {
        return FarmView(farm)
    } else {
        return EmptyView()
    }
}

// can fix above issue by ViewBuilder DSL
// to transform control-flow statements to
// have same underlying return type for each branch
@ViewBuilder
func makeView(for farm: Farm) -> some View {
    // WRONG, should return same type
    if condition {
        return FarmView(farm)
    } else {
        return EmptyView()
    }
}
  • one associatedType require another associateType
protocol Animal {
    associatedType Feed: AnimalFeed
    associatedType Habitat
    func eat(_ food: Feed)
}

struct Farm {
    func feed(_ animal: some Animal) { ... }
    func buildHome<A>(for animal: A) -> A.Habitat where A: Animal { ... }
}
  • use type parameter in generic type
  • opaque name must always be named for generic types
struct Silo<Material> {
    private var storage: [Material]
    init(storing materials: [Material]) {
        self.storage = materials
    }
}

var hayStorage: Silo<Hay>

Arbitrary type

  • any express arbitrary type
  • sometimes, value small enough to fit inside box, if other values are too large, value will be allocated elsewhere, box stores a pointer to the value
  • existential type: static type can dynamically store any concrete type
  • type erasure: use same representation for different concrete type
  • concrete type is said to be erased at compile time, the concrete type is only known at runtime
  • new in Swift5.7,
    • use any keyword for protocols with associated types
    • compiler can convert instance of any to some by unboxing underlying value and passing it directly to some parameter
      • unboxing as the compiler open the box and take out value stored inside

Capabilities of some and any

  • some
    • holds fixed concrete type
    • guarantee type relationships
  • any
    • holds arbitrary concrete type
    • erases type relationships\
  • write some by default, change some to any when need to store arbitrary values

Example

protocol Animal {
    associatedType Feed: AnimalFeed
    func eat(_ food: Feed)
}

struct Farm {
    func feed(_ animal: some Animal) {
        let crop = type(of: animal).Feed.grow()
        let produce = crop.harvest()
        animal.eat(produce)
    }

    func feedAll(_ animals: [any Animal]) {
        for animal in animals {
            // can convert `any` to `some`
            feed(animal)
        }
    }
}

References

Published on 09 Jun 2022 Find me on Facebook, Twitter!

«  WWDC2022 - SF Symbols
Fix Repository Doesn't Have a Release File Error  »

Comments

    Join the discussion for this article at here . Our comments is using Github Issues. All of posted comments will display at this page instantly.