Ответ
Да, компилятор Swift может неявно изменять уровень доступа методов в определенных сценариях, преимущественно для обеспечения совместимости или оптимизации.
Основные случаи:
-
Совместимость с Objective-C (
@objc) Когда метод помечен@objcдля экспорта в Objective-C runtime, но не объявлен какpublicилиopen, компилятор может сделать его эффективноprivateдля Swift, оставив доступным только через Objective-C.class InternalHelper: NSObject { @objc func performTask() { } // Доступен в Objective-C, но не в Swift модулях } -
Оптимизация (Whole Module Optimization) При включенной оптимизации всего модуля (
-whole-module-optimization), компилятор может изменитьinternalметоды наprivate, если видит, что они не используются за пределами текущего файла. Это позволяет проводить более агрессивные оптимизации. -
Реализация протоколов При реализации
publicпротокола воinternalклассе, требования протокола становятсяpublicв контексте типа, но фактическая реализация остаетсяinternal. -
Синтезированные члены Для автоматически синтезированных членов (например,
==дляEquatable) компилятор устанавливает уровень доступа, соответствующий типу.
Важно: Эти изменения — деталь реализации компилятора. В исходном коде следует явно указывать намеренный уровень доступа (private, fileprivate, internal, public, open).
Ответ 18+ 🔞
А, ну ты про это, про Swift и его компиляторные фокусы! Да, бывает такое, сука, он там по-тихому может доступы подкрутить, как ему вздумается. В основном, конечно, не просто так, а для какой-то своей, компиляторской, пиздатой цели — то ли оптимизировать, то ли с Objective-C подружить.
Смотри, основные загибы, где он может накосячить с доступностью:
1. Эта ёбанная совместимость с Objective-C (@objc)
Вот представь: ты наклепал метод, пометил @objc, чтобы он в Objective-C runtime светился, но при этом не сделал его public. Компилятор смотрит на это и думает: «Ну окей, для Objective-C ты доступен, а для других Swift-модулей — пошёл нахуй, будем считать тебя private». Получается такая хитрая жопа — из Objective-C вызвать можно, а из соседнего Swift-модуля — нихуя.
class InternalHelper: NSObject {
@objc func performTask() { } // В Objective-C есть, а в Swift извне — как будто private
}
2. Оптимизация всей хуйни разом (Whole Module Optimization)
Включаешь эту опцию (-whole-module-optimization), и компилятор начинает умничать. Видит он, что у тебя internal метод используется только в одном файле, и думает: «А зачем ему быть internal на весь модуль? Давай-ка я его тихонечко на private поменяю, так оптимизации лучше пойдут». И меняет, блядь! Ты в коде видишь internal, а под капотом он уже private. Ёперный театр!
3. Реализация протоколов — тут вообще пиздец
Объявил ты public протокол, а реализуешь его во internal классе. Компилятор смотрит и чешет репу: «Ну требования-то протокола public, значит, и методы должны быть доступны как public... но сам-то класс internal! Ладно, сделаю вид, что методы public, но реально-то они internal, потому что класс дальше модуля не высунешь». Получается такой ебаный когнитивный диссонанс.
4. Автоматически сгенерированная хуйня
Например, для Equatable компилятор сам синтезирует оператор ==. И уровень доступа он выставит такой же, как у самого типа. Сделал тип public — и == будет public. Сделал internal — всё, == тоже internal. Логично, вроде, но иногда забываешь, а потом удивляешься, пиздец, почему не компилируется.
Главное, что нужно запомнить, чувак: это всё — внутренние пляски компилятора. В своём коде ты должен явно, блядь, указывать, что ты хочешь: private, fileprivate, internal, public или open. Не надейся, что он всё за тебя додумает — а то потом будешь сидеть и ебать костыли, разбираясь, почему твой «внутренний» метод внезапно стал виден там, где не надо. Пиши явно, и будет тебе счастье, а не волнение ебать.