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

Дилан
Дилан logo.png
Парадигма мультипарадигма : функциональная , объектно-ориентированная
Разработчик Сообщество открытого исходного кода Apple Computer , Арлекин , Университет Карнеги-Меллона
Впервые появился 1992 ; 29 лет назад ( 1992 )
Стабильный выпуск
2020.1 / 10 октября 2020 г . ; 8 месяцев назад ( 2020-10-10 )
Печатная дисциплина Сильный, динамичный
Платформа IA-32 , x86-64
Операционные системы Кроссплатформенность
Расширения имени файла Дилан
Веб-сайт opendylan .org
Основные реализации
Открыть Дилан , Гвидион Дилан
Диалекты
инфикс-дилан (AKA Dylan), префикс-дилан (AKA Lisp)
Под влиянием
ЗАКРЫТЬ , АЛГОЛ , Схема , EuLisp
Под влиянием
Лассо , Питон , Рубин , Джулия

Dylan - это многопарадигмальный язык программирования, который включает поддержку функционального и объектно-ориентированного программирования (ООП), является динамическим и рефлексивным, а также предоставляет модель программирования, предназначенную для поддержки генерации эффективного машинного кода, включая детальный контроль над динамическим и статическим поведением. . Он был создан в начале 1990-х годов группой под руководством Apple Computer .

Краткий и подробный обзор языка можно найти в Справочном руководстве Дилана.

Дилан является производным от Scheme и Common Lisp и добавляет интегрированную объектную систему, производную от Common Lisp Object System (CLOS). В Дилане все значения (включая числа, символы, функции и классы ) являются объектами первого класса . Dylan поддерживает множественное наследование , полиморфизм , множественную отправку , аргументы ключевых слов , интроспекцию объекта, макросы расширения синтаксиса на основе шаблонов и многие другие расширенные функции. Программы могут выражать детальный контроль над динамизмом, допуская программы, которые занимают континуум между динамическим и статическим программированием и поддерживают эволюционную разработку (что позволяет быстро создавать прототипы с последующим постепенным уточнением и оптимизацией).

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

Дилан заимствует большую часть своей семантики из Scheme и других Lisp; некоторые реализации Dylan изначально были построены в существующих системах Lisp. Тем не менее, Дилан имеет Алгол -как синтаксис вместо Лисп-подобный синтаксис префикс.

История

Дилан был создан в начале 1990-х годов группой под руководством Apple Computer . Когда-то в процессе разработки он предназначался для использования с компьютером Apple Newton , но реализация Dylan не достигла достаточной зрелости во времени, и Newton вместо этого использовал смесь C и NewtonScript, разработанную Уолтером Смитом. Apple прекратила разработку Dylan в 1995 году, хотя и сделала доступной «технологическую версию» (Apple Dylan TR1), которая включала усовершенствованную интегрированную среду разработки (IDE).

Две другие группы внесли свой вклад в дизайн языка и разработали его реализации: Harlequin выпустил коммерческую среду IDE для Microsoft Windows, а Университет Карнеги-Меллона выпустил компилятор с открытым исходным кодом для систем Unix под названием Gwydion Dylan. Обе эти реализации теперь имеют открытый исходный код. Реализация Harlequin теперь называется Open Dylan и поддерживается группой добровольцев Dylan Hackers.

Язык Дилана носил кодовое имя Ральф. Джеймс Хоакин выбрал имя Дилан для «динамического языка».

Синтаксис

Многие синтаксические особенности Дилана берут начало в его наследии Лиспа. Первоначально Дилан использовал синтаксис префиксов, подобный Лиспу, который был основан на s-выражениях . К тому времени, когда разработка языка была завершена, синтаксис был изменен на синтаксис, подобный АЛГОЛу, с ожиданием, что он будет более знаком более широкой аудитории программистов. Синтаксис был разработан Майклом Калем. Это подробно описано в Справочном руководстве Дилана.

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

Дилан не чувствителен к регистру . Лексический синтаксис Дилана позволяет использовать соглашение об именах, в котором знаки дефис-минус используются для соединения частей идентификаторов, состоящих из нескольких слов (иногда называемых « lisp-case » или « kebab case »). Это соглашение распространено в языках Lisp, но не может использоваться в языках программирования, которые рассматривают любой дефис-минус, который не является частью числового литерала, как один лексический токен , даже если он не окружен пробельными символами .

Помимо буквенно-цифровых символов и знаков дефис-минус, Dylan допускает использование некоторых не буквенно-цифровых символов в составе идентификаторов. Идентификаторы не могут состоять только из этих не буквенно-цифровых символов или только из цифровых символов. Если есть какая-то двусмысленность, используется пробел.

Пример кода

Простой класс с несколькими слотами:

define class <point> (<object>)
  slot point-x :: <integer>,
    required-init-keyword: x:;
  slot point-y :: <integer>,
    required-init-keyword: y:;
end class <point>;

По соглашению, классы обозначаются знаками «меньше» и «больше», используемыми в качестве угловых скобок , например, класс, названный <point>в примере кода.

В end class <point>обоих случаях classи <point>являются необязательными. Это верно для всех endпунктов. Например, вы можете написать end ifили просто endзавершить ifзаявление.

Тот же самый класс, переписанный минимально возможным способом:

define class <point> (<object>)
  slot point-x;
  slot point-y;
end;

Теперь оба слота имеют тип <object>. Слоты необходимо инициализировать вручную.

По соглашению имена констант начинаются с символа «$»:

define constant $pi :: <double-float> = 3.1415927d0;

Факториальная функция:

define function factorial (n :: <integer>) => (n! :: <integer>)
  case
    n < 0     => error("Can't take factorial of negative integer: %d\n", n);
    n = 0     => 1;
    otherwise => n * factorial(n - 1);
  end
end;

Вот n!и <integer>обычные идентификаторы.

Нет явного оператора возврата . Результатом метода или функции является последнее вычисленное выражение. Это распространенный стиль - оставлять точку с запятой после выражения в позиции возврата.

Модули против пространства имен

Во многих объектно-ориентированных языках классы являются основным средством инкапсуляции и модульности; каждый класс определяет пространство имен и контролирует, какие определения видны извне. Кроме того, классы во многих языках определяют неделимую единицу, которая должна использоваться как единое целое. Например, использование Stringфункции конкатенации требует импорта и компиляции всех файлов String.

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

В Дилане концепции compile-unit и import-unit разделены, и классы не имеют к ним никакого отношения. А библиотека определяет элементы , которые должны быть собраны и обработаны вместе, в то время как модуль определяет пространство имен. Классы могут быть объединены в модули или разрезаны по желанию программиста. Часто полное определение класса не существует в одном модуле, а распределено по нескольким, которые при желании могут быть собраны вместе. В разных программах могут быть разные определения одного и того же класса, включая только то, что им нужно.

Например, рассмотрим дополнительную библиотеку для поддержки регулярных выражений в String. В некоторых языках, чтобы функциональные возможности были включены в строки, функциональные возможности должны быть добавлены в Stringпространство имен. Как только это происходит, Stringкласс становится больше, и функции, которым не нужно использовать регулярное выражение, все равно должны «платить» за это увеличением размера библиотеки. По этой причине такие надстройки обычно помещаются в свои собственные пространства имен и объекты. Обратной стороной этого подхода является то, что новые функции больше не являются частью String ; вместо этого он изолирован в собственном наборе функций, которые должны вызываться отдельно. Вместо того myString.parseWith(myPattern), что было бы естественной организацией с точки зрения объектно-ориентированного подхода, используется что-то подобное myPattern.parseString(myString), что эффективно меняет порядок.

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

Более практическое использование интерфейса конструкции заключается в создании государственных и частных версий модуля, то , что другие языки включают как болт на особенность , которая неизменно вызывает проблемы и добавляет синтаксис. В соответствии с Диланом, каждый вызов функции может быть просто помещен в "Частный" интерфейс или "Разработка" и собирать общедоступные функции в Public. В Java или C ++ видимость объекта определяется в коде, а это означает, что для поддержки аналогичного изменения программист будет вынужден полностью переписать определения и не может иметь две версии одновременно.

Классы

Классы в Dylan описывают slots(элементы данных, поля, ivars и т. Д.) Объектов аналогично большинству объектно-ориентированных языков. Весь доступ к слотам осуществляется через методы, как в Smalltalk . Методы получения и установки по умолчанию генерируются автоматически на основе имен слотов. В отличие от большинства других объектно-ориентированных языков, другие методы, применимые к классу, часто определяются вне класса, и поэтому определения классов в Dylan обычно включают только определение хранилища. Например:

define class <window> (<view>)
  slot title :: <string> = "untitled", init-keyword: title:;
  slot position :: <point>, required-init-keyword: position:;
end class;

В этом примере определяется класс " <window>". Синтаксис <class name> используется только по соглашению, чтобы имена классов выделялись - угловые скобки являются просто частью имени класса. Напротив, в некоторых языках принято использовать заглавную первую букву имени класса или префикс имени с помощью C или T (например). <window>наследуется от одного класса, <view>и содержит два слота, titleсодержащих строку для заголовка окна и positionточку XY для угла окна. В этом примере заголовку присвоено значение по умолчанию, а позиции - нет. Необязательный синтаксис init-keyword позволяет программисту указать начальное значение слота при создании экземпляра объекта класса.

В таких языках, как C ++ или Java, класс также определяет свой интерфейс. В этом случае в приведенном выше определении нет явных инструкций, поэтому на обоих языках рассматривается доступ к слотам и методам protected, то есть они могут использоваться только подклассами. Чтобы разрешить несвязанному коду использовать экземпляры окна, они должны быть объявлены public.

В Дилане такие правила видимости считаются не частью кода, а частью системы модуля / интерфейса. Это добавляет значительную гибкость. Например, один интерфейс, использованный на ранней стадии разработки, мог объявлять все общедоступным, тогда как интерфейс, используемый при тестировании и развертывании, мог ограничивать это. В C ++ или Java эти изменения потребуют изменений в исходном коде, поэтому люди не будут этого делать, тогда как в Dylan это совершенно не связанная концепция.

Хотя в этом примере он не используется, Дилан также поддерживает множественное наследование .

Методы и общие функции

В Дилане методы внутренне не связаны с каким-либо конкретным классом; методы можно рассматривать как существующие вне классов. Как и CLOS, Dylan основан на множественной отправке (мультиметоды), где конкретный вызываемый метод выбирается на основе типов всех его аргументов. Во время компиляции нет необходимости знать метод, понимая, что требуемая функция может быть доступна или нет, в зависимости от предпочтений пользователя.

В Java одни и те же методы будут изолированы в определенном классе. Чтобы использовать эту функциональность, программист вынужден импортировать этот класс и явно ссылаться на него для вызова метода. Если этот класс недоступен или неизвестен во время компиляции, приложение просто не будет компилироваться.

В Дилане код изолирован от хранилища в функциях . Многие классы имеют методы, которые вызывают свои собственные функции, благодаря чему они выглядят и ощущаются как большинство других объектно-ориентированных языков. Однако код также может находиться в общих функциях , то есть они не привязаны к определенному классу и могут быть вызваны кем угодно. Связывание конкретной универсальной функции с методом в классе выполняется следующим образом:

define method turn-blue (w :: <window>)
  w.color := $blue;
end method;

Это определение похоже на определение в других языках и, вероятно, будет инкапсулировано внутри <window>класса. Обратите внимание на вызов: = setter, который является синтаксическим сахаром для color-setter($blue, w).

Полезность общих методов становится очевидной, когда вы рассматриваете более «общие» примеры. Например, одной из распространенных функций в большинстве языков является функция to-string, которая возвращает некоторую удобочитаемую форму для объекта. Например, окно может вернуть заголовок и позицию в скобках, а строка вернет сама себя. В Дилане все эти методы можно было собрать в один модуль с именем " to-string", тем самым убрав этот код из определения самого класса. Если конкретный объект не поддерживает a to-string, его можно легко добавить в to-stringмодуль.

Расширяемость

Вся эта концепция может показаться некоторым читателям очень странной. Код для обработки to-stringокна не определен в <window>? Это может не иметь никакого смысла, пока вы не рассмотрите, как Дилан обрабатывает вызов to-string. В большинстве языков , когда программа скомпилирована to-stringдля <window>ищутся и замещаются указателем (более или менее) к методу. В Дилане это происходит при первом запуске программы; выполнения строят таблицу имя-метода / параметры деталей и ищут способы динамически с помощью этой таблицы. Это означает, что функция для определенного метода может располагаться где угодно, а не только в единице времени компиляции. В конце концов, программисту предоставляется значительная гибкость с точки зрения того, где разместить свой код, собирая его по строкам классов, где это необходимо, и по функциональным линиям, где это не так.

Подразумевается, что программист может добавлять функциональные возможности к существующим классам, определяя функции в отдельном файле. Например, вы можете захотеть добавить проверку орфографии ко всем <string>s, что на большинстве языков потребует доступа к исходному коду строкового класса - а такие базовые классы редко выдаются в исходной форме. В Dylan (и других «расширяемых языках») метод проверки орфографии может быть добавлен в spell-checkмодуль, определяя все классы, к которым он может применяться через define methodконструкцию. В этом случае фактическая функциональность может быть определена в одной универсальной функции, которая принимает строку и возвращает ошибки. Когда spell-checkмодуль компилируется в вашу программу, все строки (и другие объекты) получат дополнительную функциональность.

Эппл Дилан

Apple Dylan - это реализация Dylan, произведенная Apple Computer . Первоначально он был разработан для продукта Apple Newton .

Рекомендации

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