Есть очень прикольный язык программирования -- Eiffel. А в нем есть очень прикольная фича -- заякоренные типы (anchored types). Давеча пришлось в одном из разговоров про нее вспомнить и набросать небольшой пример, чтобы проверить те или иные предположения.
У Eiffel-я есть он-лайн компилятор (что-то по типу godbolt, wandbox, ideone), но в нем нельзя просто так сохранить сделанное и поделиться публичной ссылкой. Поэтому помещу под кат код написанного примера, просто на память, а то вдруг еще раз потребуется.
В чем суть примера?
Есть базовый класс MESSAGE.
Есть базовый класс ENVELOPE, который хранит в себе MESSAGE. Но класс ENVELOPE написан с использованием MESSAGE в качестве якорного типа. Что позволяет создать наследника SIGNED_ENVELOPE, который хранит уже не просто MESSAGE, а SIGNED_MESSAGE. Но менять унаследованные из ENVELOPE методы не нужно, Eiffel сам разбирается с тем, что в SIGNED_ENVELOPE методы make и change_content получают уже не MESSAGE, а SIGNED_MESSAGE.
При этом Eiffel что-то может проверить в compile-time. Например, если у нас есть ссылка signed_env с типом SIGNED_ENVELOPE, то в вызов signed_env.change_content мы не может отдать просто ссылку на MESSAGE. Будет ошибка компиляции, компилятор ждет от нас SIGNED_MESSAGE (или наследника SIGNED_MESSAGE).
Но если у нас есть env типа ENVELOPE и мы env присвоили signed_env (т.е. теперь env ссылается на экземпляр SIGNED_ENVELOPE), то компилятор пропустит передачу обычного MESSAGE в env.change_content. Но ошибка будет диагностирована в run-time с выбросом исключения. Т.е. "обмануть" Eiffel не получится: то, что Eiffel не смог поймать в compile-time, он поймает в run-time.
Особенностью Eiffel-я является то, что каждый класс должен помещаться в отдельном файле. Поэтому сколько классов, столько и файлов.
Файл application.e
|
class APPLICATION inherit ARGUMENTS_32 create make feature {NONE} -- Initialization make -- Run application. local env: ENVELOPE env2: SIGNED_ENVELOPE msg: MESSAGE do create env.make (create {MESSAGE}.make("Hello")) env.examine_content create env2.make (create {SIGNED_MESSAGE}.make("Bye")) env2.examine_content env := env2 msg := create {SIGNED_MESSAGE}.make("222") env.change_content (msg) env.examine_content end end |
Файл msg.e
|
class MESSAGE create make feature body: STRING make(b: STRING) do body := b end feature tell_about_itself do print("Message body is '") print(body) print("'%N") end end |
Файл envelope.e
|
class ENVELOPE create make feature msg: MESSAGE feature make (m: like msg) do msg := m end change_content (m: like msg) do msg := m end examine_content do msg.tell_about_itself end end |
Файл signed_msg.e
|
class SIGNED_MESSAGE inherit MESSAGE redefine tell_about_itself end create make feature tell_about_itself do print("SIGNED message body is '") print(body) print("'%N") end end |
Файл signed_envelope.e
|
class SIGNED_ENVELOPE inherit ENVELOPE redefine msg end create make feature msg: SIGNED_MESSAGE end |
Комментариев нет:
Отправить комментарий