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

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

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

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

Сообщение скалогрыз » 29.06.2016 19:58:09

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

Аха. либо обернуть всё в класс и использовать type cast.

Дож писал(а):Одно дело — последовательный олдскульщик во всём, другое дело — человек, который говорит, что «array of хорошо получилось», но при этом другие полезные нововведения схожего толка неприемлет.

"Полезные новведения" это вопрос вкуса. Сколько срача было из-за IfThen() и ... что? по причинам вкусовых различий просто ничего не стали делать. Зато, по тем же вкусовым причинам нас встречает NewPascal :)

Дож писал(а):Как эта проблема решена в TList или TStringList? Как дебаггер отличает с каким типом был вызван метод у TList'а?

Ак там один тип :) Если ты поставил Бряк-поинт в том TList, то бряк-поинт сработает.
А если ты поставил в Бряк-поинт в методе дженерика, то дебаггер может и не останиватся. Т.к. код при специализации может быть выкинут (на усмотрение комплиятора). Или ещё хуже, остановится, но не в ожидаемой специализации.

Дож писал(а):Этот вопрос должен мне продемонстрировать неудачность идеи метода Last, потому что есть несколько вариантов её реализации?

А я описал проблемы с Last, в ответе Лексу Айрину
* неэффективность
* потенциальная некорретность

Дож писал(а):Так не демонстрирует же. Или что? Какой ответ от меня ожидается? Ну, я могу сказать, что чисто из логических соображений этот метод не должен использоваться в корректной программе, Range Checking в рантайме не нужен, пусть будет UB.

Если метод .last не должен использовать в корректной программе, то он нужен для написания некорретных програм? :)

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

По-моему, если программа "может не свалится" при A[i], где i - несуществующий индекс, это очень серьёзная проблема.
По двум причинам:
1-х - в алгоритме ошибка - i обязан быть существующим.
2-х - "может не свалится" а "может и свалится" - показатель низкого качества программного обеспечения. Если a[i] вернул хрень и программа не упала сразу, то есть возможность что она упадёт потом. И что ещё хуже, привидёт к потере чьих-нибудь ценных данных.
Пусть валится всегда - ошибка должна быть ошибкой. О ней нужно знать и её исправлять.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Лекс Айрин » 29.06.2016 20:08:51

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

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

Сообщение скалогрыз » 29.06.2016 20:09:55

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

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

Сообщение Дож » 29.06.2016 20:52:17

скалогрыз писал(а):Аха. либо обернуть всё в класс и использовать type cast.

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

скалогрыз писал(а):
Дож писал(а):Одно дело — последовательный олдскульщик во всём, другое дело — человек, который говорит, что «array of хорошо получилось», но при этом другие полезные нововведения схожего толка неприемлет.

"Полезные новведения" это вопрос вкуса. Сколько срача было из-за IfThen() и ... что? по причинам вкусовых различий просто ничего не стали делать. Зато, по тем же вкусовым причинам нас встречает NewPascal :)

Не только вкуса, есть множество аспектов. «Это всё вопрос вкуса» — упрощение ситуации.

В данной конкретной ситуации динамические массивы array of и дженерики решают похожую проблему (единство реализации структуры массив переменной длины), при этом позицию «array of — это очень хорошо, потому что верно X, а дженерики — это плохо, я вполне обхожусь без них», где X верно и про дженерики, я считаю неконсистентной.

скалогрыз писал(а):Ак там один тип :) Если ты поставил Бряк-поинт в том TList, то бряк-поинт сработает.
А если ты поставил в Бряк-поинт в методе дженерика, то дебаггер может и не останиватся. Т.к. код при специализации может быть выкинут (на усмотрение комплиятора). Или ещё хуже, остановится, но не в ожидаемой специализации.

Ничего не понял.

Вот есть два кода, код номер раз:
Код: Выделить всё
var
  A: TList;
  B: TList;
...
  A.Add(TFoo.Create);
...
  B.Add(TBar.Create);


код номер два:
Код: Выделить всё
var
  A: specialize TList<TFoo>;
  B: specialize TList<TBar>;
...
  A.Add(TFoo.Create);
...
  B.Add(TBar.Create);


Что такого особенного мне позволяет сделать дебаггер для первого кода, но не позволяет для второго?

скалогрыз писал(а):
Дож писал(а):Этот вопрос должен мне продемонстрировать неудачность идеи метода Last, потому что есть несколько вариантов её реализации?

А я описал проблемы с Last, в ответе Лексу Айрину
* неэффективность
* потенциальная некорретность


* Столь же эффективно, сколько A[High(A)]
* Столь же некорректно, сколько A[High(A)]

Почему A[High(A)] — сила, а A.Last — могила? Непонятно.

Дож писал(а):Так не демонстрирует же. Или что? Какой ответ от меня ожидается? Ну, я могу сказать, что чисто из логических соображений этот метод не должен использоваться в корректной программе, Range Checking в рантайме не нужен, пусть будет UB.

Если метод .last не должен использовать в корректной программе, то он нужен для написания некорретных програм? :)

Я ошибся когда писал, имел в виду, что в корректной программе не должен вызываться .Last для пустого массива.

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

По-моему, если программа "может не свалится" при A[i], где i - несуществующий индекс, это очень серьёзная проблема.

И это говорит сторонник type cast'ов из Pointer'а в класс в качестве штатного решения для списков! Я не верю своим глазам!

Вот такой код мне напечатал 0:
Код: Выделить всё
var
  I: LongInt;
  A: array of LongInt;
begin
  SetLength(A, 10);
  I := Length(A);
  Writeln(A[I]);
end.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

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

Сообщение eastorwest » 29.06.2016 21:02:02

скалогрыз писал(а):Пусть валится всегда - ошибка должна быть ошибкой.

Полагаю, что для подобного поведения среди опций компиляторов Delphi и FPC есть директива "Range checking"(R+), которая должна добавлять дополнительный проверочный код выхода индекса массива за пределы.
eastorwest
новенький
 
Сообщения: 57
Зарегистрирован: 23.07.2009 20:21:46
Откуда: Н-ск

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

Сообщение скалогрыз » 29.06.2016 21:18:54

Дож писал(а):Это плохое решение, потому что нет проверки типов (а мы говорим про строгий типизированный язык программирования Паскаль, а не про какой-нибудь там ассемблер, бейсик или форт).

Дож писал(а):И это говорит сторонник type cast'ов из Pointer'а в класс в качестве штатного решения для списков! Я не верю своим глазам!

ты забыл про то, что я писал несколько страниц назад, про
* is (для внешних данных)
* доверие собственному коду/алгоритму

Дож писал(а):Что такого особенного мне позволяет сделать дебаггер для первого кода, но не позволяет для второго?

Код: Выделить всё
function TList<T>.Stuff;
begin
  // <-- Breakpoint здесь
  if T is TBar then
    ...
  end;
end;

var
  A: specialize TList<TFoo>;
  B: specialize TList<TBar>;

...
  A.Add(TFoo.Create);
...
  B.Add(TBar.Create);
...
  A.Stuff();
  B.Stuff();

При попытке отладить Stuff() TList<TFoo>, брякпоинт может и не сработать. На момент выставления этого бряк-поинта ты можешь об этом и не узнать.

Дож писал(а):Вот такой код мне напечатал 0:
Код: Выделить всё
    var
      I: LongInt;
      A: array of LongInt;
    begin
      SetLength(A, 10);
      I := Length(A);
      Writeln(A[I]);
    end.


ты забыл поставить ключи компиляция -Criot. Очень полезная вещь!

Добавлено спустя 5 минут 43 секунды:
Дож писал(а):* Столь же эффективно, сколько A[High(A)]
* Столь же некорректно, сколько A[High(A)]

Почему A[High(A)] — сила, а A.Last — могила? Непонятно.


это потому что ты рассматриваешь выражение вне алгоритма.

Алгоритм всегда идёт по схеме
Код: Выделить всё
  i:=length(A);
  if i>0 then
     a[i-1]
  else
    // обработка пустого списка.

В алгоритме, тебе повторная проверка не нужна.

Ты бы стал писать
Код: Выделить всё
  i:=length(A);
  if i>0 then
    a[length(A)-1]
  else
    //обработка пустого списка

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

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

Сообщение Дож » 29.06.2016 21:40:07

ты забыл про то, что я писал несколько страниц назад, про
* is (для внешних данных)
* доверие собственному коду/алгоритму

А я знаю решение, не требующее 1) проверок в Run-Time (всё будет проверено на этапе компиляции) 2) доверия в этом месте :)

При попытке отладить Stuff() TList<TFoo>, брякпоинт может и не сработать. На момент выставления этого бряк-поинта ты можешь об этом и не узнать.

Эта проблема не решена для inline'утых фукнций? Я тоже могу не узнать, что внутри них не сработал BP?

ты забыл поставить ключи компиляция -Criot. Очень полезная вещь!

Я ждал этого комментария, и подготовил новый пример:
Код: Выделить всё
uses
  Classes;
type
  PArrayOfLongInt = ^LongInt;
var
  I: LongInt;
  A: array of LongInt;
  L: TList;
begin
  SetLength(A, 1);

  L := TList.Create;
  L.Add(@A[0]);
  I := -1;
  PArrayOfLongInt(L[0])[I] := 99;
  Writeln(Length(A));
  L.Free;
end.


При компиляции с -Criot напечатало 100 почему-то. Не спасла опция от неопределённого поведения.

Отдельный вопрос — как с этой опцией использовать код, содержащий ^array[0..1] of, написанный адептами олдскула?

Добавлено спустя 7 минут 58 секунд:
скалогрыз писал(а):
Дож писал(а):* Столь же эффективно, сколько A[High(A)]
* Столь же некорректно, сколько A[High(A)]

Почему A[High(A)] — сила, а A.Last — могила? Непонятно.


это потому что ты рассматриваешь выражение вне алгоритма.

И то, и другое я рассматриваю с точки зрения использования в одинаковых ситуациях. Рассуждение «A[High(A)] — это хорошо, потому что оно используется в правильных, хороших алгоритмах, а A.Last — плохо, потому что может быть использовано в плохих, негодных алгоритмах» считаю странным и неубедительным.

Вот утверждение «A.Last читается плохо и запутывает глупого программиста, который не прочитал в доке, что оно эквивалентно A[High(A)]» я бы ещё понял и не стал спорить («вопрос вкуса» типа).
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

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

Сообщение скалогрыз » 29.06.2016 21:59:33

Дож писал(а):Я ждал этого комментария, и подготовил новый пример:

:mrgreen: :mrgreen: :mrgreen:
Но, тут ты уже перестарался, с неправильным обращением с массивом.
... если поменять TList на TList<Integer> ситуацию улучшиться? :mrgreen:

Дож писал(а):Отдельный вопрос — как с этой опцией использовать код, содержащий ^array[0..1] of, написанный адептами олдскула?

никак. И при желании можно даже от компилятора огрести некорректный range-check error.
Для компенсации такого недуга были добавлены open array. (который массивы с известным размером, но неизвестным происхождением) и slice() для преобразования old-school массива в открытый массив (с правильным размером).

А вот от дженериков функционала открытых массивов ждать не придётся.

Добавлено спустя 2 минуты 4 секунды:
Дож писал(а):A[High(A)] — это хорошо, потому что оно используется в правильных, хороших алгоритмах

Кстати, я не говорил, что A[High(A)] это хорошо.
я утверждаю, что A[i] - хорошо, при заранее известном i.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Дож » 29.06.2016 22:18:52

скалогрыз писал(а):... если поменять TList на TList<Integer> ситуацию улучшиться? :mrgreen:

Условно говоря, если поменять на TList<array of LongInt>, а не приводить что-то к Pointer'у, то — да, сильно улучшится, программа упадёт с Range Check Error.

Я вообще ненавистник -Cr, потому что это сильное замедление программы (проверка каждой конструкции вида A[I] для массивов, что может быть неприемлемо при обработке больших данных, например, изображений). Я сторонник качественного кода и проверок на этапе компиляции. Если написано A[I], то это забота программиста сделать так, чтобы I было корректным индексом, а не программы. Задача программы — быстро выполнять то, что от неё требуется.

скалогрыз писал(а):А вот от дженериков функционала открытых массивов ждать не придётся.

Не очень понимаю, что помешает написать условное
SomeFunc(Slice(GenericArr.AsOldschoolArray, GenericArr.Length));
?

Добавлено спустя 8 минут 10 секунд:
Кстати, я не говорил, что A[High(A)] это хорошо.
я утверждаю, что A[i] - хорошо, при заранее известном i.

Согласен. А если известно, что массив непуст, то A.Last — это хорошо, плохо или как?
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

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

Сообщение скалогрыз » 29.06.2016 22:30:01

Дож писал(а):Условно говоря, если поменять на TList<array of LongInt>, а не приводить что-то к Pointer'у, то — да, сильно улучшиться, программа упадёт с Range Check Error.

Аааааааа ... теперь понятно, что ты написать хотел.
Ну тогда твой пример должен был выглядеть вот так.
Код: Выделить всё
 
    uses
      Classes;
    type
      TDynArrayOFLongInt = array of LongInt;
      PArrayOfLongInt = TDynArrayOFLongInt;
    var
      I: LongInt;
      A: array of LongInt;
      L: TList;
    begin
      SetLength(A, 1);

      L := TList.Create;
      L.Add(@A[0]);
      I := -1;
      PArrayOfLongInt(L[0])[I] := 99;
      Writeln(Length(A));
      L.Free;
    end.

Проблема была с описанием PArrayOfLongInt. -Criot теперь ругается с rangecheck еррором.
Хотя, нужно заметить, что класть любой ref-counting тип (строку/дин массив/интерфейс) в Pointer, вещь нежелательная и опасная.

Дож писал(а):Я вообще ненавистник -Cr, потому что это сильное замедление программы (проверка каждой конструкции вида A[I] для массивов, что может быть неприемлемо при обработке больших данных, например, изображений).

а замеры потери производительности были/есть?

Дож писал(а):Я сторонник качественного кода и проверок на этапе компиляции. Если написано A[I], то это забота программиста сделать так, чтобы I было корректным индексом, а не программы

ну хотя бы на этапе разработки, использоват как подсобное средство

Дож писал(а):Не очень понимаю, что помешает написать условное
SomeFunc(Slice(GenericArr.AsOldschoolArray, GenericArr.Length));

Тем что ты используешь открытый массив. Это пример, того что массивы, вещь более низкоуровневая, чем генерики.
И даже если они в чём-то похожи, они всё-таки разные.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Дож » 29.06.2016 23:43:43

а замеры потери производительности были/есть?

Нет, но как бы
Код: Выделить всё
var
  I: LongInt;
  A, B, C: array of LongInt;
begin
  SetLength(A, 100);
  SetLength(B, 100);
  SetLength(C, 100);
  for I := 0 to High(C) do begin
    C[I] := A[I] + B[I];
  end;
  Writeln(C[Random(100)]);
end.


fpc -al -O3
Код: Выделить всё
.Lj43:
   addl   $1,%ecx
# [9] C[I] := A[I] + B[I];
   movl   U_$P$PROGRAM_$$_A,%edx
   movl   U_$P$PROGRAM_$$_B,%ebx
   movl   (%edx,%ecx,4),%esi
   movl   (%ebx,%ecx,4),%edx
   leal   (%esi,%edx),%ebx
   movl   U_$P$PROGRAM_$$_C,%edx
   movl   %ebx,(%edx,%ecx,4)
   cmpl   %ecx,%eax
   jg   .Lj43


fpc -Cr -al -O3
Код: Выделить всё
.Lj43:
   addl   $1,%ebx
# [9] C[I] := A[I] + B[I];
   movl   U_$P$PROGRAM_$$_A,%esi
   movl   %ebx,%eax
   cmpl   $2147483647,%eax
   jbe   .Lj46
   call   fpc_rangeerror
.Lj46:
   movl   U_$P$PROGRAM_$$_A,%eax
   movl   %ebx,%edx
   call   FPC_DYNARRAY_RANGECHECK
   movl   U_$P$PROGRAM_$$_B,%edi
   movl   %ebx,%eax
   cmpl   $2147483647,%eax
   jbe   .Lj47
   call   fpc_rangeerror
.Lj47:
   movl   U_$P$PROGRAM_$$_B,%eax
   movl   %ebx,%edx
   call   FPC_DYNARRAY_RANGECHECK
   movl   (%esi,%ebx,4),%edx
   movl   (%edi,%ebx,4),%eax
   leal   (%edx,%eax),%edi
   movl   U_$P$PROGRAM_$$_C,%esi
   movl   %ebx,%eax
   cmpl   $2147483647,%eax
   jbe   .Lj48
   call   fpc_rangeerror
.Lj48:
   movl   U_$P$PROGRAM_$$_C,%eax
   movl   %ebx,%edx
   call   FPC_DYNARRAY_RANGECHECK
   movl   %edi,(%esi,%ebx,4)
   cmpl   %ebx,-8(%ebp)
   jg   .Lj43


Лично мне не нравится то, что я здесь вижу. У меня есть программы, в которых работа с памятью занимает заметное время, и я не хотел бы, чтобы оно было ещё более заметным.

Тем что ты используешь открытый массив. Это пример, того что массивы, вещь более низкоуровневая, чем генерики.
И даже если они в чём-то похожи, они всё-таки разные.

Это какое-то странное рассуждение. На низком уровне открытый массив — это пара указатель + число элементов. Указатель+число может быть завёрнуто в удобный дженерик TOpenArrayOf<T>, к которому можно неявно скастовать TDynamicArrayOf<T> оператором преобразования и передать этот дженерик в функцию. Я при этом не буду использовать открытого массива как языковую конструкцию, дайте только нормальные дженерики с операторами.

И причём тут похожесть / не похожесть и низкоуровневость? Есть концепция «динамический массив», который умеет определённые вещи. Эту концепцию можно реализовать в паскале ручками для фиксированного типа T. Если эту реализацию завернуть в дженерик, то получится концепция динамический массив для всех типов. Дженерик, реализующий концепцию «динамический массив», не обязан реализовывать концепцию «низкоуровневый массив», но для него могут быть сделаны функции-конвертеры.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

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

Сообщение скалогрыз » 30.06.2016 00:03:14

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

ну работа с памятью, работе с паматью рознь.
RANGECHECK, не распределяется память и кучу не дёргает :) Временной замер бы!

Дож писал(а):Указатель+число может быть завёрнуто в удобный дженерик TOpenArrayOf<T>, к которому можно неявно скастовать TDynamicArrayOf<T> оператором преобразования и передать этот дженерик в функцию.

Открытый массив дешевле дженерика будет, в использовании. Ибо обёрток нет - кусок памяти фиксированного размера и типа. И даже Делфи совместим.

Дож писал(а):И причём тут похожесть / не похожесть и низкоуровневость? Есть концепция «динамический массив», который умеет определённые вещи. Эту концепцию можно реализовать в паскале ручками для фиксированного типа T

и RefCount-ing тоже в дженерике реализуешь? или ждём ARC паскаль?

Добавлено спустя 13 минут 17 секунд:
Ну вот, кстати тест
Код: Выделить всё
{$mode objfpc}
uses SysUtils;

function Trial(n: integer=1): integer;
var
  a : array of integer;
  i : integer;
  c : integer;
begin
  SetLength(a, 1024*1024);
  c:=length(a);
  for n:=0 to n-1 do
    for i:=0 to c-1 do a[i]:=i;

  Result:=a[c-1];
end;

var
  t : tdatetime;
  k : integer;
  n : integer;
begin
  n:=1;
  if ParamCount>0 then n:=StrToIntDef(ParamStr(1),n);
   
  t:=now;
  k:=Trial(n);
  t:=now-t;
  writeln('val:  ', k);
  writeln('ran:  ',n,' times');
  writeln('time: ',round( t*MSecsPerDay),'mls');
end.


При компиляции без -Cr (fpc test.pas), при запуске "test.exe 1000", результат:
Код: Выделить всё
val:  1048575
ran:  1000 times
time: 2251mls

При компиляции с -Cr (fpc -Cr test.pas), при запуске "test.exe 1000", результат:

Код: Выделить всё
val:  1048575
ran:  1000 times
time: 3456mls

Разница-то всего в 1.5 раза!

А при наличии оптимизации, так вообще:
fpc -O3 test.pas
Код: Выделить всё
val:  1048575
ran:  1000 times
time: 642mls


fpc -O3 -Cr test.pas
Код: Выделить всё
val:  1048575
ran:  1000 times
time: 3455mls


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

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

Сообщение Mirage » 30.06.2016 00:44:58

скалогрыз писал(а):Но Борланд действительно, сделали массивы динамическими.


Дин. массивы сперты из Оберона.

скалогрыз писал(а):* is (для внешних данных)
* доверие собственному коду/алгоритму


А чем это свой код отличается от не своего, что ему типобезопасность становится не нужна? Или своего времени на отладку не жалко?
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

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

Сообщение скалогрыз » 30.06.2016 00:59:10

Mirage писал(а):А чем это свой код отличается от не своего, что ему типобезопасность становится не нужна? Или своего времени на отладку не жалко?
кому-то же в этой жизни нужно доверять :)

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

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

Сообщение Дож » 30.06.2016 03:00:45

скалогрыз писал(а):А при наличии оптимизации, так вообще:
fpc -O3 test.pas
Код: Выделить всё
val:  1048575
ran:  1000 times
time: 642mls


fpc -O3 -Cr test.pas
Код: Выделить всё
val:  1048575
ran:  1000 times
time: 3455mls

Серьёзно??? 642 против 3455, в 5 раз? Это верные результаты?

Добавлено спустя 46 минут 4 секунды:
скалогрыз, прогнал тесты у себя:
* Windows 7, i5 2.53Gh 64x, fpc -O3 3.0.0rc1 — 2049mls
* Windows 7, i5 2.53Gh 64x, fpc -O3 -Cr 3.0.0rc1 — 4781mls (в 2.5 раз медленнее)
* Raspbian, armv6l 32, fpc -O3 2.6.4 — 11661mls
* Raspbian, armv6l 32, fpc -O3 -Cr 2.6.4 — 70436mls (в 7 раз медленнее)

Добавлено спустя 1 час 7 минут 59 секунд:
Открытый массив дешевле дженерика будет, в использовании. Ибо обёрток нет - кусок памяти фиксированного размера и типа. И даже Делфи совместим.

Но стоп, дженерик же будет практически в точности дублировать то, как работает открытый массив! Вот, например,
Код: Выделить всё
{$MODE OBJFPC}
type
generic TOpenArrayOf<T> = object
public type
  P = ^T;
public
  Elements: P;
  Length: LongInt;
end;

TOpenArrayOfLongInt = specialize TOpenArrayOf<LongInt>;

var
  A: array[0..3] of LongInt;
  O: TOpenArrayOfLongInt;

{$I-}
procedure PrintLast(const X: array of LongInt); overload;
begin
  Writeln(X[Length(X) - 1]);
end;

procedure PrintLast(const X: TOpenArrayOfLongInt); overload;
begin
  Writeln(X.Elements[X.Length - 1]);
end;

begin
  A[3] := 99;
  PrintLast(A);
  O.Elements := @A[0];
  O.Length := 4;
  PrintLast(O);
end.


fpc -O3 -al
Код: Выделить всё
Так выглядит открытый массив, 19 инструкций!
P$PROGRAM_$$_PRINTLAST$array_of_LONGINT:
# [g.pas]
# [19] begin
   pushl   %ebp
   movl   %esp,%ebp
   pushl   %ebx
   pushl   %esi
# Var X located in register ebx
# Var $highX located in register esi
   movl   %eax,%ebx
   movl   %edx,%esi
# [20] Writeln(X[Length(X) - 1]);
   call   fpc_get_output
   leal   1(%esi),%edx
   movl   -4(%ebx,%edx,4),%ecx
   movl   %eax,%ebx
   movl   %ebx,%edx
   movl   $0,%eax
   call   fpc_write_text_sint
   movl   %ebx,%eax
   call   fpc_writeln_end
# [21] end;
   popl   %esi
   popl   %ebx
   leave
   ret

Код: Выделить всё
Пресловутый «дженерик», 16 инструкций!
P$PROGRAM_$$_PRINTLAST$TOPENARRAYOF$1$CRC31B95292:
# [24] begin
   pushl   %ebx
   pushl   %esi
# Var X located in register ebx
   movl   %eax,%ebx
# [25] Writeln(X.Elements[X.Length - 1]);
   call   fpc_get_output
   movl   %eax,%esi
   movl   (%ebx),%edx
   movl   4(%ebx),%eax
   movl   -4(%edx,%eax,4),%ecx
   movl   %esi,%edx
   movl   $0,%eax
   call   fpc_write_text_sint
   movl   %esi,%eax
   call   fpc_writeln_end
# [26] end;
   popl   %esi
   popl   %ebx
   ret


Где она, легковестность открытого массива? Код обеих функций PrintLast практически идентичен. Более того, так и должно быть в идеальном мире!

Причём тут дельфи-совместимость, непонятно. Я не говорю, что нужно убирать какие-то фичи или заменять их на другие в обязательном порядке, нет. Я говорю, что нужно добавлять новые фичи, дающие новые возможности в создании офигенных штук. И я говорю, в ответ на ваш комментарий «Тем что ты используешь открытый массив. Это пример, того что массивы, вещь более низкоуровневая, чем генерики. И даже если они в чём-то похожи, они всё-таки разные.», что открытый массив — это не какая-то заоблачная или глубокая или сверхнизкоуровневая концепция, находящаяся за гранью возможностей, которые предоставляют дженерики, а её вполне себе можно будет реализовать дженериком (и вполне можно было бы иметь в качестве штатного, поддержанного в RTL ортогонального к другим возможностям языка открытого массива, если бы развитие языка изначально шло с точки зрения проработки концепций, а не случайного надёргивания магии из разных мест, поддержки совместимости с Delphi и т.д.).

и RefCount-ing тоже в дженерике реализуешь? или ждём ARC паскаль?

:)

Почему динамический массив должен быть RefCounting? Потому что так его сделали в Delphi? Это не входит в концепцию динамического массива. Почему всё динамическое в языке нужно освобождать ручками, а для динамических массивов сделали особое исключение? Почему только динамические массивы пользуются такими привилегиями, а свой, автоматически освобождаемый тип сделать нельзя? (Можно, конечно… через COM-интерфейсы, т.е. через жопу). Не вижу чем динамический массив должен отличаться в этом месте от обычных объектов.

Так или иначе, повсеместный ARC, очень надеюсь, не случится, а «Management operators» уже в разработке и я их с нетерпением жду :)
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Пред.След.

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

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

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

Рейтинг@Mail.ru