Comments 22
ваше расширение будет доступно для всех опциональных типов. Выглядит не очень хорошо: (...) Однако компилятор защитит вас и не скомпилирует этот код.
То есть это не особенность языка, и ничего там не будет доступно, а просто просчёт в системе автодополнения, которая не была готова к таким фокусам(?)
Мне тоже не понятен этот момент. Там же чётко написано ограничение
extension Optional where Wrapped == String { ...
Я так же могу в котлин написать:
class Wrapper<T>(val t: T)
fun Wrapper<String>.printMe() {
println(t)
}
Однако компилятор защитит вас и не скомпилирует этот код. Но если вы добавите больше таких расширений — ваша автоподсказка будет забита мусором.
В котлине автоподсказка мусором не забивается. Может, виновата ide, а не язык?
extension Optional where Wrapped == String {
func orEmpty() -> String {
switch self {
case .some(let value):
return value
default:
return ""
}
}
}
можно было оставить и изначальную реализацию orEmpty()
extension Optional where Wrapped == String {
func orEmpty() -> String {
return self ?? ""
}
}
А это совсем не то, чего я хотел.
Именно — передача по ссылке/значению очень субъективно. Лично на мой взгляд, передача по ссылке по-умолчанию на порядок удобнее и логичнее. Особенно если мои дата-классы иммутабельные. А если надо скопировать, то есть метод `copy` из коробки. Конечно бывают кейзы, когда хотелось бы иметь value-типы и в жвм возможно их скоро завезут, но таких случаев значительно меньше, чем те, что покрываются обычными дата-классами.
Вы можете создать свой протокол и расширение для класса, чтоб соответствовать этому протоколу.
Да это приятная фича языка поддерживаемая платформой (в отличии от жвм), только примеры про неё ничего не говорят.
Это может быть сложно даже с Mockito
Серьезно? Если у вас есть интерфейс, нет никакой проблемы замокировать его. С файналами не так всё просто конечно, но пример совершенно это не показывает.
Они отличаются только названием и, конечно же, sealed-класс передается по ссылке, а перечисление в Swift — по значению.
Сначала опять про ссылки и значения. Для перечислений нет никакой разницы, передавать адрес константы или её номер. А для sealed-классов, та же дилемма, что и в первом пункте. И да, различий нет уж и много, но они есть.
Да, про ссылки/значения — холивар может быть вечным. Вот, например, есть у вас объекты типа «монитор», и у них есть свойство «разрешение». Это свойство состоит из двух полей: ширина, высота. Вопрос: какого типа должно быть свойство «разрешение»? Класс или структура? Должно ли оно передаваться по ссылке или по значению. И если у меня есть два монитора с одинаковым разрешением, то меняя разрешение на одном из них ожидаю ли я, что оно изменится и на втором? :)
Про Мокито вы невнимательно прочитали. Речь о невозможности замокать именно final-класс, а не интерфейс. И в этом и преимущество Свифта: можно даже final-класс подписать на свой протокол (интерфейс) и мокать уже протокол (интерфейс). Главное, чтоб в протоколе (интерфейсе) сигнатуры методов совпадали с тем, что объявлено в final-классе.
Ну всё-таки в Mockito 2 final классы мокаются без проблем.
Передача по ссылке или значению — это архаизмы реализаций компиляторов и языков прошлых лет, когда это имело смысл. На сегодняшний день важно лишь, что описываемая сущность является мутабельной или иммутабельной. В случае иммутабельной сущности нам не важно передается ли она по значению или по ссылке и где физически она находится в памяти — это уже внутренние проблемы компилятора и рантайма. При операциях с иммутабельными сущностями каждый раз создается новый экземпляр. Таким образом иммутабельные классы полностью идентичны value type (подразумевается наличие equals()/hashCode()).
В случае же мутабельной сущности, мы имеем каждый раз дело с экземпляром, занимающим определенное место в памяти, и поэтому осознанно работаем с ним по ссылке (некоему хэндлу, если угодно). Для передачи информации о внутреннем состоянии мутабельного объекта вовне есть два способа: хороший — обернуть его иммутабельным врапером, либо плохой: просто сделать defensive copy и отдать на растерзание. Структуры в Свифте — это просто реализация defencive copying по умолчанию, тогда как в Котлине это нужно делать въявную. Мне кажется не стоило делать отдельный класс объектов языка только лишь для реализации одного паттерна. Тем более, что изначально структуры (записи) в языках программирования означали немножко другое и появились задолго до классов.
Необходимость мокать final классы, говорит о просветах в дизайне.
То есть я бы сказал, что просветом в дизайне являются скорее такие интерфейсы, если на их существование нет никакой другой весомой причины (например, скрыть платформо-зависимые компоненты).
Ну а открывать класс только для того, чтобы его можно было мокнуть без Mockito 2 — тоже не сильно хорошо.
- Отделение контракта чтобы не тащить за собой зависимости реализации.
- Раздельное управление API и реализацией.
- Добавление явных декораторов вместо неявных аспектов.
- Улучшение читаемости API.
- Сокрытие платформозависимого компонента, конечно же.
Можно, наверное, еще подумать, зачем может быть нужен интерфейс с единственной
реализацией, но и приведенного должно быть достаточно.
Конечно, легко себе вообразить проект, где перечисленные выше причины вообще никогда не возникнут, но в моем текущем проекте и во всех предыдущих за последние лет 6 наличие интерфейса практически у любого сервиса подразумевалось по умолчанию.
Не могу плюсануть комментарий (видимо есть ограничение по времени), но вы не один)
Swift vs. Kotlin. Отличия важны