Добро пожаловать!

Я Дож, программирование — моё хобби. По мере того, как я осваиваю что-то новое, стараюсь об этом написать пост.
На текущий момент в блоге затронуты следующие темы: vim, free pascal, lisp, forth, m4
Занимаюсь разработкой своего языка под названием DEmbro, подбробней: wiki и svn
Для постов, не связанных с программированием, у меня есть отдельное жж.

Мышь для веселья, клавиатура для боя!

ноября 26, 2015

Анонс фичи: Обобщённые функции, процедуры и методы

Это мой перевод анонса так называемых generic routines. Оригинальный текст письма доступен здесь. Слова «generic routine» я перевожу напрямую как «обобщённая подпрограмма», т.к. пока ещё не знаю какой русский термин приживётся в паскаль-сообществе (возможны ещё варианты функция-дженерик, параметризованная функция или просто дженерик)


Всем привет!

Я рад наконец-то объявить о добавлении обобщённых функций, процедур и методов (вместе назваемых «подпрограммами») во Free Pascal, позволяющих писать типобезопасный код, который можно переиспользовать для многих типов.

Синтаксис:

Синтаксис объявления обобщённых подпрограмм схож с синтаксисом объявления обычнох подпрограмм, и тоже поддерживает классовые методы:

generic [class] (procedure|function) IDENTIFIER<TYPEARGLIST>[(PARAMETERLIST)][: RESULTTYPE]; MODIFIERS;

TYPEARGLIST пишется по тем же правилам, что и соответствующий список в обобщённых типах. Типы-параметры, объявленные в TYPEARGLIST, могут быть использованы в PARAMETERLIST, в RESULTTYPE и, конечно же, в теле подпрограммы.

Обобщённые подпрограммы могут быть перегружены и по TYPEARGLIST, и по PARAMETERLIST.

Для вызова обобщённой подпрограммы используется следующий синтаксис:

specialize IDENTIFIER<TYPELIST>[(PARAMETERS)]

TYPELIST пишется по тем же правилам, что и при специализации обобщённых типов. Если подпрограмма вызывается не из глобального пространства имён, а из типа, переменной, или через имя модуля, то нужно поместить соответствующее выражение перед словом «specialize»:

TYPENAME.specialize IDENTIFIER<TYPELIST>[(PARAMETERS)]
VARIABLE.specialize IDENTIFIER<TYPELIST>[(PARAMETERS)]
UNITNAME.specialize IDENTIFIER<TYPELIST>[(PARAMETERS)]

Вызовы обобщённых подпрограмм считаются обычным выражением, поэтому они могут быть использованы так:

=== начало примера ===

{$mode objfpc}

generic function Add<T>(aLeft, aRight: T): T;
begin
  Result := aLeft + aRight;
end;

begin
  Writeln(specialize Add<String>('Generic ', 'routines') + specialize Add<String>(' with ', 'Free Pascal'));
end.

=== конец примера ===

Совместимость с Delphi:

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

[class] (procedure|function) IDENTIFIER<TYPELIST>[(PARAMETERLIST)][: RETURNTYPE]; MODIFIERS;

Т.е. всего лишь опущено слово «generic». Аналогично и при вызове:

IDENTIFIER<TYPELIST>[(PARAMETERS)]

Из-за того, что нет ключевого слова «specialize», указывающего на специализацию, сложные выражения пока что не работают в Delphi режиме. Поэтому запись результата вызова функции работает хорошо, но с чем-то более сложным вы можете столкнуться с ошибкой компиляции.

Пожалуйста, обратите внимание, что в отличие от Delphi, мы поддерживаем глобальные обобщённые функции/процедуры даже в Delphi режиме.

Ограничения/Планы:

Разработка фичи ещё не окончена, что-то ещё требует серьёзных доработок, а какие-то части ещё совсем не работают. Вот список подобных моментов:

  • поддержка сложных выражений в Delphi режиме (относится также и к специализации типов)
  • поддержка указателей на обобщённые подпрограммы (сейчас это приведёт к ошибке компиляции в лучшем случае, и внутренней ошибке или исключению в худшем)
  • поддержка возвращаемого значения в режимах без поддержки слова «Result»
  • поддержка вложенных обобщённых функций, особенно важен случай обобщённых методов внутри обобщённых классов

Поэтому прошу вас тестировать и сообщать о любых багах в трекер. Вопросы могут быть также заданы здесь в рассылке (и нет, эта фича не будет добавлена в FPC 3.0.0).

С уважением,
Свен


Читать дальше......

сентября 01, 2014

Free Pascal: Трюки с объектами

Введение

Данный пост я решил написать после дискуссии на форуме freepascal.ru, из которой я для себя узнал много всего полезного. За ценные знания большое спасибо Vapaamies, runewalsh и Сергею Горелкину, также вклад в дискуссию внесли zub и stanilar.

В посте будет рассказано о читах разной степени приемлимости, но даже если у вас нет необходимости в их применении, пост поможет глубже понять устройство объектов в паскале. Под объектами здесь и далее подразумеваются типы, объявленные как object, а не class. С class'ом многие рассматриваемые тут задачи решаются легко, т.к. язык поддерживает и указатели на конструкторы, и виртуальные конструкторы, и классовые типы (т.е. class of ...).

Тем не менее, в последнее время я возвращаюсь к истокам и всё чаще использую именно object, т.к. в отличии от class, он (1) может быть создан на стеке или внутри какой-то внешней структуры, не затрачивая времени на аллокацию, что полезно для мелких и короткоживущих объектов, и (2) гораздо легковеснее, не несёт с собой в программу RTTI, что может быть полезно при приступах оптимизаторской паранойи.


Читать дальше......

Пост ненависти к GoogleCL

Недавно захотел опробовать отправку поста в линуксе при помощи GoogleCL. Из консоли, то есть, — потому что посты я набираю исключительно в Vim'е, да ещё и с собственной преобразовалкой Markup'а, и вместо копирования текста в браузер мне проще из консоли отправить пост.

Установил, набрал пример из документации:

google blogger post --tags "GoogleCL, awesome" "Here's a really short post. The next posts will be much longer\!"

Запросили логин и название блога — ввёл. А дальше… впервые в своей жизни увидел w3m — консольный браузер! У меня же нет графической оболочки. Оказывается, чтобы залогиниться в консольной программе, требуется браузер, да не просто браузер, а с поддержкой JavaScript! Т.к. w3m не поддерживает JavaScript, из коробки по крайней мере, я поставил lynx, попытался залогиниться через него, — а в нём не работает нажатие на кнопку «Разрешить» (пишет «ОТКЛЮЧЕННАЯ кнопка посылки формы»).

Ёлки-палки, о чём думали в гугле, когда делали это!? Получается, консольная программа не такая уж и консольная. Как с этим быть, кто знает?


Читать дальше......

августа 31, 2014

Free Pascal: Type Helpers

Это мой перевод анонса так называемых type helpers, сделанного в феврале 2013 года. На мой взгляд, он достаточно хорошо и подробно описывает эту фичу. Оригинальный текст письма доступен здесь.


Приветствую сообщество Free Pascal!

Я рад представить дополнение к хелперам, которое распространяет существующую концепцию хелперов на примитивные типы.

Мотивация

С хелперами для классов и записей появилась возможность расширять классы и записи без их наследования (что всё равно было бы невозможно для записей). К примеру, это позволяет добавлять методы типам из других модулей, на которые вы не можете влиять напрямую, или не можете повлиять на экземпляр (например, используемый в TMemo наследник TStrings). Сейчас логично расширить это также и на другие типы, поддерживаемые Паскалём, но теперь нами движет в большей степени возможность сгруппировать методы вместе для примитивных типов.

Здесь не будет идти речь об использовании в паскале концепции объекта-обёртки в управляемых языках/окружениях, таких как Java и .NET, но всё это можно рассматривать и с этой точки зрения.

Синтаксис

Объявление хелперов для типов выглядит следующим образом:

TYPENAME = type helper[(BASEHELPER)] for EXTENDEDTYPE
   DECLARATIONS
end;

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

Аналогично хелперам для записей, классовые методы ДОЛЖНЫ быть объявлены статичными. (Прим. пер.: т.е. использована директива static.)

Использование

Хелперы для типов активны, если они видимы. Это означает, что либо они должны быть объявлены в том же модуле до использующего их кода, либо они должны быть объявлены в используемом модуле. Как и в случае с хелперами для классов и записей, только один типовой хелпер может быть активен для одного заданного типа и вы должны следить за видимостью, когда используете хелперы (к примеру, в текущем модуле сперва проверяется implementation секция, затем interface (если код в implementation секции) и затем используемые модули просматриваются справа налево и каждый модуль сверху вниз).

В некоторых случаях смысл типа зависит от настроек компилятора, с которыми хелпер был скомпилирован. К примеру, тип Integer может означать либо ShortInt, либо LongInt в зависимости от текущего режима (fpc/tp и objfpc/delphi соответственно) и тип String отличается в зависимости от переключателей {$H+/-} и {$modeswitch unicodestring}. Это нужно помнить при использовании их в «generic» типах. Другой специфичный случай — тип Extended на платформах, которые не поддерживают этот тип (и поэтому могут быть определены как Double). Кроме того, тип, объявленный как «NewType = type OldType», считается полностью независимым типом, к примеру в случае перегрузки операторов.

Если хелпер для типа находится в области видимости, вы можете без проблем вызывать его методы и свойства как будто вы работаете с классами или записями. Давайте предположим, что у нас есть хелпер с методом «ToString: String» для типа LongInt в области видимости, тогда выглядеть это будет как-то так:

var
    i: LongInt;
begin
    Writeln(i.ToString);
end.

Кроме вызова типовых хелперов на переменных, их можно также вызвать на константах, но нужно позаботиться о том, что будет использован корректный тип. К примеру, константа «200» будет иметь типа «Byte», тогда как «20» — тип «SmallInt». Кроме того, тип строковых констант зависит от текущего используемого режима (в особеноости от {$H+/-} и {$modeswitch unicodestring}) и содержимого строки. К примеру, в случае "{$mode objfpc}{$H+}" строка, содержащая юникодные символы, будет рассматриваться как константа типа UnicodeString и поэтому только хелперы для UnicodeString будут применены.

Для следующего примера предположим, что хелпер из предыдущего примера опять находится в области видимости:

begin
   Writeln($12345678.ToString);
end.

Также допустимы указатели (к примеру, "@i") (тип: Pointer) и встроенные константы: "True" (тип: Boolean), "False" (тип: Boolean) и "Nil" (тип: Pointer). Пожалуйста, обратите внимание, что в случае типизированных указателей будет использован нетипизированный указатель, потому что соответствующее имя типа не может быть доступно в текущем модуле (а значит, хелпер не может быть найден). Константы, которые не могут быть использованы с типовыми хелперами — множества и конструкторы массивов.

Классовые методы (и свойства) могут быть применены не только к переменным и константам, но и к самим типам:

type
   TLongIntHelper = type helper for LongInt
     class procedure Test; static;
   end;

class procedure TLongIntHelper.Test;
begin
   Writeln('Test');
end;

var
   i: LongInt;
begin
   i.Test;
   $12345678.Test;
   LongInt.Test;
end.

Поддерживаемые типы

Имеются ограничения на типы, которые могут быть расширены. Любой примитивный тип может быть расширен, за исключением:

  • файловых типов (TextFile, file of ...)
  • процедурных переменных

Конечно, также запрещены записи, классы, Objective C классы, C++ классы, объекты и интерфейсы.

Если смотреть с другой стороны, то это значит, что следующие типы разрешены:

  • порядковые типы
  • сроковые типы (включая символьные типы)
  • множества и перечислимые типы
  • массивы
  • булевские типы
  • Variant
  • типы чисел с плавающей точкой
  • указатели

Совместимость с Delphi

Эта возможность введена в Delphi XE3, но вместо использования более логичного синтаксиса «type helper» была добавлена поддержка для примитивных типов «record helper». Поэтому для поддержания совместимости с Delphi такой синтаксис также используется в Delphi режиме. Кроме того, в не Delphi режимах поддерживается наследование для типовых хелперов.

Будущее развитие

  • Добавить поддержку для большего числа типов, особенно для интерфейсов и объектов. Они могут быть добавлены либо как классовые хелперы, либо как «object helper» и «interface helper» (т.к. объекты и интерфейсы поддерживают наследование правил видимостей, внутри они напоминают хелперы для классов больше, чем хелперы для записей/типов).
  • Позволить нескольким хелперам быть активными для одного типа в одно и то же время. Это одно из основных ограничений текущей реализации хелперов. Для этого нужно продумать соответствующие правила поиска, а возможность добавить как modeswitch (быть может, по умолчанию включив её в objfpc).
  • Добавить поддержку хелперов в JVM версии. Наиболее разумным подходом в реализации этого кажется передавать переменную «Self» как дополнительный параметр и рассматривать методы как статичные (как это сделано в .NET для методов в хелперах).

С уважением,
Свен


Читать дальше......

января 11, 2014

DEmbro: что с ним было в 2013

Хочется вкратце рассказать о том, в каком состоянии сейчас находится DEmbro и что было сделано за прошедший 2013 год.

Начну с некоторых проблем, с которыми я столкнулся при разработке. Одна из них, как ни странно, — компиляция. Для сборки dembro использовалась довольно сложная система, которая использовала M4 для препроцессинга команд на специальном языке, описывающем встроенные команды, с последующей генерацией кода, заголовков, документации и т.д. Эта система сборки была написана плохо, не учитывала многих зависимостей (и потому практически при каждом запуске требовала полной перекомпиляции), засоряла всё лишними файлами, частенько ломалась на какой-нибудь из платформ (Windows/Linux), в общем требовала полного переосмысления и переработки.

Сам M4 оказался не так хорош на практике. Необходимость постоянно следить за вложенностью цитат при активном использовании кода, сложности с лишними пробелами и переносами строк, коллизии синтаксиса M4 с программой делают почти непригодной M4 для чего-то сложнее, чем просто макросы. Поэтому было принято решение полностью отказаться от M4 как языка обработки командных файлов DEmbro и почти отказаться от использования в программах на паскале (но не полностью, иногда макросы мне всё же нужны). В частности, я закрываю разработку своего побочного проекта metapascal.

Ещё одна проблема — моё паскальное наследие. Пришло понимание, что, даже несмотря на то, что на DEmbro я успешно написал две игры и свой HTTP-сервер (который уже полтора года используется), полностью перейти на него удастся не так быстро, как хотелось бы. Как следствие, мне захотелось привести свои модули на паскале в порядок, а это не так-то просто — в моих разных проектах модули в чём-то отличаются и потому не совместимы друг с другом, от этого тормозится параллельное развитие нескольких проектов. Код самого DEmbro плох и требует написания некоторых фундаментальных вещей для дальнейшего развития, на данном этапе дело практически зашло в тупик.

Наконец, были проблемы с тестированием. При разработке DEmbro добавление фичи может сломать десять других как нечего делать, и уследить за этим вручную очень трудно. Требовалось регрессионное тестирование.  И хоть модуль для этого датирован аж июнем 2011 года, тесты для него практически не написаны, на регулярной основе запускать их не представлялось возможным.

Мутным текстом выше я обозначил проблемы, теперь же не менее мутным текстом опишу как я эти проблемы решил.

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

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

Я долго думал чем заменить M4 при обработке языка команд. Рассматривал много вариантов, но в конце концов остановился на том, чтобы написать этот обработчик на самом DEmbro. Плюс очевиден: DEmbro, как и большинство форт-языков, предназначен для создания проблемно-ориентированных языков, и поэтому написание такого обработчика занимает пару часов времени и 50 строк кода. Минус: для использования этого обработчика нужен уже скомпилированный DEmbro, что усложнаяет развёртывание на новой платформе, но препроцессинг можно сделать и на другой платформе, и потом просто перенести сгенерированные файлики, поэтому этот минус не так страшен.

Под этот новый обработчик нужно переписать все командные файлы, этого я до сих пор не сделал (их много), поэтому уже почти год команды не перегенерировались. Можно даже сказать, что DEmbro более года находится в некомпилирующемся состоянии. Но переписывание команд планируется осуществить в ближайшие несколько недель.

Свои библиотеки на паскале приведены в порядок, структуризированы, и готовы к развитию. Я уже начал использовать новые фичи из нестабильного fpc 2.7.1, о которых может быть напишу позже.

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

О том, что с DEmbro планируется в дальнейшем, какие глобальные решения были приняты, я напишу позже.


Читать дальше......

августа 11, 2012

DEmbro портирован в FreeBSD

[doj@korica ~/dembro/trunk/release]$ ./de
Loaded default system file
!  Runtime(, 0, 0): cannot open file 'docs/rus/all.utf8.de'
DEmbro v0.11 built Sat Aug 11 01:30 2012
Type "quit" to exit
dembro> ." Hello FreeBSD!!!!!!!!!!!!!!!!!1111111111111111"
Hello FreeBSD!!!!!!!!!!!!!!!!!1111111111111111 ok
dembro>


Благополучно скомпилировал и запустил DEmbro в FreeBSD. Для этого потребовалось заменить в некоторых местах IFDEF LINUX на IFDEF LINUX_or_BSD, подправить вызов парочки утилит и собрать свежий Free Pascal с свна (в пакете fpc для FreeBSD не работает модуль DynLib).

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


Читать дальше......

августа 10, 2012

DEmbro v0.11 -> v0.12

Планируется серьёзное переписывание ядра и системы команд DEmbro, а именно

  1. Расширенные возможности работы с шитым кодом: несколько отдельных буферов, возможность стирать часть кода.
  2. Расширенные возможности работы со словарём: возможность менять поведение словаря в некоторых случаях (например, когда происходит создание слова с именем, которое уже есть в словаре: сгенерировать исключение, создать новое, заменить старое, сделать что-то ещё), возможность удалять созданные ранее команды, поддержка механизма локальных слов.
  3. Упразднить универсальный стек W, который может работать с любым типом данных, до стека, умеющего работать только с ячейками. Добавить команды по работе с byte, word, dword в памяти по указателям.
  4. Стабилизировать систему команд для чисел с плавающей точкой.
  5. Вынести команды по работе со стеками R и L, унифицировать хранение traceback данных (точки возврата из команд) в R, унифицировать работу с исключениями.
  6. Пронести работу с исключениями в ядро, вынести возможность их обработки вне de32.dll/libde32.so, без «undefined behavior» как сейчас.
  7. Отщепить от «дембро-машины» так называемое «дембро-состояние», сделать возможность одной дембро-машине иметь несколько дембро-состояний. Это нужно для реализации многопоточности: сейчас все стеки и данные привязаны к глобальной дембро-машине и потому ни о какой многопоточности не может быть и речи.
  8. Собственно, реализовать многопоточность.
  9. Перевести основную часть функций по работе со строками и исходным кодом на «классические фортовские строки», т.е. на пару ячеек: размер строки и указатель на начало строки. В DEmbro сейчас основным типом строк является str — строки со счётчиком ссылок, но во многих случаях можно обойтись без них, а работают они медленно.
  10. Унифицировать шитый код, написать нормальную дампилку, может быть добавить новый «меташитый код». :)
  11. Исправить устаревшие названия на новые.
В связи с этим, готовлюсь повысить версию до v0.12. Сейчас выбираю стабильную ревизию, чтобы выделить её в отдельный бранч на свне.


Читать дальше......

Постоянные читатели

Обо мне

Моя фотография
Мой e-mail: vitek_03(at)mail(dot)ru