Comments 3
Важно помнить, что подобные решения — это злоупотребление системой типов. Своего рода хак. Любой такой хак представляет собой неочевидный подход для решения критически важных проблем, жертвуя самодокументированием кода.
Возможно в каких-то ситуациях такой подход и может выполнить роль предохранителя, но главным образом фантомные типы используют для разгрузки рантайма от лишних проверок, делегируя эту задачу компилятору.
Кроме этого, в статье приведены неудачные примеры, демонстрирующие отсутствие понимания культуры программирования на Swift.
1) Пример с User и Product. Для сравнения двух бизнес объектов не требуется в явном виде сравнивать их идентификаторы. Достаточно лишь унаследовать протокол Equatable и сравнивать объекты напрямую. При желании можно переопределять дефолтный алгоритм сравнения (если не требуется сравнение по всем полям структуры).
Проверка произойдет также на уровне компилятора и не даст собрать неверный код.
2) Пример с fetch. Для методов получения бизнес объектов из хранилища, также вместо идентификатора обычно передаётся объект целиком, либо используется специальный класс для задания параметров поиска NSPredicate.
Проверка тоже на уровне компилятора — никаких проблем.
3) Пример с HealthKit. Тут всё просто. Проблема из ничего. Для проверки возможности скастить единицу измерения у этого же класса есть специальный метод is(compatibleWith:) developer.apple.com/documentation/healthkit/hkquantity/1615508-is
Это конечно райнтайм, но зато без замусоривания кода лишними абстракциями.
Поэтому к такому способу жонглирования типами нужно подходить очень избирательно.
И кстати Generics во всем цивилизованном мире зовутся обобщениями (обобщенными типами), а не универсальными типами.
Возможно в каких-то ситуациях такой подход и может выполнить роль предохранителя, но главным образом фантомные типы используют для разгрузки рантайма от лишних проверок, делегируя эту задачу компилятору.
Кроме этого, в статье приведены неудачные примеры, демонстрирующие отсутствие понимания культуры программирования на Swift.
1) Пример с User и Product. Для сравнения двух бизнес объектов не требуется в явном виде сравнивать их идентификаторы. Достаточно лишь унаследовать протокол Equatable и сравнивать объекты напрямую. При желании можно переопределять дефолтный алгоритм сравнения (если не требуется сравнение по всем полям структуры).
struct User {
let id: UUID
}
struct Product {
let id: UUID
}
extension User: Equatable {
static func == (lhs: User, rhs: User) -> Bool {
return lhs.id == rhs.id
}
}
extension Product: Equatable {
static func == (lhs: Product, rhs: Product) -> Bool {
return lhs.id == rhs.id
}
}
let product = Product(id: UUID())
let user = User(id: UUID())
user == product
Проверка произойдет также на уровне компилятора и не даст собрать неверный код.
2) Пример с fetch. Для методов получения бизнес объектов из хранилища, также вместо идентификатора обычно передаётся объект целиком, либо используется специальный класс для задания параметров поиска NSPredicate.
func fetch(_ product: Product) -> Product? {
// return product
}
fetch(user)
Проверка тоже на уровне компилятора — никаких проблем.
3) Пример с HealthKit. Тут всё просто. Проблема из ничего. Для проверки возможности скастить единицу измерения у этого же класса есть специальный метод is(compatibleWith:) developer.apple.com/documentation/healthkit/hkquantity/1615508-is
let average = statistics?.averageQuantity()
var mass = 0.0
if let qty = average,
qty.is(compatibleWith: .meter())
{
mass = qty.doubleValue(for: .meter())
}
Это конечно райнтайм, но зато без замусоривания кода лишними абстракциями.
Поэтому к такому способу жонглирования типами нужно подходить очень избирательно.
И кстати Generics во всем цивилизованном мире зовутся обобщениями (обобщенными типами), а не универсальными типами.
+4
UFO just landed and posted this here
К сожалению нет. Введение фантомного типа не допускает динамического изменения свойств родительского типа. В этом и весь смысл. У нас есть два структурно одинаковых объекта, но нам нужно разделить их семантически. Тогда мы декларируем обобщение, которое никак не используется и получаем уже два несовместимых типа.
0
Sign up to leave a comment.
Фантомные типы в Swift