stringtranslate.com

Eiffel (язык программирования)

Eiffelобъектно-ориентированный язык программирования, разработанный Бертраном Мейером (сторонником объектно-ориентированного программирования и автором Object-Oriented Software Construction ) и Eiffel Software. Мейер задумал язык в 1985 году с целью повышения надежности разработки коммерческого программного обеспечения; [4] первая версия стала доступна в 1986 году. В 2005 году Eiffel стал языком, стандартизированным по ISO .

Дизайн языка тесно связан с методом программирования Эйфеля. Оба они основаны на наборе принципов, включая дизайн по контракту , разделение команд и запросов , принцип равномерного доступа , принцип единственного выбора , принцип открытости и закрытости , разделение опций и операндов .

Многие концепции, изначально введенные Эйфелем, позже нашли свое применение в Java , C# и других языках. [5] Новые идеи проектирования языка, особенно в рамках процесса стандартизации Ecma / ISO , продолжают внедряться в язык Эйфеля.

Характеристики

Ключевые характеристики языка Эйфеля включают в себя:

Цели дизайна

Эйфель отдает предпочтение декларативным заявлениям, а не процессуальному кодексу, и пытается исключить необходимость в инструкциях по ведению бухгалтерского учета.

Eiffel избегает трюков кодирования или методов кодирования, предназначенных для подсказок по оптимизации компилятору. Цель состоит не только в том, чтобы сделать код более читаемым, но и в том, чтобы позволить программистам сосредоточиться на важных аспектах программы, не увязая в деталях реализации. Простота Eiffel направлена ​​на продвижение простых, расширяемых, повторно используемых и надежных ответов на вычислительные проблемы. Компиляторы для компьютерных программ, написанных на Eiffel, предоставляют обширные методы оптимизации, такие как автоматическое встраивание, которые снимают с программиста часть бремени оптимизации.

Фон

Eiffel изначально был разработан Eiffel Software, компанией, основанной Бертраном Мейером . Object-Oriented Software Construction содержит подробное рассмотрение концепций и теории объектной технологии, которая привела к дизайну Эйфеля. [9]

Целью разработки языка Eiffel, библиотек и методов программирования является предоставление программистам возможности создавать надежные, повторно используемые программные модули. Eiffel поддерживает множественное наследование , универсальность , полиморфизм , инкапсуляцию , безопасные по типу преобразования и ковариантность параметров . Наиболее важным вкладом Eiffel в разработку программного обеспечения является проектирование по контракту (DbC), в котором утверждения , предварительные условия , постусловия и инварианты классов используются для обеспечения корректности программы без ущерба для эффективности.

Дизайн Эйфеля основан на теории объектно-ориентированного программирования, с незначительным влиянием других парадигм или заботой о поддержке устаревшего кода. Eiffel формально поддерживает абстрактные типы данных . Согласно дизайну Эйфеля, программный текст должен иметь возможность воспроизводить свою проектную документацию из самого текста, используя формализованную реализацию «Абстрактного типа данных».

Реализации и среды

EiffelStudio — это интегрированная среда разработки, доступная как по открытой , так и по коммерческой лицензии. Она предлагает объектно-ориентированную среду для разработки программного обеспечения . EiffelEnvision — это подключаемый модуль для Microsoft Visual Studio , который позволяет пользователям редактировать, компилировать и отлаживать проекты Eiffel из среды разработки Microsoft Visual Studio. Доступны еще пять реализаций с открытым исходным кодом : «The Eiffel Compiler» tecomp; Gobo Eiffel; SmartEiffel , реализация GNU, основанная на более старой версии языка; LibertyEiffel , основанная на компиляторе SmartEiffel; и Visual Eiffel .

Несколько других языков программирования включают элементы, впервые представленные в Eiffel. Sather , например, изначально был основан на Eiffel, но с тех пор разошелся и теперь включает несколько функциональных функций программирования. Интерактивный обучающий язык Blue, предшественник BlueJ , также основан на Eiffel. Apple Media Tool включает Apple Media Language на основе Eiffel.

Спецификации и стандарты

Определение языка Eiffel является международным стандартом ISO . Стандарт был разработан ECMA International , которая впервые утвердила стандарт 21 июня 2005 года как Стандарт ECMA-367, Eiffel: Analysis, Design and Programming Language. В июне 2006 года ECMA и ISO приняли вторую версию. В ноябре 2006 года ISO впервые опубликовала эту версию. Стандарт можно найти и использовать бесплатно на сайте ECMA. [10] Версия ISO [11] идентична во всех отношениях, за исключением форматирования.

Eiffel Software, tecomp "The Eiffel Compiler" и разработчик Eiffel-library-developer Gobo взяли на себя обязательство по внедрению стандарта; EiffelStudio 6.1 и tecomp "The Eiffel Compiler" от Eiffel Software реализуют некоторые из основных новых механизмов, в частности, встроенные агенты, команды присваивателя, скобочную нотацию, несоответствующее наследование и присоединенные типы. Команда SmartEiffel отвернулась от этого стандарта, чтобы создать собственную версию языка, которая, по их мнению, ближе к оригинальному стилю Eiffel. Object Tools не раскрыла, будут ли будущие версии ее компилятора Eiffel соответствовать стандарту. LibertyEiffel реализует диалект где-то между языком SmartEiffel и стандартом.

В стандарте приводятся следующие спецификации на языке предшественника Eiffel:

Текущая версия стандарта от июня 2006 года содержит некоторые несоответствия (например, ковариантные переопределения) [ требуется ссылка ] . Комитет ECMA пока не объявил никаких сроков и указаний по устранению несоответствий.

Синтаксис и семантика

Общая структура

«Система» или «программа» Eiffel — это набор классов . Выше уровня классов Eiffel определяет кластер , который по сути является группой классов и, возможно, подкластеров (вложенных кластеров). Кластеры — это не синтаксическая языковая конструкция , а скорее стандартное организационное соглашение. Обычно программа Eiffel организована так, что каждый класс находится в отдельном файле, а каждый кластер — в каталоге, содержащем файлы классов. В этой организации подкластеры являются подкаталогами. Например, в соответствии со стандартными организационными и регистровыми соглашениями x.eможет быть именем файла, который определяет класс с именем X.

Класс содержит функции , которые похожи на «процедуры», «члены», «атрибуты» или «методы» в других объектно-ориентированных языках программирования. Класс также определяет свои инварианты и содержит другие свойства, такие как раздел «заметки» для документации и метаданных. Стандартные типы данных Eiffel, такие как INTEGER, STRINGи ARRAY, сами по себе являются классами.

Каждая система должна иметь класс, обозначенный как «корневой», с одной из его процедур создания, обозначенной как «корневая процедура». Выполнение системы состоит из создания экземпляра корневого класса и выполнения его корневой процедуры. Обычно это создает новые объекты, вызывает новые функции и т. д.

Eiffel имеет пять основных исполняемых инструкций: назначение, создание объекта, вызов процедуры, условие и итерация. Управляющие структуры Eiffel строго следуют структурному программированию : каждый блок имеет ровно один вход и ровно один выход.

Область применения

В отличие от многих объектно-ориентированных языков, но подобно Smalltalk , Eiffel не допускает никакого назначения в атрибуты объектов, за исключением свойств объекта, что является практическим применением принципа сокрытия информации или абстракции данных, требуя формальных интерфейсов для мутации данных. Если выразить это на языке других объектно-ориентированных языков программирования, все атрибуты Eiffel «защищены», и «сеттеры» необходимы для клиентских объектов для изменения значений. Результатом этого является то, что «сеттеры» могут и обычно реализуют инварианты, для которых Eiffel предоставляет синтаксис.

Хотя Eiffel не позволяет клиенту класса осуществлять прямой доступ к функциям класса, он позволяет определить «команду присваивателя», например:

  some_attribute : SOME_TYPE assign set_some_attribute set_some_attribute ( v : VALUE_TYPE ) -- Устанавливает значение some_attribute равным `v'. do some_attribute := v end             

Хотя это и небольшой поклон всему сообществу разработчиков, чтобы разрешить что-то, выглядящее как прямой доступ (например, тем самым нарушая принцип сокрытия информации), эта практика опасна, поскольку она скрывает или запутывает реальность использования "сеттера". На практике лучше перенаправить вызов на сеттер, а не подразумевать прямой доступ к функции, как some_attributeв примере кода выше. [ необходима цитата ]

В отличие от других языков, имеющих понятия «public», «protected», «private» и т. д., Eiffel использует технологию экспорта для более точного управления областью действия между классами клиента и поставщика. Видимость функций проверяется статически во время компиляции. Например, (ниже) «{NONE}» похоже на «protected» в других языках. Область действия, примененная таким образом к «набору функций» (например, все, что находится ниже ключевого слова «feature» или до следующего ключевого слова набора функций, или до конца класса), может быть изменена в классах-потомках с помощью ключевого слова «export».

feature { NONE } -- Инициализация default_create -- Инициализация нового десятичного экземпляра `ноль'. do make_zero end  

В качестве альтернативы отсутствие экспортной декларации {x} подразумевает {ANY} и аналогично «публичной» области действия других языков.

особенность -- Константы 

Наконец, область действия может выборочно и точно контролироваться для любого класса во вселенной проекта Eiffel, например:

функция { DECIMAL , DCM_MA_DECIMAL_PARSER , DCM_MA_DECIMAL_HANDLER } -- Доступ    

Здесь компилятор разрешит доступ к функциям внутри группы функций только классам, перечисленным в фигурных скобках (например, DECIMAL, DCM_MA_DECIMAL_PARSER, DCM_MA_DECIMAL_HANDLER ).

"Привет, мир!"

Внешний вид и восприятие языка программирования часто передаются с помощью программы "Hello, world!" . Такая программа, написанная на Eiffel, может быть:

класс HELLO_WORLD создать создать функцию сделать сделать печать ( "Hello, world!%N" ) конец конец       

Эта программа содержит класс HELLO_WORLD. Конструктор (процедура создания) для класса, названного make, вызывает printсистемную библиотечную процедуру для записи "Hello, world!"сообщения на выход.

Проектирование по контракту

Концепция Design by Contract является центральной для Eiffel. Контракты утверждают, что должно быть истинным до выполнения процедуры (предусловие) и что должно быть истинным после завершения процедуры (постусловие). Контракты инвариантов классов определяют, какие утверждения должны быть истинными как до, так и после доступа к любой функции класса (как к процедурам, так и к атрибутам). Более того, контракты кодифицируют в исполняемый код предположения разработчиков и дизайнеров об операционной среде функций класса или классе в целом с помощью инварианта.

Компилятор Eiffel предназначен для включения контрактов функций и классов на различных уровнях. Например, EiffelStudio выполняет все контракты функций и классов во время выполнения в «режиме Workbench». Когда создается исполняемый файл, компилятор получает указание с помощью файла настроек проекта (например, файла ECF) включить или исключить любой набор контрактов. Таким образом, исполняемый файл может быть скомпилирован для включения или исключения любого уровня контракта, тем самым обеспечивая непрерывные уровни модульного и интеграционного тестирования. Более того, контракты могут непрерывно и методично выполняться с помощью функции Auto-Test, имеющейся в EiffelStudio.

Механизмы «Проектирования по контракту» тесно интегрированы с языком и направляют переопределение функций при наследовании:

Кроме того, язык поддерживает «инструкцию проверки» (своего рода «утверждение»), инварианты цикла и варианты цикла (которые гарантируют завершение цикла).

Возможность безопасного использования пустоты

Возможность Void-safe, как и статическая типизация, является еще одним средством для улучшения качества программного обеспечения. Программное обеспечение Void-safe защищено от ошибок времени выполнения, вызванных вызовами ссылок void , и поэтому будет более надежным, чем программное обеспечение, в котором могут происходить вызовы целевых объектов void. Аналогия со статической типизацией полезна. Фактически, возможность void-safe можно рассматривать как расширение системы типов или шаг за пределы статической типизации, поскольку механизм обеспечения безопасности void интегрирован в систему типов.

Защита от вызовов void target может быть рассмотрена с помощью понятия присоединения и (в расширении) отсоединения (например, ключевое слово detachable). Возможность void-safe можно увидеть в короткой переработке примера кода, использованного выше:

 some_attribute : detachable SOME_TYPE use_some_attribute -- Устанавливает значение some_attribute в `v'. do if attached some_attribute as l_attribute then do_something ( l_attribute ) end end do_something ( a_value : SOME_TYPE ) -- Делает что-то с `a_value'. do ... делает что-то с ` a_value ' ... end                             

Пример кода выше показывает, как компилятор может статически решать вопрос надежности того, some_attributeбудет ли он присоединен или отсоединен в точке его использования. Примечательно, что attachedключевое слово допускает "локальное присоединение" (например, l_attribute), которое ограничено только блоком кода, заключенным в конструкцию if-statement. Таким образом, в этом небольшом блоке кода локальная переменная (например, l_attribute) может быть статически гарантированно непустой (т. е. безопасной для void).

Возможности: команды и запросы

Основная характеристика класса заключается в том, что он определяет набор функций: поскольку класс представляет набор объектов времени выполнения или «экземпляров», функция является операцией над этими объектами. Существует два вида функций: запросы и команды. Запрос предоставляет информацию об экземпляре. Команда изменяет экземпляр.

Различие между командой и запросом важно для метода Эйфеля. В частности:

Перегрузка

Eiffel не допускает перегрузки аргументов . Каждое имя функции в классе всегда сопоставляется с определенной функцией в классе. Одно имя в одном классе означает одно. Такой выбор дизайна способствует читаемости классов, избегая причины неоднозначности относительно того, какая процедура будет вызвана вызовом. Это также упрощает механизм языка; в частности, это делает возможным механизм множественного наследования Eiffel. [12]

Имена, конечно, могут быть повторно использованы в разных классах. Например, признак plus (вместе с его инфиксным псевдонимом "+" ) определен в нескольких классах: INTEGER , REAL , STRING и т. д.

Универсальность

Универсальный класс — это класс, который различается по типу (например, LIST [PHONE], список телефонных номеров; ACCOUNT [G->ACCOUNT_TYPE], позволяющий ACCOUNT [SAVINGS] и ACCOUNT [CHECKING] и т. д.). Классы могут быть универсальными, чтобы выразить, что они параметризованы по типам. Универсальные параметры отображаются в квадратных скобках:

класс СПИСОК [ G ] ...   

G известен как «формальный универсальный параметр». (Эйфель резервирует «аргумент» для подпрограмм и использует «параметр» только для универсальных классов.) При таком объявлении G представляет внутри класса произвольный тип; поэтому функция может возвращать значение типа G, а подпрограмма может принимать аргумент этого типа:

элемент : G сделать ... конец положить ( x : G ) сделать ... конец         

И являются «общими производными» этого класса. Разрешенные комбинации (с , , LIST [INTEGER], ) следующие:LIST [WORD]n: INTEGERw: WORDil: LIST [INTEGER]wl: LIST [WORD]

n := il . item wl . put ( w )   

INTEGERи WORDявляются «фактически общими параметрами» в этих общих выводах.

Также возможно иметь «ограниченные» формальные параметры, для которых фактический параметр должен наследовать от заданного класса, «ограничение». Например, в

 класс HASH_TABLE [ G , KEY -> HASHABLE ]     

вывод HASH_TABLE [INTEGER, STRING]допустим только в том случае, если STRINGнаследует от HASHABLE(как это действительно происходит в типичных библиотеках Eiffel). Внутри класса, имея KEYограничение HASHABLEсредствами , для x: KEYможно применить ко xвсем функциям HASHABLE, как в x.hash_code.

Основы наследования

Чтобы унаследовать от одного или нескольких других классов, класс должен включать inheritв начало предложение:

класс C наследует A B    -- ... Остальная часть объявления класса ...

Класс может переопределять (переопределять) некоторые или все унаследованные функции. Это должно быть явно объявлено в начале класса через redefineподпункт пункта наследования, как в

класс C наследует A переопределяет f , g , h конец B переопределяет u , v конец             

Полное обсуждение наследования Эйфеля см . в [13] .

Отложенные классы и функции

Классы могут быть определены с помощью , deferred classа не с , classчтобы указать, что класс не может быть напрямую инстанцирован. Не инстанцируемые классы называются абстрактными классами в некоторых других объектно-ориентированных языках программирования. На языке Эйфеля, только «эффективный» класс может быть инстанцирован (он может быть потомком отложенного класса). Функция также может быть отложена с помощью deferredключевого слова вместо doпредложения. Если класс имеет какие-либо отложенные функции, он должен быть объявлен как отложенный; однако класс без отложенных функций тем не менее сам может быть отложенным.

Отложенные классы играют отчасти ту же роль, что и интерфейсы в таких языках, как Java, хотя многие теоретики объектно-ориентированного программирования считают, что интерфейсы сами по себе в значительной степени являются ответом на отсутствие множественного наследования в Java (которое есть в Eiffel). [14] [15]

Переименование

Класс, который наследует от одного или нескольких других, получает все свои функции по умолчанию под их исходными именами. Однако он может изменить их имена с помощью renameпредложений. Это требуется в случае множественного наследования, если есть конфликты имен между унаследованными функциями; без переименования результирующий класс нарушил бы принцип отсутствия перегрузки, отмеченный выше, и, следовательно, был бы недействительным.

Кортежи

Типы кортежей можно рассматривать как простую форму класса, предоставляющую только атрибуты и соответствующую процедуру «setter». Типичный тип кортежа читается как

 КОРТЕЖ [ имя : СТРОКА ; вес : ДЕЙСТВИТЕЛЬНЫЙ ; дата : ДАТА ]      

и может быть использован для описания простого понятия записи о рождении, если класс не нужен. Экземпляр такого кортежа — это просто последовательность значений с заданными типами, указанными в скобках, например

 [ "Бриджит" , 3.5 , Last_night ]  

К компонентам такого кортежа можно получить доступ, как если бы теги кортежа были атрибутами класса, например, если tбыл назначен вышеуказанный кортеж, то t.weightон имеет значение 3.5.

Благодаря понятию команды назначения (см. ниже) точечная нотация также может использоваться для назначения компонентов такого кортежа, как в

 т . вес := т . вес + 0,5    

Теги кортежа являются необязательными, поэтому тип кортежа также можно записать как TUPLE [STRING, REAL, DATE]. (В некоторых компиляторах это единственная форма кортежа, поскольку теги были введены вместе со стандартом ECMA.)

Точная спецификация eg TUPLE [A, B, C]заключается в том, что она описывает последовательности из как минимум трех элементов, первые три из которых имеют типы A, B, Cсоответственно. В результате TUPLE [A, B, C]соответствует (может быть назначен) TUPLE [A, B], TUPLE [A]и TUPLE(без параметров) самому верхнему типу кортежа, которому соответствуют все типы кортежей.

Агенты

Механизм «агента» Эйфеля оборачивает операции в объекты. Этот механизм может использоваться для итерации, событийно-управляемого программирования и других контекстов, в которых полезно передавать операции вокруг структуры программы. Другие языки программирования, особенно те, которые делают упор на функциональное программирование , допускают схожий шаблон с использованием продолжений , замыканий или генераторов ; агенты Эйфеля подчеркивают объектно-ориентированную парадигму языка и используют синтаксис и семантику, похожие на блоки кода в Smalltalk и Ruby .

Например, чтобы выполнить my_actionблок для каждого элемента my_list, нужно написать:

 my_list.do_all ( агент my_action )  

Чтобы выполнить my_actionтолько те элементы, которые удовлетворяют my_condition, можно добавить ограничение/фильтр:

 my_list.do_if ( агент my_action , агент my_condition )    

В этих примерах my_actionи my_conditionявляются подпрограммами. Префикс с ними agentдает объект, который представляет соответствующую подпрограмму со всеми ее свойствами, в частности, возможностью быть вызванным с соответствующими аргументами. Так что если aпредставляет этот объект (например, потому что aявляется аргументом для do_all), инструкция

 а . вызов ( [ x ] ) 

вызовет исходную процедуру с аргументом x, как если бы мы напрямую вызвали исходную процедуру: my_action (x). Аргументы callпередаются в виде кортежа, здесь [x].

Можно оставить некоторые аргументы агента открытыми и сделать другие закрытыми . Открытые аргументы передаются как аргументы в call: они предоставляются во время использования агента . Закрытые аргументы предоставляются во время определения агента . Например, если action2имеет два аргумента, итерация

 my_list.do_all ( действие агента2 ( ? , y ) )    

итерации action2 (x, y)для последовательных значений x, где второй аргумент остается установленным на y. Вопросительный знак ?указывает на открытый аргумент; yявляется закрытым аргументом агента. Обратите внимание, что базовый синтаксис agent fявляется сокращением для agent f (?, ?, ...)со всеми открытыми аргументами. Также возможно сделать цель агента открытой с помощью нотации {T}?, где Tявляется типом цели.

Различие между открытыми и закрытыми операндами (операнды = аргументы + цель) соответствует различию между связанными и свободными переменными в лямбда-исчислении . Выражение агента, например, action2 (?, y)с некоторыми закрытыми операндами и некоторыми открытыми, соответствует версии исходной операции, каррированной на закрытых операндах.

Механизм агента также позволяет определять агента без ссылки на существующую процедуру (например my_action, my_condition, , action2), через встроенные агенты, как в

my_list.do_all ( agent ( s : STRING ) require not_void : s / = Void do s.append_character ( ' , ' ) ensure appended : s.count = old s.count + 1 end )                    

Встроенный агент, переданный здесь, может иметь все атрибуты обычной процедуры, включая предусловие, постусловие, спасательное предложение (здесь не используется) и полную сигнатуру. Это позволяет избежать определения процедур, когда все, что нужно, — это вычисление, которое должно быть упаковано в агента. Это полезно, в частности, для контрактов, как в инвариантном предложении, которое выражает, что все элементы списка являются положительными:

 my_list . for_all ( агент ( x : INTEGER ): BOOLEAN do Результат := ( x > 0 ) конец )           

Текущий механизм агента оставляет возможность ошибки типа времени выполнения (если процедура с n аргументами передается агенту, ожидающему m аргументов с m < n ). Этого можно избежать проверкой времени выполнения через предварительное условие valid_arguments. callДоступно несколько предложений по чисто статической коррекции этой проблемы, включая предложение об изменении языка от Рибета и др. [16]

Однажды рутины

Результат подпрограммы можно кэшировать, используя onceключевое слово вместо do. Непервые вызовы подпрограммы не требуют дополнительных вычислений или выделения ресурсов, а просто возвращают ранее вычисленный результат. Распространенный шаблон для «функций once» — предоставление общих объектов; первый вызов создаст объект, последующие вернут ссылку на этот объект. Типичная схема:

shared_object : SOME_TYPE once create Result . make ( args ) — Создает объект и возвращает ссылку на него через `Result'. end       

Возвращаемый объект — Resultв примере — сам по себе может быть изменяем, но его ссылка остается прежней.

Часто «однажды выполняемые процедуры» выполняют требуемую инициализацию: несколько вызовов библиотеки могут включать вызов процедуры инициализации, но только первый такой вызов выполнит требуемые действия. Используя этот шаблон, инициализация может быть децентрализована, что позволяет избежать необходимости в специальном модуле инициализации. «Однажды выполняемые процедуры» по своему назначению и эффекту аналогичны шаблону singleton во многих языках программирования и шаблону Borg, используемому в Python.

По умолчанию "once routine" вызывается один раз на поток . Семантика может быть настроена на один раз на процесс или один раз на объект , квалифицируя ее с помощью "once key", например once ("PROCESS").

Конверсии

Eiffel предоставляет механизм, позволяющий осуществлять преобразования между различными типами. Механизмы сосуществуют с наследованием и дополняют его. Чтобы избежать путаницы между двумя механизмами, конструкция реализует следующий принцип:

(Принцип преобразования) Тип не может одновременно соответствовать другому и преобразовываться в него.

Например, NEWSPAPERможет соответствовать PUBLICATION, но INTEGERпреобразуется в REAL(и не наследуется от него).

Механизм преобразования просто обобщает специальные правила преобразования (такие как, например, между INTEGERи REAL), которые существуют в большинстве языков программирования, делая их применимыми к любому типу, пока соблюдается указанный выше принцип. Например, класс DATEможет быть объявлен для преобразования в STRING; это позволяет создать строку из даты просто через

 моя_строка := моя_дата  

как сокращение для использования явного создания объекта с процедурой преобразования:

 создать my_string . make_from_date ( my_date )  

Чтобы сделать первую форму возможной в качестве синонима второй, достаточно перечислить процедуру создания (конструктор) make_from_dateв convertпредложении в начале класса.

В качестве другого примера, если есть такая процедура преобразования, перечисленная в TUPLE [day: INTEGER; month: STRING; year: INTEGER], то можно напрямую присвоить кортеж дате, вызвав соответствующее преобразование, как в

 Bastille_day := [ 14 , "Июль" , 1789 ]    

Обработка исключений

Обработка исключений в Eiffel основана на принципах проектирования по контракту. Например, исключение возникает, когда вызывающий подпрограмму не может удовлетворить предварительное условие или когда подпрограмма не может гарантировать обещанное постусловие. В Eiffel обработка исключений не используется для управления потоком или для исправления ошибок ввода данных.

Обработчик исключений Eiffel определяется с помощью ключевого слова rescue . В разделе rescue ключевое слово retry выполняет процедуру снова. Например, следующая процедура отслеживает количество попыток выполнения процедуры и повторяет ее только определенное количество раз:

connect_to_server ( server : SOCKET ) — Подключиться к серверу или отказаться от попыток после 10. require server /= Void и затем server . address /= Void локальные попытки : INTEGER do server . connect sure connected : server . is_connected rescue if attempts < 10 then attempts := attempts + 1 retry end end                                  

Однако этот пример, возможно, некорректен для чего угодно, кроме самых простых программ, поскольку сбой соединения следует ожидать. Для большинства программ имя процедуры вроде attempt_connecting_to_server было бы лучше, а постусловие не обещало бы соединение, оставляя вызывающему процессу принятие соответствующих мер, если соединение не было открыто.

Параллелизм

Доступно несколько сетевых и потоковых библиотек, таких как EiffelNet и EiffelThreads. Модель параллелизма для Eiffel, основанная на концепциях проектирования по контракту, — это SCOOP , или простое параллельное объектно-ориентированное программирование , пока не являющееся частью официального определения языка, но доступное в EiffelStudio . CAMEO [17] — это (нереализованный) вариант SCOOP для Eiffel. Параллелизм также взаимодействует с исключениями. Асинхронные исключения могут быть проблемными (когда процедура вызывает исключение после того, как ее вызывающий завершил работу). [18]

Синтаксис оператора и скобок, команды присваивателя

Взгляд Эйфеля на вычисления полностью объектно-ориентирован в том смысле, что каждая операция относится к объекту, «цели». Так, например, такое сложение, как

а + б  

концептуально понимается так, как если бы это был вызов метода

а . плюс ( б ) 

с целью a, функцией plusи аргументом b.

Конечно, первый вариант является общепринятым синтаксисом и обычно предпочтителен. Синтаксис оператора позволяет использовать любую форму, объявляя функцию (например, в INTEGER, но это применимо к другим базовым классам и может использоваться в любом другом, для которого подходит такой оператор):

плюс псевдоним "+" ( другое : INTEGER ): INTEGER -- ... Обычное объявление функции... конец       

Диапазон операторов, которые можно использовать в качестве "псевдонима", довольно широк; они включают предопределенные операторы, такие как "+", а также "свободные операторы", состоящие из небуквенно-цифровых символов. Это позволяет разрабатывать специальные инфиксные и префиксные обозначения, например, в математических и физических приложениях.

Каждый класс может дополнительно иметь одну функцию, псевдонимом "[]", оператор "скобка", позволяющий использовать нотацию a [i, ...]как синоним для того, a.f (i, ...)где fнаходится выбранная функция. Это особенно полезно для структур контейнеров, таких как массивы, хэш-таблицы , списки и т. д. Например, доступ к элементу хэш-таблицы со строковыми ключами можно записать

 номер := телефонная_книга [ "ДЖИЛЛ СМИТ" ]   

"Команды присваивателя" — это сопутствующий механизм, разработанный в том же духе, позволяющем использовать устоявшуюся, удобную нотацию, переосмысленную в рамках объектно-ориентированного программирования. Команды присваивателя позволяют синтаксису, похожему на присваивание, вызывать процедуры "установщика". Собственно присваивание никогда не может иметь форму , a.x := vпоскольку это нарушает сокрытие информации; вам придется использовать команду (процедуру) установщика. Например, класс хэш-таблицы может иметь функцию и процедуру

псевдоним элемента "[]" ( ключ : STRING ): ELEMENT [ 3 ] -- Элемент ключа `key'. -- (Запрос "Getter") do ... end           put ( e : ELEMENT ; key : STRING ) -- Вставляет элемент `e', связывая его с ключом `key'. -- (Команда "Setter") do ... end         

Затем, чтобы вставить элемент, необходимо использовать явный вызов команды setter:

 [ 4 ] телефонная_книга . put ( Новая_персона , "ДЖИЛЛ СМИТ" )   

Это можно эквивалентно записать как

 [ 5 ] телефонная_книга [ "ДЖИЛЛ СМИТ" ] := Новый_человек    

(таким же образом, что phone_book ["JILL SMITH"]является синонимом number := phone_book.item ("JILL SMITH")), при условии, что объявление itemnow начинается (замена для [3]) с

 псевдоним элемента "[]" ( ключ : СТРОКА ): ЭЛЕМЕНТ назначить положить       

Это объявляет putкоманду присваивателя, связанную с itemи, в сочетании с псевдонимом скобок, делает [5] допустимым и эквивалентным [4]. (Это также можно было бы записать, не используя скобки, как phone_book.item ("JILL SMITH") := New_person.

Примечание: Список аргументов присваивателя a ограничен следующим образом: (возвращаемый тип a; весь список аргументов a...)

Лексические и синтаксические свойства

Eiffel не чувствителен к регистру. Токены make, maKeи MAKEвсе обозначают один и тот же идентификатор. Однако см. «правила стиля» ниже.

Комментарии начинаются с --(двух последовательных тире) и продолжаются до конца строки.

Точка с запятой, как разделитель инструкций, необязательна. В большинстве случаев точка с запятой просто опускается, за исключением случаев разделения нескольких инструкций в строке. Это приводит к уменьшению беспорядка на странице программы.

Нет вложенности деклараций функций и классов. В результате структура класса Eiffel проста: некоторые предложения уровня класса (наследование, инвариант) и последовательность деклараций функций, все на одном уровне.

Обычно функции группируют в отдельные «пункты функций» для большей удобочитаемости, при этом стандартный набор базовых тегов функций отображается в стандартном порядке, например:

класс HASH_TABLE [ ЭЛЕМЕНТ , КЛЮЧ -> ХЕШИРОВАННЫЙ ] наследует ТАБЛИЦА [ ЭЛЕМЕНТ ]         функция -- Инициализация -- ... Объявления команд инициализации (процедуры создания/конструкторы) ...   feature -- Access -- ... Объявления небулевых запросов к состоянию объекта, например, item ...   функция -- Отчет о состоянии -- ... Объявления булевых запросов о состоянии объекта, например is_empty ...   функция -- Изменение элемента -- ... Объявления команд, которые изменяют структуру, например, put ...   -- и т.д. конец

В отличие от большинства языков программирования с фигурными скобками , Eiffel делает четкое различие между выражениями и инструкциями. Это соответствует принципу разделения команд и запросов метода Eiffel.

Стилевые условности

Большая часть документации Eiffel использует отличительные стилистические соглашения, призванные обеспечить единообразный внешний вид и восприятие. Некоторые из этих соглашений применяются к самому формату кода, а другие — к стандартному типографскому отображению кода Eiffel в форматах и ​​публикациях, где эти соглашения возможны.

Хотя язык нечувствителен к регистру, стандарты стиля предписывают использование всех заглавных букв для имен классов ( LIST), всех строчных букв для имен функций ( make) и начальных заглавных букв для констант ( Avogadro). Рекомендуемый стиль также предполагает подчеркивание для разделения компонентов идентификатора из нескольких слов, как в average_temperature.

Спецификация Eiffel включает в себя рекомендации по отображению текстов программного обеспечения в форматах набора: ключевые слова выделены жирным шрифтом, определяемые пользователем идентификаторы и константы показаны в italics, комментарии, операторы и знаки препинания в Roman, а текст программы в blueкак в настоящей статье, чтобы отличить его от пояснительного текста. Например, программа "Hello, world!", приведенная выше, будет отображаться в документации Eiffel следующим образом:

класс HELLO_WORLD создать сделать функцию сделать сделать печать ( "Привет, мир!" ) конец конец       

Интерфейсы к другим инструментам и языкам

Eiffel — чисто объектно-ориентированный язык, но он обеспечивает открытую архитектуру для взаимодействия с «внешним» программным обеспечением на любом другом языке программирования.

Например, можно программировать операции на уровне машины и операционной системы на языке C. Eiffel предоставляет простой интерфейс для подпрограмм C, включая поддержку «встроенного C» (написание тела подпрограммы Eiffel на языке C, обычно для коротких операций на уровне машины).

Хотя между Eiffel и C нет прямой связи, многие компиляторы Eiffel ( Visual Eiffel — одно из исключений) выводят исходный код C как промежуточный язык для передачи компилятору C для оптимизации и переносимости . Таким образом, они являются примерами транскомпиляторов . Компилятор Eiffel tecomp может выполнять код Eiffel напрямую (как интерпретатор), не проходя через промежуточный код C, или выдавать код C, который будет передан компилятору C для получения оптимизированного собственного кода. В .NET компилятор EiffelStudio напрямую генерирует код CIL (Common Intermediate Language). Компилятор SmartEiffel также может выводить байт-код Java .

Ссылки

  1. ^ "Эйфель в двух словах". archive.eiffel.com . Получено 24 августа 2017 г. .
  2. ^ "EiffelStudio 24.05 уже доступна!". Eiffel.org . 14 июня 2024 г.
  3. ^ Купер, Питер (2009). Beginning Ruby: From Novice to Professional . Beginning from Novice to Professional (2-е изд.). Беркли: APress. стр. 101. ISBN 978-1-4302-2363-4. В меньшей степени на Ruby также оказали влияние Python, LISP, Eiffel, Ada и C++.
  4. ^ "Eiffel – the Language". berenddeboer.net . Получено 6 июля 2016 г. .
  5. ^ Мейер, Бертран (28.08.2009). Прикосновение класса: как научиться хорошо программировать с помощью объектов и контрактов. Springer Science & Business Media. ISBN 978-3-540-92144-8.
  6. ^ "Языки программирования - Eiffel" (PDF) . Department of Computer Science, Virginia Tech . Получено 25 марта 2023 г.
  7. ^ Карл Фрисс. "Eiffel Syntax Guide". Eiffel Syntax Guide . Получено 25 марта 2023 г. .
  8. ^ Клаус Брабранд. «Язык программирования EIFFEL» (PDF) . IT University of Copenhagen . Получено 25 марта 2023 г. .
  9. ^ Объектно-ориентированное построение программного обеспечения , второе издание, Бертран Мейер , Prentice Hall, 1997, ISBN 0-13-629155-4 
  10. ^ ECMA International: Стандарт ECMA-367 – Eiffel: Язык анализа, проектирования и программирования, 2-е издание (июнь 2006 г.); доступно онлайн по адресу https://ecma-international.org/publications-and-standards/standards/ecma-367/
  11. ^ Международная организация по стандартизации: Стандарт ISO/IEC DIS 25436, доступен онлайн по адресу [1]
  12. Бертран Мейер: Перегрузка против объектной технологии, в журнале «Объектно-ориентированное программирование» (JOOP), т. 14, № 4, октябрь–ноябрь 2001 г., доступно онлайн
  13. ^ "9 НАСЛЕДОВАНИЕ". Archive.eiffel.com. 1997-03-23 . Получено 2013-07-08 .
  14. ^ "Множественное наследование и интерфейсы". Artima.com. 2002-12-16 . Получено 2013-07-08 .
  15. ^ "Множественное наследование — не зло". C2.com. 2007-04-28 . Получено 2013-07-08 .
  16. ^ Филипп Рибет, Сирил Адриан, Оливье Зендра, Доминик Колне: Соответствие агентов в языке Эйфеля , в Journal of Object Technology , т. 3, № 4, апрель 2004 г., Специальный выпуск: TOOLS USA 2003, стр. 125-143. Доступно онлайн на странице статьи JOT
  17. ^ Брук, Филлип; Ричард Пейдж (2008). «Камея: альтернативная модель параллелизма для Eiffel» (PDF) . Формальные аспекты вычислений . 21 (4). Springer: 363–391. doi :10.1007/s00165-008-0096-1. S2CID  18336088.
  18. ^ Брук, Филлип; Ричард Пейдж (2007). «Исключения в параллельном Эйфеле». Журнал объектных технологий . 6 (10): 111–126. doi : 10.5381/jot.2007.6.10.a4 .

Внешние ссылки