FPC, Lazarus зачем они Вам?
Модератор: Модераторы
Это религия и жизнь. Во всех понятиях!
Использую FPC в своих хобби-проектах, со временем всё больше разочаровываюсь в компиляторе и сейчас кроме как словами «по инерции» аргументировать выбор именно его не могу.
Дож писал(а):всё больше разочаровываюсь в компиляторе и сейчас кроме как словами «по инерции» аргументировать выбор именно его не могу.
А поподробнее? Сбоев компилятор не даёт. Качеством компоновки - можно управлять. Непонятно: Что именно Вас разочаровывает?
Что именно Вас разочаровывает?
Неортогональность фичей (выливающаяся в вездесущую кривизну и грабли), инертное мышление комьюнити («geniric'и? нафиг generic'и, их придумал дьявол!»), приоритеты разработчиков.
Какой аспект развернуть?
Неортогональность фичей и выливающиеся кривизну и грабли, пожалуйста
Остальное известно.
Остальное известно.
Могу выделить целый класс проблем с перегрузкой функций и видимостью идентификаторов в разных модулях.
Тут пример как компилятор не справляется с выбором правильной функции
viewtopic.php?f=1&t=10457#p87548
благодаря разной неявной магии с приведением типов друг к другу можно напороться на совершенно прекрасные ошибки, потерю битов и прочее, пример:
http://lists.freepascal.org/pipermail/f ... 36005.html
Если я хочу сделать много глобальных функций Max, Intersect, Sort, IfThen и т.д., и для разных типов, разнесённых по разным модулям, то у меня ничего не выйдет — ОПРОВЕРГНУТО НИЖЕ, потому что функция из одного модуля полностью закроет функцию другого модуля с таким же названием. А неймспейсы и конструкции вида UnitName.Max подрывают идею перегруженных функций, к тому же with UnitName do не работает.
Но, сюрприз, это всё не относится к перегрузке операторов! Операторы могут быть перегружены, разнесены по разным модулям и они не перекроют объявления друг друга.
По ортогональности фичей: для примера возьмём фичу из 3.0
http://wiki.freepascal.org/FPC_New_Feat ... pe_helpers
Перевод: http://keyfighter.blogspot.ru/2014/08/blog-post.html
Типа круто, можно расширять базовые типы. Но
1. Для одного типа всегда виден только один хелпер (самый последний), опять эти вездесущие конфликты объявлений.[/*]
2. Для class'а хелперы есть, для record'а хелперы есть, для примитивных типов появилось. А для object'а где?[/*]
И я не удивлюсь, если ещё какие-нибудь грабли есть, если начать пользоваться хелперами на практике.
Давайте окунёмся в прекрасный мир дженериков, которые полируются уже не первый год. На самом деле, я ими пользуюсь так редко, что на данный момент уже даже не помню всех проблем, с которыми сталкивался, не в курсе какие на данный момент уже решены, а какие ещё нет, так что может быть моё негативное отношение к реализации дженериков уже неактуально.
Например, вы знаете как написать дженерик TVector<TScalar> и перегрузить для него операторы сложения и умножения? (Должно работать для TScalar=Single,Double,LongInt).
Допустим, я хочу написать один дженерик с красивым именем TMap<TKey, TValue>, которым было бы удобно пользоваться для всего, и для примитивных типов, и для объектов, и для классов, как мне это осуществить? Какой тип должен возвращать метод Get(const Key: TKey), например? (Напомню, что такой метод может быть всего один в классе, т.к. перегрузки по возвращаемому значению не бывает.)
Почему в следующем коде у меня ошибка? По логике ведь всё ок, если я буду специализировать T обычными типами.
Из старых фичей тоже встречаются несоответствия. Например, почему в строго типизированном языке программирования, коим паскаль позиционируется, оператор @ возвращает тип Pointer, который можно передать в функцию как любой типизированный аргумент? — ЭТО ПОВЕДЕНИЕ РЕГУЛИРУЕТСЯ ОПЦИЕЙ, СМ. НИЖЕ
Тут пример как компилятор не справляется с выбором правильной функции
viewtopic.php?f=1&t=10457#p87548
благодаря разной неявной магии с приведением типов друг к другу можно напороться на совершенно прекрасные ошибки, потерю битов и прочее, пример:
http://lists.freepascal.org/pipermail/f ... 36005.html
Если я хочу сделать много глобальных функций Max, Intersect, Sort, IfThen и т.д., и для разных типов, разнесённых по разным модулям, то у меня ничего не выйдет — ОПРОВЕРГНУТО НИЖЕ, потому что функция из одного модуля полностью закроет функцию другого модуля с таким же названием. А неймспейсы и конструкции вида UnitName.Max подрывают идею перегруженных функций, к тому же with UnitName do не работает.
Но, сюрприз, это всё не относится к перегрузке операторов! Операторы могут быть перегружены, разнесены по разным модулям и они не перекроют объявления друг друга.
По ортогональности фичей: для примера возьмём фичу из 3.0
http://wiki.freepascal.org/FPC_New_Feat ... pe_helpers
Перевод: http://keyfighter.blogspot.ru/2014/08/blog-post.html
Типа круто, можно расширять базовые типы. Но
1. Для одного типа всегда виден только один хелпер (самый последний), опять эти вездесущие конфликты объявлений.[/*]
2. Для class'а хелперы есть, для record'а хелперы есть, для примитивных типов появилось. А для object'а где?[/*]
И я не удивлюсь, если ещё какие-нибудь грабли есть, если начать пользоваться хелперами на практике.
Давайте окунёмся в прекрасный мир дженериков, которые полируются уже не первый год. На самом деле, я ими пользуюсь так редко, что на данный момент уже даже не помню всех проблем, с которыми сталкивался, не в курсе какие на данный момент уже решены, а какие ещё нет, так что может быть моё негативное отношение к реализации дженериков уже неактуально.
Например, вы знаете как написать дженерик TVector<TScalar> и перегрузить для него операторы сложения и умножения? (Должно работать для TScalar=Single,Double,LongInt).
Допустим, я хочу написать один дженерик с красивым именем TMap<TKey, TValue>, которым было бы удобно пользоваться для всего, и для примитивных типов, и для объектов, и для классов, как мне это осуществить? Какой тип должен возвращать метод Get(const Key: TKey), например? (Напомню, что такой метод может быть всего один в классе, т.к. перегрузки по возвращаемому значению не бывает.)
Почему в следующем коде у меня ошибка? По логике ведь всё ок, если я буду специализировать T обычными типами.
Код: Выделить всё
{$MODE OBJFPC}
type
generic G<T> = record
case l: LongInt of
0: (x: T;)
end;
begin
end.
gen.pas(5,11) Error: Type parameters may require initialization/finalization - cannot be used in variant records
Из старых фичей тоже встречаются несоответствия. Например, почему в строго типизированном языке программирования, коим паскаль позиционируется, оператор @ возвращает тип Pointer, который можно передать в функцию как любой типизированный аргумент? — ЭТО ПОВЕДЕНИЕ РЕГУЛИРУЕТСЯ ОПЦИЕЙ, СМ. НИЖЕ
Последний раз редактировалось Дож 03.10.2015 13:19:54, всего редактировалось 1 раз.
Дож писал(а):По ортогональности фичей: для примера возьмём фичу из 3.0...Типа круто, можно расширять базовые типы. Но
1. Для одного типа всегда виден только один хелпер (самый последний), опять эти вездесущие конфликты объявлений.[/*]
2. Для class'а хелперы есть, для record'а хелперы есть, для примитивных типов появилось. А для object'а где?[/*]
И я не удивлюсь, если ещё какие-нибудь грабли есть, если начать пользоваться хелперами на практике.
Helper-ы добавляются под нажимом совместимости с Delphi. Соответсвтенно и работают хелперы, как и в делфи.
Ну и object-ы тоже не обзавелись хелперами, т.к. в Delphi object-ы считаются устаревшейже технологией... если они вообще там ещё остались.
И потом, если с хелперами много граблей, какой смысл их вообще прикручивать к объектам? (хотя обещали!)
Хелперы добавили не из-за технической необходимости, а потому что "в Делфи есть, и наш свеженаписанный код, больше под FPC не копилируется. Добавьт фичу пожалуйста"
Дож писал(а):Например, почему в строго типизированном языке программирования, коим паскаль позиционируется, оператор @ возвращает тип Pointer, который можно передать в функцию как любой типизированный аргумент?
http://www.freepascal.org/docs-html/ref/refse74.html
The @ operator returns a typed pointer if the $T switch is on. If the $T switch is off then the address operator returns an untyped pointer, which is assigment compatible with all pointer types. The type of the pointer is ^T, where T is the type of the variable reference.
http://www.freepascal.org/docs-html/3.0 ... gsu75.html
In the {$T+} or {$TYPEDADDRESS ON} state, the @ operator, when applied to a variable, returns a result of type ^T, if the type of the variable is T. In the {$T-} state, the result is always an untyped pointer, which is assignment compatible with all other pointer types.
И потом, если с хелперами много граблей, какой смысл их вообще прикручивать к объектам?
Сами по себе хелперы довольно полезная штука, помогают улучшить ту самую ортагонализацию возможностей, если их довести до ума.
bormant, большое спасибо, беру на вооружение! :)
Дож писал(а):Сами по себе хелперы довольно полезная штука, помогают улучшить ту самую ортагонализацию возможностей, если их довести до ума.
я забыл сказать, что ортогональные изменения обычно связаны с догонялками делфи
Дож писал(а):Если я хочу сделать много глобальных функций Max, Intersect, Sort, IfThen и т.д., и для разных типов, разнесённых по разным модулям, то у меня ничего не выйдет, потому что функция из одного модуля полностью закроет функцию другого модуля с таким же названием
Я чего-то не понял, а перегрузка не решает?
Дож писал(а):Для одного типа всегда виден только один хелпер (самый последний), опять эти вездесущие конфликты объявлений.
В отлиции от дельфей, тут хелперы можно наследовать:
Код: Выделить всё
program Project1;
{$mode objfpc}
{$modeswitch typehelpers}
type
{ inthelper }
inthelper = type helper for integer
procedure test;
end;
{ inthelper2 }
inthelper2 = type helper (inthelper) for integer
procedure test2;
end;
{ inthelper }
procedure inthelper.test;
begin
writeln('test');
end;
{ inthelper2 }
procedure inthelper2.test2;
begin
writeln('test2');
end;
var i : Integer;
begin
i.test;
i.test2;
readln;
end.
А судя по дельфийскому хелпу, у хелперов подразумевалась и возможность множественного наследования. Не понятно, почему не сделали более человечный вариант по мотивам D:
Код: Выделить всё
function ToString(AValue : Integer) : String; Helper;
...
var i : Integer;
integer.ToString(i);
i.ToString;
Дож писал(а):ли я хочу сделать много глобальных функций Max, Intersect, Sort, IfThen и т.д., и для разных типов, разнесённых по разным модулям, то у меня ничего не выйдет, потому что функция из одного модуля полностью закроет функцию другого модуля с таким же названием. А неймспейсы и конструкции вида UnitName.Max подрывают идею перегруженных функций, к тому же with UnitName do не работает.
ну хз-хз. вот смотри пример.
dodge.pas
Код: Выделить всё
{$ifdef fpc}{$mode delphi}{$endif}
uses
maxint, maxstr;
begin
writeln(max('aaa','bbb'));
writeln(max(5,6));
end.
maxstr.pas
Код: Выделить всё
unit maxstr;
interface
{$ifdef fpc}{$mode delphi}{$h+}{$endif}
function Max(const a,b: string): string; overload;
implementation
function Max(const a,b: string): string; overload;
begin
if a>b then Result:=a
else Result:=b;
end;
end.
maxint.pas
Код: Выделить всё
unit maxint;
interface
{$ifdef fpc}{$mode delphi}{$h+}{$endif}
function Max(const a,b: Integer): Integer; overload;
implementation
function Max(const a,b: Integer): Integer; overload;
begin
if a>b then Result:=a
else Result:=b;
end;
end.
компилится и работает.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
скалогрыз писал(а):я забыл сказать, что ортогональные изменения обычно связаны с догонялками делфи
Они, скорее, связаны с качеством проработки фич. В собственном-то диалекте никаких догонялок не требуется.
kazalex писал(а):Они, скорее, связаны с качеством проработки фич. В собственном-то диалекте никаких догонялок не требуется.
имхо, проблема в том, что фичу добавить можно в язык, а вот убрать сложнее.
хотя typeswitch-и помогаеют. Каждый делает свой набор фич по вкусу.
скалогрыз писал(а):имхо, проблема в том, что фичу добавить можно в язык, а вот убрать сложнее.
Я же о другом. Если фичу таки решили добавить, то прорабатывать применимость и варианты использования нужно от и до. А то полу-работающие полу-фичи какие-то получаются
