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

Эйфель
Логотип Eiffel
Парадигма Объектно-ориентированный , на основе классов , универсальный , параллельный
Разработано Бертран Мейер
Разработчик Программное обеспечение Eiffel
Впервые появился 1986 г.
Стабильный выпуск
EiffelStudio 20.11 / 21 декабря 2020 ; 9 месяцев назад ( 21.12.2020 )
Предварительный выпуск
EiffelStudio 20.11 / 21 декабря 2020 ; 9 месяцев назад ( 21.12.2020 )
Печатная дисциплина статический
Язык реализации Эйфель
Платформа Кроссплатформенность
Операционные системы FreeBSD , Linux , Mac OS X , OpenBSD , Solaris , Windows
Лицензия двойной и корпоративный
Расширения имени файла .e
Веб-сайт www .eiffel .org
Основные реализации
EiffelStudio , LibertyEiffel , SmartEiffel , Visual Eiffel , Gobo Eiffel, "The Eiffel Compiler" tecomp
Под влиянием
Ада , Симула , Z
Под влиянием
Ада 2012 , Альбатрос , C # , D , Java , Racket , Ruby , Sather , Scala

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

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

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

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

Ключевые характеристики языка Eiffel включают:

  • Объектно-ориентированная программная структура, в которой класс служит основной единицей декомпозиции.
  • Дизайн по контракту тесно интегрирован с другими языковыми конструкциями.
  • Автоматическое управление памятью, обычно реализуемое сборкой мусора .
  • Наследование , включая множественное наследование , переименование , переопределение , «выбор», наследование несоответствий и другие механизмы, предназначенные для обеспечения безопасности наследования.
  • Ограниченное и неограниченное обобщенное программирование
  • Единая система типов, обрабатывающая семантику значений и ссылок, в которой все типы, включая базовые типы, такие как INTEGER, основаны на классах.
  • Статическая типизация
  • Защита от аннулирования или статическая защита от вызовов нулевых ссылок с помощью механизма прикрепленных типов.
  • Агенты или объекты, которые обертывают вычисления, тесно связанные с замыканиями и лямбда-исчислением .
  • Один раз подпрограммы или подпрограммы, оцениваемые только один раз, для совместного использования объектов и децентрализованной инициализации.
  • Синтаксис на основе ключевых слов в традициях ALGOL / Pascal, но без разделителей, поскольку точки с запятой являются необязательными, а синтаксис операторов доступен для подпрограмм.
  • Нечувствительность к регистру
  • Простое параллельное объектно-ориентированное программирование ( SCOOP ) облегчает создание нескольких одновременно активных средств выполнения на уровне абстракции, превышающем конкретные детали этих средств (например, несколько потоков без специального управления мьютексами).

Цели дизайна

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

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

Фон

Eiffel был первоначально разработан Eiffel Software, компанией, основанной Бертраном Мейером . Построение объектно-ориентированного программного обеспечения содержит подробное описание концепций и теории объектной технологии, которая привела к созданию Эйфеля.

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

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

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

EiffelStudio - это интегрированная среда разработки, доступная как по лицензии с открытым исходным кодом, так и по коммерческой лицензии. Он предлагает объектно-ориентированную среду для разработки программного обеспечения . EiffelEnvision - это подключаемый модуль для Microsoft Visual Studio, который позволяет пользователям редактировать, компилировать и отлаживать проекты Eiffel из среды Microsoft Visual Studio IDE. Доступны пять других реализаций с открытым исходным кодом : Tecomp "The Eiffel Compiler"; Гобо Эйфель; SmartEiffel , реализация GNU, основанная на более старой версии языка; LibertyEiffel , основанный на компиляторе SmartEiffel; и Visual Eiffel .

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

Технические характеристики и стандарты

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

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

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

  • Бертран Мейер: Eiffel: The Language, Prentice Hall, вторая печать, 1992 г. (первая печать: 1991 г.)
  • Бертран Мейер: Standard Eiffel (пересмотр предыдущей статьи), в настоящее время, с 1997 г. по настоящее время, на странице Бертрана Мейера в ETL3, и
  • Бертран Мейер: Построение объектно-ориентированного программного обеспечения, Prentice Hall: первое издание, 1988; Издание второе, 1997 г.
  • Бертран Мейер: Прикосновение к классу: учимся хорошо программировать с объектами и контрактами, Springer-Verlag, 2009 ISBN  978-3-540-92144-8 lxiv + 876 страниц Полноцветная печать, многочисленные цветные фотографии

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

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

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

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

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

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

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

Определение объема

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

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

 
   some_attribute: SOME_TYPE assign set_some_attribute
    
   set_some_attribute (v: VALUE_TYPE)
                -- Set value of some_attribute to `v'.
            do
                some_attribute := v
            end

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

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

feature {NONE} -- Initialization
	default_create
			-- Initialize a new `zero' decimal instance.
		do
			make_zero
		end

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

feature -- Constants

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

feature {DECIMAL, DCM_MA_DECIMAL_PARSER, DCM_MA_DECIMAL_HANDLER} -- Access

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

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

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

class
    HELLO_WORLD
create
    make
feature
    make
        do
            print ("Hello, world!%N")
        end
end

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

Дизайн по контракту

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

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

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

  • Обычное предусловие: предусловие может быть ослаблено только наследованием; любой вызов, отвечающий требованиям предка, соответствует требованиям потомка.
  • Обычное постусловие: Постусловие может быть усилено только наследованием; любой результат, гарантированный предком, по-прежнему предоставляется потомком.
  • Инвариант класса: условия, которые должны выполняться после создания объекта и после любого вызова экспортированной подпрограммы класса. Поскольку инвариант проверяется так часто, это делает его одновременно и самой дорогой, и самой мощной формой условия или контракта.

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

Возможность защиты от пустоты

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

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

   some_attribute: detachable SOME_TYPE
    
   use_some_attribute
                -- Set value of some_attribute to `v'.
            do
                if attached some_attribute as l_attribute then
                    do_something (l_attribute)
                end
            end
    
    do_something (a_value: SOME_TYPE)
                -- Do something with `a_value'.
            do
               ... doing something with `a_value' ...
            end

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

Особенности: команды и запросы

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

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

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

Перегрузка

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

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

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

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

class LIST [G] ...

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

item: G do ... end
put (x: G) do ... end

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

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

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

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

   class HASH_TABLE [G, KEY -> HASHABLE]

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

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

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

class C inherit
   A
   B

-- ... Rest of class declaration ...

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

class C inherit
    A
        redefine f, g, h end
    B
        redefine u, v end

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

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

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

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

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

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

Кортежи

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

   TUPLE [name: STRING; weight: REAL; date: DATE]

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

   ["Brigitte", 3.5, Last_night]

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

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

   t.weight := t.weight + 0.5

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

Точная спецификация , например , в 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 (agent my_action)

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

   my_list.do_if (agent my_action, agent my_condition)

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

   a.call ([x])

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

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

   my_list.do_all (agent action2 (?, 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 (agent (x: INTEGER): BOOLEAN do Result := (x > 0) end)

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

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

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

shared_object: SOME_TYPE
    once
        create Result.make (args)
             -- This creates the object and returns a reference to it through `Result'.
    end

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

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

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

Конверсии

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

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

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

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

   my_string := my_date

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

   create my_string.make_from_date (my_date)

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

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

      Bastille_day := [14, "July", 1789]

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

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

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

connect_to_server (server: SOCKET)
      -- Connect to a server or give up after 10 attempts.
    require
        server /= Void and then server.address /= Void
    local
        attempts: INTEGER
    do
        server.connect
    ensure
      connected: server.is_connected
    rescue
        if attempts < 10 then
            attempts := attempts + 1
            retry
        end
    end

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

Параллелизм

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

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

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

a + b

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

a.plus (b)

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

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

plus alias "+" (other: INTEGER): INTEGER
        -- ... Normal function declaration...
    end

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

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

   number := phone_book ["JILL SMITH"]

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

item alias "[]" (key: STRING): ELEMENT         [3]
      -- The element of key `key'.
      -- ("Getter" query)
    do
        ...
    end

put (e: ELEMENT; key: STRING)
      -- Insert the element `e', associating it with the key `key'.
      -- ("Setter" command)
    do
        ...
    end

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

   [4] phone_book.put (New_person, "JILL SMITH")

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

   [5] phone_book ["JILL SMITH"] := New_person

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

   item alias "[]" (key: STRING): ELEMENT assign put

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

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

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

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

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

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

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

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

class HASH_TABLE [ELEMENT, KEY -> HASHABLE] inherit TABLE [ELEMENT]

    feature -- Initialization
         -- ... Declarations of initialization commands (creation procedures/constructors) ...

    feature -- Access
         -- ... Declarations of non-boolean queries on the object state, e.g. item ...

    feature -- Status report
         -- ... Declarations of boolean queries on the object state, e.g. is_empty ...

    feature -- Element change
         -- ... Declarations of commands that change the structure, e.g. put ...

    -- etc.
end

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

Соглашения о стилях

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

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

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

class
    HELLO_WORLD
create
    make
feature
    make
       do
          print ("Hello, world!")
       end
end

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

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

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

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

использованная литература

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

  • Веб-сайт Eiffel Software компании, представившей Eiffel, назывался Interactive Software Engineering (ISE).