Цена использования генериков
Модератор: Модераторы
- alexs
- долгожитель
- Сообщения: 4066
- Зарегистрирован: 15.05.2005 23:17:07
- Откуда: г.Ставрополь
- Контактная информация:
Цена использования генериков
Вброс для развития флейма
Цена использования генериков - http://lazarusroad.blogspot.com/2012/06 ... erics.html
Я полностью согласен - кажущаяся проста порождает лишний код.
Цена использования генериков - http://lazarusroad.blogspot.com/2012/06 ... erics.html
Я полностью согласен - кажущаяся проста порождает лишний код.
- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
В статье нет ни слова о том, чем грозит обилие сгенерированный обобщениями кода? Если размером бинарника/асмовского кода - то это та величина, которой можно пренебречь, ради удобства.
Как страшный сон вспоминаю TList'ы и ручное приведение типов
Как страшный сон вспоминаю TList'ы и ручное приведение типов
- alexs
- долгожитель
- Сообщения: 4066
- Зарегистрирован: 15.05.2005 23:17:07
- Откуда: г.Ставрополь
- Контактная информация:
Мысль статьи - лучше несколько раз подумать и сгенерить меньший код, чем тупо раздувать приложение.
А создать наследника от TList нельзя было?
И привидение типов победится и размер не распухнет...
А создать наследника от TList нельзя было?
И привидение типов победится и размер не распухнет...
- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
Вот тут проект на Generic'ах чуть более, чем полностью ^_^ А на TList'ах... Нафиг-нафиг ^_^
- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
Если за "здравым смыслом" стоит только экономия размера бинарника (а никаких других доводов я пока не встречал, при том, без отладочной информации рабочий проект с 17 классами, порождёнными от обобщений (а в каждом классе вызывается Specialize 4-10 раз) этот самый размер бинарника - бешеные 2 мб), то так и да, лень побеждает ^_^
Ну, кроме размера кода увеличивается время компиляции и возникают проблемы с отладкой (да и просто баги компилятора). Но по-моему более красивый и понятный код намного перевешивает все эти мелочи.
А если от их избытка компиляция превысит минуту-две?
Есть общий тезис: Всего должно быть в меру.
Программа будет плохой не только, если в ней будет много генериков, но и если в ней будет слишком много объектов.
Среди программистов (в широком смысле слова) уже не один десяток лет идет спор ЗА и ПРОТИВ формальных подходов. Я сторонник того, что тупой формализм плох везде: в программировании, в быту, в политике, в экономике и т.п.
У генериков есть простое предназначение, если нужно создать несколько классов, как братья-близнецы похожие друг на друга, но отличающиеся типом одной переменной (поля), и как следствие типов методов обращающихся с этой переменной. Это позволяет не дублировать код в методах, что важно, если код сложнее чем 1-2 оператора.
Говоря о том, что лучше: приводить тип TList, использовать генерики или использовать наследование TList? Ответ часто бывает неожиданным: все плохо. Так как возможно, что сама программа изначально плохо спроектирована, очень часто код находится вне класса, хотя должен быть внутри методов класса. Создание полноценной объектной модели предметной области очень часто позволяет повысить эффективность разработки программы на порядок и даже более.
Часто массовое использование TList-ов это и есть признак непрозрачной программы, построенной очень косо, дальнейшее ее сопровождение, особенно если в ней есть генерики только усложняется, т.к. нет ясности.
Программа будет плохой не только, если в ней будет много генериков, но и если в ней будет слишком много объектов.
Среди программистов (в широком смысле слова) уже не один десяток лет идет спор ЗА и ПРОТИВ формальных подходов. Я сторонник того, что тупой формализм плох везде: в программировании, в быту, в политике, в экономике и т.п.
У генериков есть простое предназначение, если нужно создать несколько классов, как братья-близнецы похожие друг на друга, но отличающиеся типом одной переменной (поля), и как следствие типов методов обращающихся с этой переменной. Это позволяет не дублировать код в методах, что важно, если код сложнее чем 1-2 оператора.
Говоря о том, что лучше: приводить тип TList, использовать генерики или использовать наследование TList? Ответ часто бывает неожиданным: все плохо. Так как возможно, что сама программа изначально плохо спроектирована, очень часто код находится вне класса, хотя должен быть внутри методов класса. Создание полноценной объектной модели предметной области очень часто позволяет повысить эффективность разработки программы на порядок и даже более.
Часто массовое использование TList-ов это и есть признак непрозрачной программы, построенной очень косо, дальнейшее ее сопровождение, особенно если в ней есть генерики только усложняется, т.к. нет ясности.
Использовал генерики в JAVA, C#. Использую и в FreePascal т.к. это удобно, уменьшает количество кода лапами, сокращает время отладки, сокращает время разработки, создает более читаемый код. А то что бинарник становится больше, это меня не волнует. Более приоритетно быстрее выдать работающий продукт.
Меня больше смущает реализация генериков в FreePascal.
Почему если у меня описан тип
Описываю переменную
При обращении к элементу листа я должен приводить тип
Меня больше смущает реализация генериков в FreePascal.
Почему если у меня описан тип
Код: Выделить всё
TCrossArray = specialize TPointsList<TPointArray>;Описываю переменную
Код: Выделить всё
CrossPointsCollection: TCrossArray;При обращении к элементу листа я должен приводить тип
Код: Выделить всё
Cr1 := TPointArray(CrossPointsCollection.Items[I])- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
Код: Выделить всё
program Project1;
uses
fgl;
Type
TPointArray = Class
Private
bID: Integer;
Public
Property ID: Integer Read bID Write bID;
End;
Type TCrossArray = specialize TFPGList<TPointArray>;
Var
i: Integer;
aBuffer, Cr1: TPointArray;
CrossPointsCollection: TCrossArray;
begin
CrossPointsCollection := TCrossArray.Create;
aBuffer := TPointArray.Create;
aBuffer.ID := 1;
CrossPointsCollection.Add(aBuffer);
For i := 0 To CrossPointsCollection.Count - 1 Do
Begin
Cr1 := CrossPointsCollection.Items[0];
WriteLn(Cr1.ID);
WriteLn(CrossPointsCollection.Items[0].ID);
End;
CrossPointsCollection.Free;
aBuffer.Free;
end.
Интересно. А почему у меня компилятор требует приведения типа? Все отличие в TFPGList. У меня TList
- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
TList - это вообще не обобщение ^_^ Без кода сказать сложно...
TList - это вообще не обобщение
Спасибо. Понял. Переделаю.
Добавлено спустя 22 часа 55 минут 29 секунд:
Чёта так не живет
Код: Выделить всё
{$mode objfpc}
interface
uses
Classes, SysUtils, fgl;
const
DemosVersion = '0.0.1';
type
// Точка контура
TConturPoint = record
X, Y, Z: Double;
end;
// Тело между сечениями
TBodyBetweenCross = record
CrossBeginZ: Double;
CrossEndZ: Double;
CrossDeltaZ: Double;
end;
// Массив точек контура
TPointArray = specialize TFPGList<TConturPoint>;
// Массив сечений
TCrossArray = specialize TFPGList<TPointArray>;
// Тело между сечениями
TBodyArray = specialize TFPGList<TBodyBetweenCross>;
implementation
end.
Упс
Код: Выделить всё
Hint: Start of reading config file D:\lazarus\fpc\2.6.0\bin\i386-win32\fpc.cfg
Hint: End of reading config file D:\lazarus\fpc\2.6.0\bin\i386-win32\fpc.cfg
Free Pascal Compiler version 2.6.0 [2012/03/14] for i386
Copyright (c) 1993-2011 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling Demos.lpr
2 151/1.344 Kb Used
Compiling demosmain.pas
Compiling typesdemos.pas
Error: Operator is not overloaded: "TConturPoint" = "TConturPoint"
- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
Проблема с IndexOf для списка. Там нужно что-то вроде If Items[i] = Item, а для записи не перегружен оператор сравнения на равенство. Причем тут говорят, что по реализации обобщений в FPC специализация не может видеть перегруженные операторы, которые не прибиты к собственно объявлению записи. В режиме совместимости с Delphi такой код прокатит
Буду рад увидеть пример с {$mode objfpc}
Лично я Record'ы недолюбливаю и на каждый чих пложу классы, так что с такой проблемой не сталкивался
Код: Выделить всё
program Project1;
{$mode delphi}{$H+}
uses
Classes, SysUtils, fgl;
const
DemosVersion = '0.0.1';
type
// Точка контура
{ TConturPoint }
TConturPoint = record
X, Y, Z: Double;
class operator Equal(A, B: TConturPoint): Boolean;
end;
// Тело между сечениями
{ TBodyBetweenCross }
TBodyBetweenCross = record
CrossBeginZ: Double;
CrossEndZ: Double;
CrossDeltaZ: Double;
class operator Equal(A, B: TBodyBetweenCross): Boolean;
end;
// Массив точек контура
TPointArray = TFPGList<TConturPoint>;
// Массив сечений
TCrossArray = TFPGList<TPointArray>;
{ TBodyBetweenCross }
Class Operator TBodyBetweenCross.Equal(A, B: TBodyBetweenCross): Boolean;
Begin
Result := (A.CrossBeginZ = B.CrossBeginZ) And (A.CrossEndZ = B.CrossEndZ) And
(A.CrossDeltaZ = B.CrossDeltaZ);
End;
{ TConturPoint }
Class Operator TConturPoint.Equal(A, B: TConturPoint): Boolean;
Begin
Result := (A.X = B.X) And (A.Y = B.Y) And (A.Z = B.Z);
End;
// Тело между сечениями
Type TBodyArray = TFPGList<TBodyBetweenCross>;
begin
end.
Буду рад увидеть пример с {$mode objfpc}
Лично я Record'ы недолюбливаю и на каждый чих пложу классы, так что с такой проблемой не сталкивался
