Pull to refresh

Comments 23

Не нравится мне, куда Swift идёт в своём развитии. (впрочем, как язык он не нравился мне никогда): Вместо добавления новых фич добавляется дублирующий функционал. лучше бы допилили рефлексию до рабочего состояния: всё рабочее, что есть в языке — унаследовано от ObjC и реализовано в ObjC Runtime.

Что selector'ов нет у всего, что не наследуется от NSObject, это, конечно, плохо, согласен. И что в protocol теперь только обязательные функции объявлять можно.


Но с другой стороны, какой ещё язык программирования позволяет запретить передавать пустые указатели в compile time? Насколько знаю, optional в Java — решение лишь отчасти, позволяет лишь приделать костыль. А какой ещё язык программирования будет следить вот так:


class Something {
    var someURL: URL
    var someData: Data//допустим, это добавли позже
    init(someURL: URL) {
        self.someURL = someURL//нет, не компилируется, забыть инициализровать someData не получится
    }
}

Ещё очень полезная вещь — enum с параметрами.


enum SomeResult {
    case valid(data: Data)
    case failure(error: Error)
}

Результат и ошибка одновременно не получатся никак. А ещё, в отличие от Java, структуры объявлять можно, и управлять их изменяемостью. Где ещё так? Хоть недостатков у Swift тоже немало, например, нет объявления атрибутов.

Если бы всё было так просто… В Swift есть ТРИ (четыре?) разных вида рефлексии:
— Нативная для ObjC runtime
— Нативная для Swift (`Mirror(for: <..>)`)
— Стороняя реализация: github.com/Zewo/Reflection
— KeyPath? (который как бы и не совсем рефлексия, так как его нельзя полноценно создавать в рантайме)

Но ни одна из реализаций не является полноценной (и даже в сумме они не покрывают всех вариантов):
ObjC runtime работает только с ObjC типами (не обязательно с NSObject, но с теми, у которых есть указатель isa)
Mirror может только читать почти всё (за редкими, но важными, исключениями, вроде Enum)
Библиотека Reflection может читать и писать, но только структуры
KeyPath — такая странная хрень, которая таки дёргает внутреннее апи, никак не доступное рядовому разработчику, но делает это бесполезно: его можно создать либо из ObjC селектора, либо синтаксическим сахаром, который надо явно написать.

И ничего из этого не может писать любые поля класса, не транслируемого так или иначе в ObjC runtime и любые поля Swift типа в любом классе. В общем не быть типу int? использованным в динамическом json маппинге.

> Но с другой стороны, какой ещё язык программирования позволяет запретить передавать пустые указатели в compile time?
Вроде бы как в Kotlin есть такое (впрочем, я никогда не писал на этом языке).

По поводу enum с ассоциированными значениями… Во первых, это наверняка можно реализовать без Enum (не пробовал, в голову приходят абстрактный тип с наследниками), во вторых лично мне не нравится такой подход из-за того, что он провоцирует божественный метод-свалку c switch..case, в который запихнуто всё.

Ваш конкретный пример — я бы посоветовал посмотреть на RxSwift или ReactiveX (реализации Reactive паттерна для Swift). К тому же иногда таки нужно передать и данные, и ошибку: «запрос к серверу не выполнен и вот актуальное состояние», например. В прочем, создать кастомный Error с полем данных.
Если бы всё было так просто… В Swift есть ТРИ (четыре?) разных вида рефлексии

Именно об этом я и упомянул кратко. Для CoreData всё равно нужен NSObject, так что там можно через selector'ы делать. Для JSON и впрямь ситуация оставлят желат лучшего, тем более, что объявления атрибутов нет, в Java и C# обычно ими и пользуются.


Во первых, это наверняка можно реализовать без Enum (не пробовал, в голову приходят абстрактный тип с наследниками)

Тогда в абстрактный может пойти лишь статус, ибо если объявить метод getError, в наследуемом классе его уже не спрятать, хотя, Java (в отличие от C#) позволяет protected метод сделать public. Но даже если так, это надо знать, к какому типу данных приводить в каждом случае, а если кто-то захотел что-то поменять в этих классах, да ещё так, что где-то возвращает null...


во вторых лично мне не нравится такой подход из-за того, что он провоцирует божественный метод-свалку c switch..case, в который запихнуто всё

Любую полезную возможность можно использовать во вред, что уж говорить...


Ваш конкретный пример — я бы посоветовал посмотреть на RxSwift или ReactiveX

Ну это, наверно, неудачный пример. Добавляем loading, recovering и прочее, и уже не всегда будет нужная реализация. Кстати, RxSwift результат выражает именно через enum с параметрами.

Но с другой стороны, какой ещё язык программирования позволяет запретить передавать пустые указатели в compile time?

Возможно я не понимаю что имеется ввиду но разве в Kotlin этого нет? Если тип не nullable — передать туда null (или даже возможность передать его) — ошибка (да, есть способы выстрелить себе в ногу, если оно хочется). kotlinlang.org/docs/reference/null-safety.html например.

Я допускаю, что Kotlin и, может, и ещё какой-то язык программирования это умеют. Я не знаток Kotlin, но слышал, что он основан на JVM, в котором, если не путаю, не предусмотрено возможности объявления структур. На мой взгляд, это большое упущение, а вот в каком языке программирования эти возможности одновременно присутствуют? К тому ж, не знаю насколько так, но слышал, что в Kotlin ключевое слово throws не является обязательным. Если это так, по мне это плохо. Кстати, я всегда это называл главным недостатком C#.

C# вполне подходит под это теперь. Там и структуры есть, и nullable reference типы добавили недавно. А так, ну имеет свифт эти две фичи одновременно. Сильно лучше и быстрее язык от этого не стал.
Вообще все последние изменения в C# выглядят так, будто их содрали со Swift. Что в двойне забавно, учитывая то, что Swift явно содран с C#
Какие, например? nullable reference явно утащили из тайпскрипта. Все остальные фичи это портирование того, что уже есть в F#.
Возможно. Я не знаком с F#, из всех языков, что я знаю синтаксис Swift наиболее близок именно к C#, с серьёзной примесью синтаксического сахара.

Собственно, nullable reference очень похож на логичное продолжение Nullable<T>.
и nullable reference типы добавили недавно

Хорошо, если наконец-то добавили. А то для Singularity, пусть в немного другом виде, оно сколько лет было, а в массы не шло. Несколько лет было, что в Swift возможность уже была, а в C# — когда-нибудь.


Но вот если б в C# ещё б аналогичным образом ввели возможность делать обязательным throws — вот это было б дело, а то в нём часто приходится на всякий случай ставить catch на всё, ибо типичная реальная ситуация с документацией хорошо известна. Конечно, у C# со структурами всегда были неудобства в плане их изменяемости. Но по сравнению с Swift как минимум преимущество — возможность объявления атрибутов. Классический синтаксис мне всё ж больше нравится. Ну и с пространствами имён удобнее, хотя с ними плохо стыкуются typealias/using ... =. Ну и PLINQ — преимущество C#, Swift для параллельной обработки ничего лучше closure пока не предлагает.

throws выглядит хорошо до того момента, пока не приходится добавлять выбрасывание ошибки в существующий метод, на который ссылается весь проект (метод в ситуации, для в которой генерируется ошибка, не работал и раньше)

Значит это было ошибкой проектирования. На крайний случай можно поставить такую заглушку:


     func SomeUnsafeFunction() throws {
        //..
        if (something) {
            throw Errors.someError
        }
    }

    func SomeOtherFunction() {
        do {
            try SomeUnsafeFunction()
        }
        catch {
            print("That must be implemented correctly after the urgent release")
        }
    }
Ну, как бы, я ни разу идеальной архитектуры и не видел :( Всё является компромиссом между навыками, временем, изменчивостью требований, и иногда зарплатой.

Конкретно в этом примере хотелось обработать ошибку в одном конкретном месте и крашить приложение в других.

Вообще, в Swift, особенно начиная с 5-го, эти exceptions и вовсе не нужны. Это больше обратная совместимость и возможность унификации с другими средами, как RxSwift. Для сравнения, в ReactiveSwift, который отходит от этого стандарта, вообще никакого throw нет. А есть тип данных Result, в котором как раз enum с параметрами. В 5-м Swift этот тип данных вошёл в стандартный набор. Но где уже всё обросло throw, приходится находить способы адаптации.

Мне конечно с самого начала не нравился свифт и казался мешаниной фич, да еще странно реализованных (впрочем, писать на нем вполне приятно), но тут совсем глаза вытекли. Авторы там совсем нюх потеряли, хотя вроде не студенты делают язык.
Просто берут популярные экстеншены со stackoverflow и добавляют в core
В переводе не хватает ссылок на Proposals, в оригинале есть!
SE-0249 Key Path Expressions as Functions
SE-0253 Callable values of user-defined nominal types
Да, посчитал не слишком существенным и избыточным в данном случае.
Мне всегда интересно посмотреть мотивацию того или иного изменения.
Вот код будет)) Один будет так писать, другой так, третий так)))
это больше про Kotlin, чем про Swift. Где универсально в угоду всем подходам ))
Обновил Xcode до 11.4. Симуляции стали работать заметно медленнее. Анимированные изменения в SwiftUI стали отображаться с небольшой задержкой (а если длительность анимации меньше этой задержки, то и вовсе без анимации).
Кто-то еще замечал такое?
Sign up to leave a comment.

Articles