Давно пишу на Delphi XE8, и тут обнаружилась неприятная проблема – баг компилятора из-за которого программа иногда не компилируется (ошибка F2084 Internal error: C2359). Хорошо бы перейти на Delphi поновее, или может быть Lazarus. Хочу спросить, какие фичи есть в новых версиях, и нет ли в них частности такого:
1) Очень не хватает возможности назвать то, на что ссылается блок with. Т.е. нужно обозначение вроде this или it, аналогичное self для класса. Это не только моя мысль, я видел такой запрос в инете, так что можно надеяться идея дошла до разработчиков;
2) Хорошо что в XE появились процедуры и функции к рекордам, т.е. инкапсуляция для рекордов, а нельзя ли ещё наследование (понятно что нельзя полиморфизм, а инкапсуляция и наследование вполне);
3) Хотелось бы иметь быстрые классы без лишней вспомогательной информации. Я имею в виду, что классы включают в себя таблицу виртуальных методов, информацию о классе вроде его названия и пр., поэтому не очень хочется превращать в класс разную мелочь (трата ресурсов компьютера). Может быть, то что я предлагаю можно реализовать только за счёт отказа от полиморфизма, ну пусть хотя бы так. В принципе сейчас можно для этого заменять классы указателями на рекорды, но опять же не хватает наследования;
4) Как там в новых Delphi с Firemonkey и поддержкой Linux, Mac, Android? Они хотя бы скомпилировали Delphi на FMX?
5) Метапрограммирование, макросы – есть сейчас что-то такое?
6) Я давно предлагаю поэтапную компиляцию: сначала превратить исходник в более быстрый (размноженный), например в котором инлайновые функции заинлайнились и их удобнее отлаживать. Вряд ли это кто-то сделал, но вдруг...
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Здравствуйте, Khimik, Вы писали:
K> 1) Очень не хватает возможности назвать то, на что ссылается блок with. Т.е. нужно обозначение вроде this или it, аналогичное self для класса. Это не только моя мысль, я видел такой запрос в инете, так что можно надеяться идея дошла до разработчиков;
Такого нет. Есть разговоры об отказе от with вообще.
K> 2) Хорошо что в XE появились процедуры и функции к рекордам, т.е. инкапсуляция для рекордов, а нельзя ли ещё наследование (понятно что нельзя полиморфизм, а инкапсуляция и наследование вполне);
Методы у записей появилсиь задолго до XE, в 2006, кажется. Записи с наследованием называются object, но это легаси, хотя и рабочее.
K> 3) Хотелось бы иметь быстрые классы без лишней вспомогательной информации. Я имею в виду, что классы включают в себя таблицу виртуальных методов, информацию о классе вроде его названия и пр., поэтому не очень хочется превращать в класс разную мелочь (трата ресурсов компьютера). Может быть, то что я предлагаю можно реализовать только за счёт отказа от полиморфизма, ну пусть хотя бы так. В принципе сейчас можно для этого заменять классы указателями на рекорды, но опять же не хватает наследования;
TMyObj = object
end;
K> 4) Как там в новых Delphi с Firemonkey и поддержкой Linux, Mac, Android? Они хотя бы скомпилировали Delphi на FMX?
Все платформы поддерживаются, Delphi на FMX не переписывали.
K> 5) Метапрограммирование, макросы – есть сейчас что-то такое?
Здравствуйте, rudzuk, Вы писали:
K>> 2) Хорошо что в XE появились процедуры и функции к рекордам, т.е. инкапсуляция для рекордов, а нельзя ли ещё наследование (понятно что нельзя полиморфизм, а инкапсуляция и наследование вполне);
R>Методы у записей появилсиь задолго до XE, в 2006, кажется. Записи с наследованием называются object, но это легаси, хотя и рабочее.
А чем object-ы отличаются от record-ов? зачем было вводить инкапсуляцию у рекордов, если она уже есть у obtect-ов?
K>> 5) Метапрограммирование, макросы – есть сейчас что-то такое?
R>Во Free Pascal есть.
Т.е. у Lazarus? Значит если в Lazarus допилят отдалку — будет круто и лучше Delphi?
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Здравствуйте, Khimik, Вы писали:
K> R>Методы у записей появилсиь задолго до XE, в 2006, кажется. Записи с наследованием называются object, но это легаси, хотя и рабочее.
K> А чем object-ы отличаются от record-ов? зачем было вводить инкапсуляцию у рекордов, если она уже есть у obtect-ов?
У object могут быть виртуальные методы, у записей нет. Записи поддерживают перегрузку операторов, кастомную инициализацию/финализацию, object нет (во Free Pascal ожно перегрузить операторы и для них). Object — это отголосок ООП из Turbo Pascal. В Delphi изменили объектную модель, он стала ссылочной (плюс изменился принцип конструирования объектов), поэтому object перестали развиваться. Ну и одновременно с этим объявили object legacy, а после стали развивать записи.
K> K>> 5) Метапрограммирование, макросы – есть сейчас что-то такое?
K> R>Во Free Pascal есть.
K> Т.е. у Lazarus? Значит если в Lazarus допилят отдалку — будет круто и лучше Delphi?
Он уже давно лучше Delphi. Во Free Pascal куча клевых штук, которых в Delphi нет.
Здравствуйте, rudzuk, Вы писали:
R>Он уже давно лучше Delphi.
Серьёзно?
Я пробовал им пользоваться и забил; по-моему одна отладка там настолько хуже дельфовой, что уже это перекрывает все плюсы. И это очень грустно конечно; я ещё слышал что Embarcadero (или кто там сейчас владеет Delphi) платит разработчикам Лазаруса за то, чтобы те не делали действительно мощные фичи, которые могли бы убить Delphi.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Здравствуйте, Khimik, Вы писали:
K> R>Он уже давно лучше Delphi.
K> Серьёзно?
Серьезно. Самые востребованные у разработчиков фичи (судя по голосованию в старом багтрекере), такие как: перегрузка инициализации/финализации/оператора копирования для записей и мультихелперы, во Free Pascal появились раньше чем в Delphi, где мультихелперов до сих пор нет. Не говоря уже о том, что во Free Pascal дженерики являются полноценными шаблонами.
K> Я пробовал им пользоваться и забил; по-моему одна отладка там настолько хуже дельфовой, что уже это перекрывает все плюсы. И это очень грустно конечно;
Меня отладчик вполне устраивает В новой версии они, как раз, работают над улучшением отладчика (интегрируют собственный).
K> я ещё слышал что Embarcadero (или кто там сейчас владеет Delphi) платит разработчикам Лазаруса за то, чтобы те не делали действительно мощные фичи, которые могли бы убить Delphi.
Здравствуйте, rudzuk, Вы писали:
K>> я ещё слышал что Embarcadero (или кто там сейчас владеет Delphi) платит разработчикам Лазаруса за то, чтобы те не делали действительно мощные фичи, которые могли бы убить Delphi.
R>Какие, например? Я о таком ничего не слышал.
Я говорю что слышал, сам не в курсе, полагаю это всё та же доработка отладчика.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Жаль что я не знал раньше про object-ы, наверно они могут быть довольно удобными, особенно если поддерживают дженерики. Только хотелось бы убедиться — они точно ничем не хуже record-ов? Можно делать object из всякой мелочи вроде комплексных чисел, но боясь дополнительных тормозов или трат памяти?
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Здравствуйте, Khimik, Вы писали:
K> Жаль что я не знал раньше про object-ы, наверно они могут быть довольно удобными, особенно если поддерживают дженерики.
В Delphi они дженерики не поддерживают, во Free Pascal поддерживают.
K> Только хотелось бы убедиться — они точно ничем не хуже record-ов? Можно делать object из всякой мелочи вроде комплексных чисел, но боясь дополнительных тормозов или трат памяти?
Если требуется наследоание — они лучше, если не требутся — смысла в них нет. С точки зрения эффективности они ни чем не отличаются от записей в одинаковых сценариях использования.
Здравствуйте, Khimik, Вы писали:
K>Давно пишу на Delphi XE8, и тут обнаружилась неприятная проблема – баг компилятора из-за которого программа иногда не компилируется (ошибка F2084 Internal error: C2359). Хорошо бы перейти на Delphi поновее, или может быть Lazarus. Хочу спросить, какие фичи есть в новых версиях, и нет ли в них частности такого:
Хотя это и Internal Error, это скорее всего связано или с тем что не Delphi не может переварить или твой код, или код используемых компонентов.
Маловероятно что переход на новую версию решит проблему, с ней надо разбираться.
Просто Delphi не может показать место где это происходит. Обычно такие места можно найти методом исключения и по косвенным признакам.
Единственный баг дельфи который ходит из версии к версии и портит нашей команде кровь — это зависание текстового поиска на больших проектах.
K>1) Очень не хватает возможности назвать то, на что ссылается блок with. Т.е. нужно обозначение вроде this или it, аналогичное self для класса. Это не только моя мысль, я видел такой запрос в инете, так что можно надеяться идея дошла до разработчиков;
Избавиться от with уже предлагали, я за.
То что ты хочешь похоже на присвоение во временную локальную переменную указателя на ту часть структуры, на которую хочешь ссылаться.
Это хороший подход, который был всегда.
В новых версиях можно объявлять такую переменную по месту.
Но я за объявление такой переменной по старинке в блоке var, читаемость лучше, нагрузка на компилятор меньше.
K>2) Хорошо что в XE появились процедуры и функции к рекордам, т.е. инкапсуляция для рекордов, а нельзя ли ещё наследование (понятно что нельзя полиморфизм, а инкапсуляция и наследование вполне); K>3) Хотелось бы иметь быстрые классы без лишней вспомогательной информации. Я имею в виду, что классы включают в себя таблицу виртуальных методов, информацию о классе вроде его названия и пр., поэтому не очень хочется превращать в класс разную мелочь (трата ресурсов компьютера). Может быть, то что я предлагаю можно реализовать только за счёт отказа от полиморфизма, ну пусть хотя бы так. В принципе сейчас можно для этого заменять классы указателями на рекорды, но опять же не хватает наследования;
Если действительно нужно экономить память,
то скорее всего мы имеем дело с большими массивами однородных объектов
и я сейчас придерживаюсь другой парадигмы:
проектирую класс не для айтема, а для коллекции айтемов, к айтемам обращаюсь по индексу, данные в коллекции организуются кастомно,
в зависимости от размеров полей и предполагаемой частоты их заполнения.
Называется паттерн Flyweight (Легковес).
Да более трудоемко писать, но во многих случаях можно сэкономить памяти на порядок — два.
Наследование в таком подходе тоже можно реализовать.
K>4) Как там в новых Delphi с Firemonkey и поддержкой Linux, Mac, Android?
Собираем сейчас относительно несложные для нас GUI приложения на несколько сот модулей под Linux на FMXLinux,
он есть в магазине приложений. Одно и тоже приложение у нас собирается и под VCL (Windows) и под FMX (Windows, Linux), код формочек одинаковый, ресурсы формочек разные, дефайнов получается немного.
K>Они хотя бы скомпилировали Delphi на FMX?
Кому это нужно?
Нету вроде даже 64-битного компилятора под винду (который собирает как 64 битное приложение).
А есть ли вообще хорошие производительные текстовые редакторы под FMX?
K>5) Метапрограммирование, макросы – есть сейчас что-то такое?
Не очень себе представляю зачем это сейчас нужно в Delphi и это нельзя решить другими способами, но может ошибаюсь, кто знает приведите пример.
K>6) Я давно предлагаю поэтапную компиляцию: сначала превратить исходник в более быстрый (размноженный), например в котором инлайновые функции заинлайнились и их удобнее отлаживать. Вряд ли это кто-то сделал, но вдруг...
При твоем подходе к "оптимизации" инлайны это мертвому припарка.
S>При твоем подходе к "оптимизации" инлайны это мертвому припарка.
Можно вопрос. Почему вы так и не запустили тест, чтобы проверить, правда ли моя сортировка с секциями быстрее стандартной сортировки?
Боитесь разозлить форумных участников, политическая позиция которых на форуме является доминантной?
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Здравствуйте, swame, Вы писали:
S>Хотя это и Internal Error, это скорее всего связано или с тем что не Delphi не может переварить или твой код, или код используемых компонентов.
Помню, в детстве VS6 начала выдавать при сборке проекта Internal Error после того, как я протёр материнку от пыли влажной тряпочкой. (Потом перестала).
Здравствуйте, Khimik, Вы писали:
K>Здравствуйте, swame, Вы писали:
S>>При твоем подходе к "оптимизации" инлайны это мертвому припарка.
K>Можно вопрос. Почему вы так и не запустили тест, чтобы проверить, правда ли моя сортировка с секциями быстрее стандартной сортировки? K>Боитесь разозлить форумных участников, политическая позиция которых на форуме является доминантной?
Я написал более корректные тесты, раза 3 приводил твои алгоритмы к компилируемому виду,
указывая тебе на проблемы:
1. алгоритмы не работали на массивах с повторяющимися значениями,
мне пришлось специально изготавливать для тестов массивы с неповторяющимися значениями.
2. Они занимали на 1-2 порядка больше памяти, чем стандартные, такие алгортмы мне неинтересны.
Больше я тестировать такое не хочу, надоело. если хочещь изготовь отдельный тестовый проект, чтобы я собрал и проверил,
чтобы компилился без установки каких-то компонент.
К тесту приложи цифры тестирования:
1. Сравнение по скорости и занимаемой памяти с алгоритмом ChatGPT БЕЗ КОПИРОВАНИЯ на массивах 1 тыс, 1 млн, 1 млрд. записей.
Здравствуйте, Alekzander, Вы писали:
A>Здравствуйте, swame, Вы писали:
S>>Хотя это и Internal Error, это скорее всего связано или с тем что не Delphi не может переварить или твой код, или код используемых компонентов.
A>Помню, в детстве VS6 начала выдавать при сборке проекта Internal Error после того, как я протёр материнку от пыли влажной тряпочкой. (Потом перестала).
A>Может, аппаратная проблема?
Не думаю, у нашей группы разработчиков таки ошибки проявляется примерно одинаково у всех, при работе с одинаковым кодом.
Это или компилятор напарывается на конструкцию , которую не может распарсить, но стандартной обработки ошибки для нее нет,
или у компилятора кончается память.
Здравствуйте, Alekzander, Вы писали:
A> Может, аппаратная проблема?
Это точно не аппаратная проблема Внутренние ошибки с таким кодом говорят о проблемах кодгена. Часто это связано с попыткой инлайнинга, но могут быть и другие приколы.
Здравствуйте, swame, Вы писали: S>Больше я тестировать такое не хочу, надоело. если хочещь изготовь отдельный тестовый проект, чтобы я собрал и проверил, S>чтобы компилился без установки каких-то компонент. S>К тесту приложи цифры тестирования: S>1. Сравнение по скорости и занимаемой памяти с алгоритмом ChatGPT БЕЗ КОПИРОВАНИЯ на массивах 1 тыс, 1 млн, 1 млрд. записей.
Хорошо, специально для вас скомпилировал и проверил ещё раз весь код. Создайте новый проект с формой, киньте на форму две кнопки и скопируйте этот код. Скорее всего сможете прямо вставить код из под ката в ваш юнит, разве что за именем модуля надо следить:
Скрытый текст
unit Unit7;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, math, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private{ Private declarations }public{ Public declarations }end;
const
MaxSerieSize=50000000;
MinSafeFloat=1e-10;
MaxSafeFloat=1e50;
type
PDoubleArr=^TDoubleArr;
TDoubleArr=array[0..maxseriesize-1] of double;
TDoubleArray=class
private
public
fcount:integer;
fcapacity:integer;
procedure SetCount(newcount:integer);
procedure SetCapacity(newcapacity:integer);
procedure QSort2GPT;
procedure QSort10Sections;
public
fitems:pdoublearr;
procedure Add(value:double);
procedure Grow;
procedure Assign(otherarray: tdoublearray);
property Count:integer read fcount write setcount;
property Capacity:integer read fcapacity write SetCapacity;
end;
var
Form1: TForm1;
implementation{$R *.dfm}procedure TDoubleArray.SetCapacity(newcapacity: integer);
begin
if NewCapacity < fCount then
raise exception.Create('NewCapacity='+inttostr(NewCapacity));
if NewCapacity <> fCapacity then
begin
ReallocMem(fitems, NewCapacity * SizeOf(double));
FCapacity := NewCapacity;
end;
end;
procedure TDoubleArray.SetCount(newcount: integer);
begin
if newcount>fcapacity then setcapacity(newcount);
fcount := newcount;
end;
procedure TDoubleArray.QSort2GPT;
var
arr:array of double;
q:integer;
procedure QSort(low,high:integer);
var
i, j: Integer;
pivot, temp: double;
begin
i := low;
j := high;
pivot := arr[(low + high) div 2];
repeat
while arr[i] < pivot do
Inc(i);
while arr[j] > pivot do
Dec(j);
if i <= j then
begin
temp := arr[i];
arr[i] := arr[j];
arr[j] := temp;
Inc(i);
Dec(j);
end;
until i > j;
if low < j then
QSort(low, j);
if i < high then
QSort(i, high);
end;
begin
if count<=1 then exit;
setlength(arr,count);
for q:=0 to count-1 do arr[q]:=fitems[q];
qsort(0,count-1);
for q:=0 to count-1 do fitems[q]:=arr[q];
setlength(arr,0);
end;
procedure TDoubleArray.QSort10Sections;
const
SectionsCount=100;
var
sectionsize:integer;
Sections:array[0..SectionsCount-1] of tdoublearray;
q,w:integer;
minval,maxval:double;
interval:double;
begin
if fcount<300 then begin
QSort2GPT;
exit;
end;
minval:=MaxSafeFloat;
maxval:=-MaxSafeFloat;
for q:=0 to fcount-1 do begin
if fitems[q]<minval then minval:=fitems[q];
if fitems[q]>maxval then maxval:=fitems[q];
end;//next q
minval:=minval-minsafefloat;
maxval:=maxval+minsafefloat;
interval:=maxval-minval;
sectionsize:=fcount div sectionscount;
for q:=0 to sectionscount-1 do begin
sections[q]:=TDoubleArray.Create;
sections[q].Capacity:=sectionsize*2;
end;
for q:=0 to fcount-1 do begin
sections[floor((sectionscount-1)*(fitems[q]-minval)/interval)].Add(fitems[q]);
end;
count:=0;
for q:=0 to SectionsCount-1 do begin
sections[q].QSort10Sections;
for w:=0 to sections[q].fcount-1 do add(sections[q].fitems[w]);
sections[q].Free;
end;
end;
procedure TDoubleArray.Add(value: double);
begin
fcount:=fcount+1;
if fcount>fcapacity then grow;
fitems^[fcount-1]:=value;
end;
procedure TDoubleArray.Grow;
begin
if fcapacity<100 then setcapacity(100) else
setcapacity(fcapacity*2);
end;
procedure TDoubleArray.Assign(otherarray: tdoublearray);
var
q:integer;
begin
count:=0;
capacity:=otherarray.Count;
for q:=0 to otherarray.Count-1 do add(otherarray.fitems[q]);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
q,w:integer;
firsttime:longword;
timegpt,timesections:longword;
curarray:tdoublearray;
outstr:string;
begin
firsttime:=GetTickCount;
for q:=0 to 100 do begin
curarray:=tdoublearray.Create;
curarray.Capacity:=100000;
for w:=0 to 99999 do curarray.Add(random);
curarray.QSort2GPT;
curarray.Free;
end;
timegpt:=gettickcount-firsttime;
firsttime:=GetTickCount;
for q:=0 to 100 do begin
curarray:=tdoublearray.Create;
curarray.Capacity:=100000;
for w:=0 to 99999 do curarray.Add(random);
curarray.QSort10Sections;
curarray.Free;
end;
timesections:=gettickcount-firsttime;
outstr:='GPT: '+inttostr(timegpt)+'; Секции: '+inttostr(timesections);
application.MessageBox(pchar(outstr),'Тест',mb_ok);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
q,w:integer;
arr1,arr2:tdoublearray;
begin
for q:=0 to 100 do begin
arr1:=tdoublearray.Create;
arr1.Capacity:=10000;
for w:=0 to 9999 do arr1.Add(random);
arr2:=tdoublearray.Create;
arr2.assign(arr1);
arr1.QSort2GPT;
arr2.QSort10Sections;
for w:=0 to arr1.Count-1 do if arr1.fitems[w]<>arr2.fitems[w] then application.MessageBox('Ошибка!','Test',mb_ok);
end;
end;
end.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен
Здравствуйте, Khimik, Вы писали:
K>Здравствуйте, swame, Вы писали:
S>>Больше я тестировать такое не хочу, надоело. если хочещь изготовь отдельный тестовый проект, чтобы я собрал и проверил, S>>чтобы компилился без установки каких-то компонент. S>>К тесту приложи цифры тестирования: S>>1. Сравнение по скорости и занимаемой памяти с алгоритмом ChatGPT БЕЗ КОПИРОВАНИЯ на массивах 1 тыс, 1 млн, 1 млрд. записей.
K>Хорошо, специально для вас скомпилировал и проверил ещё раз весь код. Создайте новый проект с формой, киньте на форму две кнопки и скопируйте этот код. Скорее всего сможете прямо вставить код из под ката в ваш юнит, разве что за именем модуля надо следить:
Проверил, твой алгоритм показывает циферку времени чуть меньше чем GPT.
Но есть пара нюансов, совсем незначительных.
1. Твой алгоритм не сортирует.
Поставь после сортировки
for w := 0 to 999998 do
Assert (curarray.fitems[w]<=curarray.fitems[w+1],
w.ToString + ' ' + FloatToStr(curarray.fitems[w]) + ' ' + FloatToStr(curarray.fitems[w+1]));
2. Занимает раз в 8 больше памяти, еще непонятно сколько будет занимать когда будет правильно работать и какая будет скорость.