Что мешает протоколу наследоваться от конкретной специализации протокола с primary associated type?
Sequence<Int> — это не отдельный объявленный протокол, а протокольный тип с ограничением на Element. В списке наследования Swift ожидает сам протокол, поэтому конкретную специализацию нельзя указать там как базовый протокол. Ограничение нужно выразить через where и связать унаследованный associated type с конкретным типом.
Протоколы с associated types позволяют описывать семейство совместимых типов, не фиксируя конкретную реализацию заранее. Позднее primary associated types добавили более удобную запись ограниченных протокольных типов, похожую на применение generic-параметра.
Однако такая запись не превращает каждую специализацию протокола в новый номинальный протокол. Swift сохраняет различие между объявлением протокола, его использованием с ограничениями и конкретным типом, который этому протоколу соответствует.
Допустим, нужен протокол последовательности, элементы которой всегда имеют тип Int. Наивная попытка выразить это наследованием от специализации Sequence<Int> смешивает два разных механизма: наследование протоколов и ограничение associated type.
Если ограничение выразить неверно, код либо не скомпилируется, либо останется слишком общим: generic-функция не сможет доказать, что элементы действительно имеют тип Int. Это влияет на доступность операций, вывод типов и возможность передавать значения в API с более строгими ограничениями.
Протокол-наследник должен наследоваться от объявления Sequence, а равенство associated type задаётся отдельным ограничением:
Здесь IntSequence остаётся обычным номинальным протоколом, но его соответствие Sequence дополнено требованием Element == Int. Поэтому любой тип, соответствующий IntSequence, обязан предоставлять именно Int как тип элемента.
Важное различие такое: наследование определяет отношения между объявлениями протоколов, а where связывает associated types и другие параметры ограничениями. Специализированная запись протокольного типа удобна при использовании протокола в generic-коде или existential-контексте, но не создаёт нового участника иерархии протоколов.
Компромисс заключается в том, что отдельный протокол IntSequence даёт именованное и переиспользуемое ограничение, но увеличивает количество деклараций. Если ограничение нужно только в одной функции, лучше оставить обычный Sequence и задать равенство S.Element == Int непосредственно в generic-сигнатуре.
В библиотеке есть функция агрегации, работающая только с последовательностями целых чисел. Рассматривались два варианта: создать именованный IntSequence или добавить ограничение Element == Int только в функцию.
Именованный протокол удобен, если такое требование является частью публичной модели предметной области и используется в нескольких API. Ограничение в generic-функции проще и не вводит новый тип, но его придётся повторять в каждом месте, где требуется именно целочисленная последовательность.
Выбор зависит от области действия правила. Для локального алгоритма достаточно generic-ограничения; для публичного контракта библиотеки предпочтителен отдельный протокол-наследник. В обоих случаях ограничение выражается через where, а не через наследование от специализации Sequence.
Создаёт ли запись со специализацией новый протокол?
Нет. Ограниченный протокольный тип лишь описывает использование уже существующего протокола с дополнительным условием. Он не получает собственного имени, набора witness-таблиц или отдельного места в иерархии наследования.
Можно ли получить тот же эффект в generic-функции без нового протокола?
Да. Нужно ограничить generic-параметр протоколом Sequence и отдельно зафиксировать его associated type: S.Element == Int. Тогда компилятор доказывает тип элементов внутри функции, но вызываемый тип не обязан соответствовать дополнительному именованному протоколу.
Достаточно ли ограничить сам параметр S протоколом Sequence?
Нет. Ограничение S: Sequence говорит только о наличии возможностей Sequence, но не устанавливает конкретный тип S.Element. Чтобы безопасно применять операции, требующие именно Int, необходимо явно добавить равенство associated type или использовать протокол вроде IntSequence, где это равенство уже является обязательным требованием.