Альтернативы )))

Любые обсуждения, не нарушающие правил форума.

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

Re: Альтернативы )))

Сообщение скалогрыз » 01.07.2016 18:30:30

Дож писал(а):В идеальном мире они вообще не объявлены, а на их месте просто написано TOpenArrayOf<Integer> и TDynArrayOf<Integer> соответственно

Тогда я не понимаю как компилятор позволяет подставлять один тип к другому.

Неявное приведение известных (компилятору) типов описано...а тут как?!
(н.р. компилятор знает о ооп наследовании, integer -> float, AnsiString -> WideString)

Или это просто заявка, что компилятор должен понимать что есть TOpenArray<T> и что есть TDynArray<T> и как один к другому привести в случае если <T> совпадает?
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Альтернативы )))

Сообщение Дож » 01.07.2016 18:37:27

Оператор приведения: у TDynArrayOf<T> должен быть определён оператор приведения к TOpenArrayOf<T>.
Код: Выделить всё
type
T1 = record
  P: PInteger;
end;

T2 = record
  I: Integer;
end;

operator := (const A: T2): T1;
begin
  Result.P := @A.I;
end;

procedure Set5(const X: T1);
begin
  X.P^ := 5;
end;

var
  A: T2;
begin
  Set5(A);
  Writeln(A.I);
end.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Альтернативы )))

Сообщение скалогрыз » 01.07.2016 19:04:14

Дож писал(а):Оператор приведения: у TDynArrayOf<T> должен быть определён оператор приведения к TOpenArrayOf<T>.

хм... а оператор писать нужно в виде дженерика, или после специализации?
Код: Выделить всё
operator := (const A: TDynArray<T>): TOpenArray<T>;
begin
  Result.P := @A.I;
end;
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Альтернативы )))

Сообщение Дож » 01.07.2016 19:09:41

Для дженерика, конечно, иначе сила его теряется. В этом плане синтаксис описания операторов в дельфи (внутри структуры, а не снаружи) мне нравится больше, чем выбранный в OBJFPC.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Альтернативы )))

Сообщение Лекс Айрин » 01.07.2016 20:46:37

только что я понял, что буду олдскульщиком до последней возможности... мозги потихоньку закипают, но понять я ничего не могу...
А считалось, что объектный паскаль упростит программирование (иначе смысла в его реализации нет).
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Альтернативы )))

Сообщение скалогрыз » 01.07.2016 22:47:46

Лекс Айрин писал(а):только что я понял, что буду олдскульщиком до последней возможности... мозги потихоньку закипают, но понять я ничего не могу...
мета-программирование же! скоро все библиотеки будут на них (дженериках) написаны.

Дож, 100% прав в том, что с новыми фичами нужно знакомиться. Не обязательно их использовать, но знать на уровне "мозни НЕ закипают, чётко понимаю что происходит" нужно. Хотя бы в пределах FPC :)

Добавлено спустя 1 час 34 минуты 29 секунд:
скалогрыз писал(а):хм... а оператор писать нужно в виде дженерика, или после специализации?

Дож писал(а):Для дженерика, конечно, иначе сила его теряется. В этом плане синтаксис описания операторов в дельфи (внутри структуры, а не снаружи) мне нравится больше, чем выбранный в OBJFPC.


Не осилил! Описал оператор после специализации дженерика
Код: Выделить всё
{$mode objfpc}
type
  generic TOpenArrayOf<T> = object
  public type
    P = ^T;
  public
    Elements: P;
    Length: LongInt;
  end;

  generic TDynArrayOf<T> = object
  public type
    P = ^T;
  public
    Elements: P;
    Length: LongInt;
    procedure SetLength(ALen: Integer);
  end;

procedure TDynArrayOf.SetLength(ALen: Integer);
begin
  Length:=ALen;
  ReallocMem(Elements, Length * sizeof(T));
end;

type
  TDynArrayOfInteger = specialize TDynArrayOf <Integer>;
  TOpenArrayOfInteger = specialize TOpenArrayOf <Integer>;

operator := (const A: TDynArrayOfInteger): TOpenArrayOfInteger;
begin
  Result.Elements := A.Elements;
  Result.Length := A.Length;
end;

procedure Foo(a: TOpenArrayOfInteger);
var
  i : integer;
begin
  for i:=0 to a.length-1 do
    writeln(a.Elements[i],' ',PtrUint(@a.Elements[i]));
end;

var
  Arr: TDynArrayOfInteger;
begin
  Arr.SetLength(3);
  Arr.Elements[0]:=10;
  Arr.Elements[1]:=20;
  Arr.Elements[2]:=30;
  Foo(Arr);
end.


Гляжу в ассемблер (fpc264 с -O3) и ожидаемо вижу:
Код: Выделить всё
P$PROGRAM_assign$TDYNARRAYOF$LONGINT$$TOPENARRAYOF$LONGINT:
# [31] begin
# [32] Result.Elements := A.Elements;
   movl   (%eax),%ecx
   movl   %ecx,(%edx)
# [33] Result.Length := A.Length;
   movl   4(%eax),%eax
   movl   %eax,4(%edx)
# [34] end;
       ...
   call   P$PROGRAM_assign$TDYNARRAYOF$LONGINT$$TOPENARRAYOF$LONGINT


тогда как
Код: Выделить всё
{$mode objfpc}

procedure Foo(const a: array of Integer; count: integer);
var
  i : integer;
begin
  for i:=0 to count-1 do
    writeln(a[i]);
end;

var
  Arr: array of Integer;
begin
  SetLength(Arr, 3);
  Arr[0]:=10;
  Arr[1]:=20;
  Arr[2]:=30;
  Foo(Arr, length(Arr));
end.

Просто передача указателя (+ размера) + размера в функцию.

скорость мерять?
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Альтернативы )))

Сообщение Дож » 02.07.2016 02:05:31

скалогрыз, о, я придумал как это можно обойти уже сейчас без использования (всё равно не существующих ещё) операторов для дженериков
Код: Выделить всё
{$mode objfpc}
type
  generic TOpenArrayOf<T> = object
  public type
    P = ^T;
  public
    Elements: P;
    Length: LongInt;
  end;

  generic TDynArrayOf<T> = object(specialize TOpenArrayOf<T>)
  public
    procedure SetLength(ALen: Integer);
  end;

procedure TDynArrayOf.SetLength(ALen: Integer);
begin
  Length:=ALen;
  ReallocMem(Elements, Length * sizeof(T));
end;

type
  TDynArrayOfInteger = specialize TDynArrayOf <Integer>;
  TOpenArrayOfInteger = specialize TOpenArrayOf <Integer>;

procedure Foo(const a: TOpenArrayOfInteger);
var
  i : integer;
begin
  for i:=0 to a.length-1 do
    writeln(a.Elements[i],' ',PtrUint(@a.Elements[i]));
end;

var
  Arr: TDynArrayOfInteger;
begin
  Arr.SetLength(3);
  Arr.Elements[0]:=10;
  Arr.Elements[1]:=20;
  Arr.Elements[2]:=30;
  Foo(Arr);
end.

Код: Выделить всё
# [41] Foo(Arr);
   movl   $U_$P$PROGRAM_$$_ARR,%eax
   call   P$PROGRAM_$$_FOO$TOPENARRAYOF$1$CRC31B95292

:) Ну а вообще — и то, и другое стоит уложить в памяти так, чтобы в операторе преобразования действий для каста не требовалось.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Альтернативы )))

Сообщение скалогрыз » 02.07.2016 05:15:02

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

ха! старое доброе ооп выручает :D соглашусь - эффективность в данном случае не страдает.

Тогда вернёмся к реф-каунтингу. Такой вот пример:
Код: Выделить всё
{$mode objfpc}
type
  generic TOpenArrayOf<T> = object
  public type
    P = ^T;
  public
    Elements: P;
    Length: LongInt;
  end;

  generic TDynArrayOf<T> = object(specialize TOpenArrayOf<T>)
  public
    procedure SetLength(ALen: Integer);
  end;

procedure TDynArrayOf.SetLength(ALen: Integer);
begin
  Length:=ALen;
  ReallocMem(Elements, Length * sizeof(T));
end;

type
  TDynArrayOfInteger = specialize TDynArrayOf <Integer>;
  TOpenArrayOfInteger = specialize TOpenArrayOf <Integer>;

procedure Foo(const a: TOpenArrayOfInteger);
var
  i : integer;
begin
  for i:=0 to a.length-1 do
    writeln(a.Elements[i],' ',PtrUint(@a.Elements[i]));
end;

var
  Arr: TDynArrayOfInteger;
  Brr: TDynArrayOfInteger;
begin
  Arr.SetLength(3);
  Arr.Elements[0]:=10;
  Arr.Elements[1]:=20;
  Arr.Elements[2]:=30;
  Brr:=Arr;
  Brr.SetLength(4);
  Brr.Elements[3]:=40;
  writeln('Brr:');
  Foo(Brr);
  writeln('Arr:');
  Foo(Arr);
end.

будут ли какие-нибудь комментарии по поводу этого кода? лично я недоволен, что попортился Arr.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Альтернативы )))

Сообщение Лекс Айрин » 02.07.2016 09:26:02

скалогрыз писал(а):Дож, 100% прав в том, что с новыми фичами нужно знакомиться.


Это не спорю. Просто не понимаю как это применяется и накуа вообще нужно. Ведь по идее, ООП должно все это прекрасно преодолевать.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Альтернативы )))

Сообщение Дож » 02.07.2016 11:54:58

будут ли какие-нибудь комментарии по поводу этого кода? лично я недоволен, что попортился Arr.

Комментарий такой, что более-менее любая подобная претензия один-в-один переделывается на претензию к TObject. Мысленно представь себе TList вместо TDynArrayOfInteger в коде и аналогичные проделываемые действия. Arr тоже попортится.

Поэтому чтобы быть последовательным, на данном конкретном примере кода нужно признать, что либо все объекты должны быть со сборщиком мусора, либо динамические массивы без RefCounting'а — это норма и можно жить также, как все живут с TObject'ами.

1. Программист должен понимать, что A := B для object'ов — весьма специфичное действие и чревато серьёзными последствиями, а для class'ов — затиранием ссылки на A. Это не Rocket Science знание.
2. Ссылку на массив можно передавать как указатель в другое место (условное PDynArrayOfInteger, либо то же TOpenArrayOfInteger).
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Альтернативы )))

Сообщение скалогрыз » 03.07.2016 03:41:23

Дож писал(а):Комментарий такой, что более-менее любая подобная претензия один-в-один переделывается на претензию к TObject. Мысленно представь себе TList вместо TDynArrayOfInteger в коде и аналогичные проделываемые действия. Arr тоже попортится.

разумеется, он не попортится. Arr и Brr будут указывать на один и тот же инстанс, и изменения через Brr будут видны через Arr.

Добавлено спустя 3 минуты 25 секунд:
Дож писал(а):1. Программист должен понимать, что A := B для object'ов — весьма специфичное действие и чревато серьёзными последствиями

ну не то что бы оно чревато серьёзными последствиями. Оно действительно чревато, но в том случае если A будет вызывать определённые изменения, которые не отразятся в B. Например если после присовения A использовать только "для чтения" то ничего плохого не произойдёт :)

А ещё всё зависит от внутренеей реализации A и B ... так что лучше всегда думать про серьёзные последствия.

Добавлено спустя 1 час 59 минут 28 секунд:
Лекс Айрин писал(а):Это не спорю. Просто не понимаю как это применяется и накуа вообще нужно. Ведь по идее, ООП должно все это прекрасно преодолевать.

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

Второе истекает из первого. Потому что тип, который ты используешь может быть и не объект. Например, чтобы положить в TList какой-нибудь record, то придётся этот record держать в куче, используя GetMem / FreeMem. Именно потому что реализация TList-а заточена на использование Pointer-а, в качестве элемента листа.
А при использовании генерика TList<T>, реализация будет заточена под тот тип, который ты хочешь. И это вполне может быть тот самый record.

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

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

Например ООП. Это же хорошо и замечательно. Но, люди стали писать библиотеки основанные на ООП, даже в тех местах, где без объектов в принципе можно обойтись.
Например, как распаковать PNG файл, и получить из него массив пискелей?! Есть кучи и кучи библиотек с объектом аля TPNGImage, но каждый из них привязан к собственной библиотеке (экосистема же!). Или опять же привязан к VCL, LCL или FCL библиотеке. Но ведь совсем не факт, что я, как программист, опираюсь на VCL, LCL или FCL.
Как итог, имеет кучу одинакового взаимно дублирующего кода. В каждой вариации свои ошибки. Переносить и поддерживать которые тяжёло, потому что привязка к библиотечно экосистеме мешает.

А с дженериками, это же вообще песня, городить однотипный огород. Уверен, много кто, опубликует (благо github!), свой вариант STL для паскаля :mrgreen:
И кстати сказать, вроде бы с Helper-ами такого не случилось :)

Я не боюсь технологий, я боюсь людей :mrgreen: :mrgreen: :mrgreen:
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Пред.

Вернуться в Потрепаться

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 12

Рейтинг@Mail.ru