Поскольку речь идет об изменчивости, Java пример List
против Iterable
не является хорошим примером изменяемых и неизменяемых типов данных (метод Iterator.remove
мутирует базовую коллекцию, поэтому List
может быть поврежден внешним вызывающим абонентом даже без приведения).
Давайте вместо этого представим два типа: MutableList
и ReadonlyList
, где MutableList
- это подтип, и только ReadonlyList
предотвращает мутирование пользователем; сам список не гарантируется, чтобы избежать мутации. (Мы не можем разумно назвать супертип ImmutableList
, потому что никакое значение не является одновременно изменяемым и неизменным списком.)
Преобразование из супертипа в подтип, например, с ReadonlyList
до MutableList
, называется downcasting . Даункастинг небезопасен, потому что не каждое значение супертипа является значением подтипа; так что либо проверка должна выполняться во время выполнения (как это делает Java, бросая ClassCastException
, если вызываемый экземпляр не имеет правильного типа), либо программа сделает что-то небезопасное для памяти (как может сделать C) ).
Теоретически язык может запретить даункинг на том основании, что он небезопасен; популярные языки программирования этого не делают, потому что удобно иметь возможность писать код, который, как вы знаете, , безопасен для типов, но система типов языка недостаточно мощна, чтобы вы могли написать подходящие аннотации типов, которые позволяют типу -checker для доказать , что код является типобезопасным. И никакие средства проверки типов не могут обоснованно доказывать каждое доказуемое свойство вашего кода. Тем не менее, теоретически, ничто не мешает языку запрещать уныние; Я просто не думаю, что многие люди предпочтут использовать такой язык для разработки большого программного обеспечения.
Тем не менее, я думаю, что решение проблемы, которую вы описываете, было бы просто не делать MutableList
подтипом ReadonlyList
. Класс MutableList
все еще может иметь метод для получения представления, доступного только для чтения, но, поскольку не было бы никакого отношения подтип / супертип, это представление не будет значением типа MutableList
, поэтому его нельзя преобразовать в изменяемый тип, даже если вы сначала перешли на общий супертип.
Во избежание снижения производительности во время выполнения язык может иметь указанную поддержку c для таких оболочек, что позволяет оболочке делегировать свои методы к исходному списку во время компиляции, а не во время выполнения.