Swift tradycyjnie zwraca dużą uwagę na czystość składni i pozwala na tworzenie własnych operatorów (overloading operatorów), w tym nowych symboli i nawet słów kluczowych. To rozszerza możliwości DSL i sprawia, że kod jest bardzo expresyjny.
Bez zrozumienia zasad deklaracji operatorów można uzyskać niejednoznaczny, trudny do odczytania i ciężki w utrzymaniu kod. Niewłaściwie wybrana priorytetowość lub asocjatywność może prowadzić do nieoczekiwanych wyników. Kompilator pozwala na tworzenie bardzo „niebezpiecznych” wyrażeń, jeśli nie określi się ograniczeń.
Można deklarować nowe operatory infix, prefix, postfix, określać ich priorytety i obszary zastosowania. Przykład:
infix operator ~> : AdditionPrecedence func ~> (lhs: Int, rhs: Int) -> Int { return lhs * 10 + rhs } let x = 2 ~> 3 // 23
Dla niestandardowych priorytetów należy zadeklarować:
precedencegroup MyPrecedence { associativity: left higherThan: AdditionPrecedence } infix operator *** : MyPrecedence
Kluczowe cechy:
Czy konieczne jest realizowanie zarówno funkcji, jak i deklaracji operatora?
Tak, jeśli zadeklarowano operator, należy zrealizować odpowiadającą mu funkcję — w przeciwnym razie wystąpi błąd kompilatora. Funkcje mają podpis, który odpowiada operatorowi pod względem sygnatury.
Jak prawidłowo wybrać precedencegroup i jak grupy wpływają na kolejność obliczeń?
precedencegroup określa priorytet obliczeń i asocjatywność dla operatorów infix. Niewłaściwy wybór grupy może prowadzić do nieoczekiwanych wyników w wyrażeniach z wieloma operatorami (np. mnożenie/dodawanie i twój operator niestandardowy).
Czy można zadeklarować niestandardowy operator z tekstową nazwą?
Nie, operatorzy niestandardowi są dostępni tylko poprzez specjalne symbole lub sekwencje określone przez składnię Swift. Standardowe nazwy tekstowe nie są dozwolone jako operators.
W projekcie zadeklarowano operatory <<< i >>> do dziwnych przekształceń kolekcji, bez opisania priorytetu, asocjatywności i dokumentacji. Nowi pracownicy nie rozumieli, co robili i w jakiej kolejności obliczane były wyrażenia.
Zalety:
Wady:
W projekcie używano niestandardowego operatora => do deklaratywnego budowania chainable pipeline (na przykład w budowniczym UI), z dokładnie opisanym priorytetem i udokumentowaną implementacją. Każdy programista rozumiał, co robi i jak jest używane.
Zalety:
Wady: