Цена использования генериков

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Аватара пользователя
alexs
долгожитель
Сообщения: 4066
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Цена использования генериков

Сообщение alexs »

Вброс для развития флейма
Цена использования генериков - http://lazarusroad.blogspot.com/2012/06 ... erics.html

Я полностью согласен - кажущаяся проста порождает лишний код.
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

В статье нет ни слова о том, чем грозит обилие сгенерированный обобщениями кода? Если размером бинарника/асмовского кода - то это та величина, которой можно пренебречь, ради удобства.
Как страшный сон вспоминаю TList'ы и ручное приведение типов
Аватара пользователя
alexs
долгожитель
Сообщения: 4066
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Сообщение alexs »

Мысль статьи - лучше несколько раз подумать и сгенерить меньший код, чем тупо раздувать приложение.
А создать наследника от TList нельзя было?
И привидение типов победится и размер не распухнет...
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

Вот тут проект на Generic'ах чуть более, чем полностью ^_^ А на TList'ах... Нафиг-нафиг ^_^
Аватара пользователя
alexs
долгожитель
Сообщения: 4066
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Сообщение alexs »

Т.е. элементарная лень перевешивает весь здравый смысл? :shock:
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

Если за "здравым смыслом" стоит только экономия размера бинарника (а никаких других доводов я пока не встречал, при том, без отладочной информации рабочий проект с 17 классами, порождёнными от обобщений (а в каждом классе вызывается Specialize 4-10 раз) этот самый размер бинарника - бешеные 2 мб), то так и да, лень побеждает ^_^
kipar
новенький
Сообщения: 78
Зарегистрирован: 04.03.2010 11:15:54

Сообщение kipar »

Ну, кроме размера кода увеличивается время компиляции и возникают проблемы с отладкой (да и просто баги компилятора). Но по-моему более красивый и понятный код намного перевешивает все эти мелочи.
Сквозняк
энтузиаст
Сообщения: 1159
Зарегистрирован: 29.06.2006 22:08:32

Сообщение Сквозняк »

А если от их избытка компиляция превысит минуту-две?
alexey38
долгожитель
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Сообщение alexey38 »

Есть общий тезис: Всего должно быть в меру.
Программа будет плохой не только, если в ней будет много генериков, но и если в ней будет слишком много объектов.
Среди программистов (в широком смысле слова) уже не один десяток лет идет спор ЗА и ПРОТИВ формальных подходов. Я сторонник того, что тупой формализм плох везде: в программировании, в быту, в политике, в экономике и т.п.

У генериков есть простое предназначение, если нужно создать несколько классов, как братья-близнецы похожие друг на друга, но отличающиеся типом одной переменной (поля), и как следствие типов методов обращающихся с этой переменной. Это позволяет не дублировать код в методах, что важно, если код сложнее чем 1-2 оператора.

Говоря о том, что лучше: приводить тип TList, использовать генерики или использовать наследование TList? Ответ часто бывает неожиданным: все плохо. Так как возможно, что сама программа изначально плохо спроектирована, очень часто код находится вне класса, хотя должен быть внутри методов класса. Создание полноценной объектной модели предметной области очень часто позволяет повысить эффективность разработки программы на порядок и даже более.
Часто массовое использование TList-ов это и есть признак непрозрачной программы, построенной очень косо, дальнейшее ее сопровождение, особенно если в ней есть генерики только усложняется, т.к. нет ясности.
Аватара пользователя
vada
энтузиаст
Сообщения: 691
Зарегистрирован: 14.02.2006 12:43:17

Сообщение vada »

Использовал генерики в JAVA, C#. Использую и в FreePascal т.к. это удобно, уменьшает количество кода лапами, сокращает время отладки, сокращает время разработки, создает более читаемый код. А то что бинарник становится больше, это меня не волнует. Более приоритетно быстрее выдать работающий продукт.
Меня больше смущает реализация генериков в FreePascal.
Почему если у меня описан тип

Код: Выделить всё

TCrossArray = specialize TPointsList<TPointArray>;

Описываю переменную

Код: Выделить всё

CrossPointsCollection: TCrossArray;

При обращении к элементу листа я должен приводить тип

Код: Выделить всё

Cr1 := TPointArray(CrossPointsCollection.Items[I])
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

Код: Выделить всё

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.
Аватара пользователя
vada
энтузиаст
Сообщения: 691
Зарегистрирован: 14.02.2006 12:43:17

Сообщение vada »

Интересно. А почему у меня компилятор требует приведения типа? Все отличие в TFPGList. У меня TList
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

TList - это вообще не обобщение ^_^ Без кода сказать сложно...
Аватара пользователя
vada
энтузиаст
Сообщения: 691
Зарегистрирован: 14.02.2006 12:43:17

Сообщение vada »

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

Сообщение Brainenjii »

Проблема с IndexOf для списка. Там нужно что-то вроде If Items[i] = Item, а для записи не перегружен оператор сравнения на равенство. Причем тут говорят, что по реализации обобщений в FPC специализация не может видеть перегруженные операторы, которые не прибиты к собственно объявлению записи. В режиме совместимости с Delphi такой код прокатит

Код: Выделить всё

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'ы недолюбливаю и на каждый чих пложу классы, так что с такой проблемой не сталкивался
Ответить