Key Path Dynamic Member Lookup (SE-0252)

swift5

#1

Я люблю всякие фичи, полезные и не очень, даже заглядываю в другие языки (современные GO/Rust/Kotlin) посмотреть что там и как, естественно слежу за свифтом, одна из таких будущих фич (уже в мастере ждем в 5.1) показалась мне особенно интересной.

Предложение SE-0252 позволяет искать свойства с помощью KeyPath. При доступе к свойству (через точку) будет вызван subscript который принимает KeyPath, KeyPath типизирован а это autocomplete и проверка компилятором как у обычных свойств.

Можно придумать кучу различных фич, например пример автора с линзами:

struct Point {
  let x: Int
  var y: Int
}

@dynamicMemberLookup 
struct Lens<T> {
  var obj: T

  init(_ obj: T) {
    self.obj = obj
  }

  subscript<U>(dynamicMember member: KeyPath<T, U>) -> Lens<U> {
    get { return Lens<U>(obj[keyPath: member]) }
  }

  subscript<U>(dynamicMember member: WritableKeyPath<T, U>) -> Lens<U> {
    get { return Lens<U>(obj[keyPath: member]) }
    set { obj[keyPath: member] = newValue.obj }
  }
}

var lens = Lens(Point(x: 0, y: 0))

_ = lens.x // converted into `lens[dynamicMember: KeyPath<Point, Int>`
_ = lens.y = Lens(10) // converted into `lens[dynamicMember: WritableKeyPath<Point, Int>]`

Или можно встраивать структуры в структуры:

@dynamicMemberLookup
protocol DelegateWrapper {
    associatedtype Delegate
    var deleagete: Delegate { get }
}


extension DelegateWrapper {
    subscript<U>(dynamicMember member: KeyPath<Delegate, U>) -> U {
        get { return deleagete[keyPath: member] }
    }
}

struct ArrayManager {
    let addString: (String) -> Void
    let removeString: () -> Void
    let getArray: () -> [String]
    init() {
        var array = [String]()
        addString = { array.append($0) }
        removeString = { array.removeLast() }
        getArray = { return array }
    }
}

struct Controller: DelegateWrapper {
    let deleagete = ArrayManager()
    
    init() {
        self.addString("A")
        self.addString("B")
        self.removeString()
        self.addString("C")
        print(self.getArray())
    }
}

_ = Controller()

В голову ещё приходит прокси, но я пока не придумал как :slight_smile:

Тулчейн можно скачать здесь.


#2

Я нуб в этих темах. Скопипастил все в playground и не запустилось. Что не так? :thinking:


#3

Swift 5.1 поставили?


#4

Для запуска версии свифта отличной от той что в Xcode, нужен соответствующий тулчейн. Обычно его можно скачать здесь, как swift 5.1 выйдет он там сразу появится.

После его установки, нужно открыть настойки Xcode и там его выбрать:

В Xcode сразу появится соответствующий значок:

В playground наверно и не будет работать, пробуйте “Command Line Tool”.

Тот тулчейн из поста нужно скопировать в папку ~/Library/Developer/Toolchains после чего его можно будет выбрать в Xcode:

P.S. Следить за предложениями можно здесь.


#5

Нет, это CI сборка перед pull request.