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

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

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

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

Сообщение sign » 23.06.2016 07:29:47

dedm0zaj писал(а):
скалогрыз писал(а):а ещё я нелюблю генерики

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

Я делаю так и не имею никаких проблем.
Когда несколько типов, то накопипастить их - дело минут.

Код: Выделить всё
  TMyList = class(TList)
  private
    function GetItems(Index: Integer): TMyType;
    procedure PutItems(Index: Integer; AValue: TMyType);
  public
    property Items[Index: Integer]: TMyType read GetItems write PutItems; default;
  end;

function TMyList.GetItems(Index: Integer): TMyType;
begin
  if (Index >= 0) and (Index < Count) then Result:= TMyType(inherited Items[Index])
  else Result := nil;
end;   
sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

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

Сообщение dedm0zaj » 23.06.2016 07:38:11

скалогрыз писал(а):Ручное копирование в этом случае лучше, т.к. код для конкретного типа изолирован от других типов,


изолированность это хорошо. но копировать по сто раз мелкие изменения - ведь жесть. и в итоге может закрасться ошибка, что один из вариантов откорректирован неверно.
менять и отлаживать такое как по мне сложнее.

с другой стороны сишные шаблоны тоже начинают показывать чудеса, когда под универсальную какую нить функцию запихивают все типы подряд, приплетая переопределения операций.

в общем в шаблонах/генериках не вижу ничего плохого, но в меру.
dedm0zaj
постоялец
 
Сообщения: 108
Зарегистрирован: 05.10.2012 19:55:20

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

Сообщение скалогрыз » 23.06.2016 18:33:35

sign писал(а):Я делаю так и не имею никаких проблем.
Когда несколько типов, то накопипастить их - дело минут.

а ещё, в эти дни, можно сделать TypeHelper, который избавит от наследования и сохранит точечную нотацию.

А для неточечной нотации, можно использовать (если не лень), inline функции.

dedm0zaj писал(а):менять и отлаживать такое как по мне сложнее.

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

dedm0zaj писал(а):в общем в шаблонах/генериках не вижу ничего плохого, но в меру.

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

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

Сообщение Лекс Айрин » 23.06.2016 18:47:31

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

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

Сообщение скалогрыз » 23.06.2016 18:57:52

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

Javascript? ему это всё не нужно, потому что типизация не строгая :mrgreen: Ведь все эти вещи это последствие строгой типизации.

Замечу, что ассебмлер не выглядит как китайщина, по сравнению с Си, т.к. в ассемблере использование символом весьма и весьма ограничено.
пишут
Код: Выделить всё
mov A, B

а не
Код: Выделить всё
=> A, B

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

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

Сообщение Лекс Айрин » 23.06.2016 20:26:21

скалогрыз писал(а):Javascript?


Не в обиду будет сказано, но ява скрипт это НЕ язык как таковой.

скалогрыз писал(а):Замечу, что ассебмлер не выглядит как китайщина, по сравнению с Си,


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

скалогрыз писал(а):пишут

Код: mov A, B

а не
Код: => A, B


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

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

Сообщение Mirage » 24.06.2016 00:03:45

Дублирование кода - зло. Дублирование исходного кода - зло в квадрате. Ибо количество ошибок зависит от количества исходного кода. Дублирование компилятором не привнесет новых ошибок (не рассматриваем реализацию дженериков от Ембаркадеро), в отличии от дублирования исходного кода.
Кстати, компилятор может сообразить, что дублировать нужно далеко не всегда. Ну собственно пример с массивами уже тут приводили. С обобщенными классами, в принципе, тоже самое.

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


Да есть такой. Тут большинство на нем как раз и пишут. Небольшое изменение в одной конструкции и дженерики не нужны. И никаких угловых скобок.
Зачем копировали тупо из C# непонятно...
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

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

Сообщение скалогрыз » 24.06.2016 00:33:56

Mirage писал(а):Кстати, компилятор может сообразить, что дублировать нужно далеко не всегда. Ну собственно пример с массивами уже тут приводили. С обобщенными классами, в принципе, тоже самое.

А ещё интересн вопрос поддержки Generic-ов, отладчиком.

Один и тот же кусок текстового кода, используется разным бинарным кодом. Причём c разными типами данных.
И об это нужно как-то сообщить компилятору.
Вот уж не знаю насчёт Dwarf-а (там-то поддержка этих вещей должна быть, вопрос только с реализацией в FPC), но вот в stabs её точно нет.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Лекс Айрин » 24.06.2016 09:16:05

скалогрыз писал(а):Один и тот же кусок текстового кода, используется разным бинарным кодом. Причём c разными типами данных.
И об это нужно как-то сообщить компилятору.


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

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

Сообщение Дож » 29.06.2016 18:24:08

скалогрыз писал(а):Вот хорошо в паскале получилось с массивами. По сути своей они как бы дженерики, но объём кода при этом не увеличивается, т.к. методы работы с массивом (например изменить размер), завязан на размере элемента. Т.е. вроде бы и дженерик, а дубляжа кода (на бинарном уровне) нет.


Кому, кстати, за массивы спасибо говорить? Borland'у за введение их в Delphi? А то я так думаю, что не будь их изначально в дельфи, в FPC никогда ничего такого самостоятельно не сделали бы, и мы бы до сих пор использовали замечательные конструкции ^array[0..1] of TElement, GetMem(A, SizeOf(TElement)*L) и FreeMem(A).

(Во всяком случае, для невероятно частых операций «добавить элемент в массив» и «обратиться к последнему элементу массива» до сих пор нет удобных конструкций, приходится для каждого инстанса массивов вручную фигачить связки (SetLength(Length+1) и A[High(A)] соотвественно), потому что «так лучше читается».)

Особенно комично было бы, если бы в альтернативной реальности без нативных динамических массивов я на форуме высказывался в поддержку их введения в язык или хотя бы дженериков для самостоятельной реализации, объяснял бы, что с GetMem/FreeMem жить невыносимо и это прошлый век, а мне бы отвечали что-нибудь вроде «Не нужны динамические массивы, паскаль — это вам не Java! Код пишется для того, чтобы его читать, а не быстро писать! С динамическими массивами код разбухает, оно нам надо?».

Минутка псевдокода для самостоятельных размышлений:
Код: Выделить всё
type
TArrayOfImpl = object
private
  FElementSize: LongInt;
  procedure Init(ElementSize: LongInt);
  function Add: Pointer;
  ...
end;

generic TArrayOf<T> = object
private
  FImpl: TArrayOfImpl;
public
  procedure Init; inline;
  procedure Add(const Value: T); inline;
  ...
end;

...

procedure TArrayOf.Init;
begin
  FImpl.Init(SizeOf(T));
end;

procedure TArrayOf.Add(const Value: T);
begin
  T(FImpl.Add^) := Value;
end;


скалогрыз писал(а):И читая maillist, я как-то обратил внимание, что люди стали клянчить для дженериков удивительные вещи.
Нужно знать тип специализации и в коде знание о типе использовать, чтобы к большему виду типов можно было было дженерик прикрутить.
Вроде такого получается
Код: Выделить всё
  if T is String  then Result := a + a
  else if T is Integer then  Result := a * a
  else if T is Record then // do nothing
  else if T is ...

ну и т.д.
Получается исходник самого дженерика, расплывается с конкретной реализацией всех типов. И хочется задать вопрос - и в чём в итоге преимущество, перед ручным копированием, если в дженерике оказывается тот же самый код?! Ручное копирование в этом случае лучше, т.к. код для конкретного типа изолирован от других типов, его легче воспринимать, менять и отлаживать


Это не такая уж удивительная вещь, её можно решить введением так называемой «частичной специализацией дженерика», по назначению похожей на «перегрузку функций с различными параметрами». Безусловно, предложенное решение через if'ы со знанием о дженериках в рантайме — это ужасно.

Минутка псевдокода:
Код: Выделить всё
generic TArrayOf<T: class> = object(specialize TArrayOf<T>)
public
  function Last: T; inline;
end;

generic TArrayOf<T: object> = object(specialize TArrayOf<T>)
public type
  P = ^T;
public
  function Last: P; inline;
end;


А ещё интересн вопрос поддержки Generic-ов, отладчиком.

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

Для дебаггера нужно отображение «машинная инструкция -> строчка в исходнике», а не наоборот, так что не очень понятно почему это должно быть проблемой.

Причём c разными типами данных.

Какая связь между отладчиком и типами данных в исходном коде (т.е. некоторой языковой абстракцией)? Я бы ещё понял, если бы отладчики умели сами, независимо от FPC читать исходники, и по ним реконструировать данные, но это ведь (наверняка) не так. Отладчику гораздо важнее по заданной инструкции машинного кода знать какие переменные и данные видны вокруг — это знание должно быть передано компилятором, да.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

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

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

Дож писал(а):Кому, кстати, за массивы спасибо говорить? Borland'у за введение их в Delphi

хз, каким авторам языков высокого уровня. Конструкция "массив каких-либо данных". Изначально такой "дженерик" был во всех языках.
Но Борланд действительно, сделали массивы динамическими.

Дож писал(а):а мне бы отвечали что-нибудь вроде «Не нужны динамические массивы, паскаль — это вам не Java! Код пишется для того, чтобы его читать, а не быстро писать! С динамическими массивами код разбухает, оно нам надо?»

И я уверен, что такие аргументы были, в среде old-school паскалистов. И скорей всего такой код, где используеются New / Dispose / GetMem :) всё ещё существует и даже используется.
Не нужно забывать, что динамические массивы несут с собой нагрузку в виде ref-counting-а, и вообще это managed тип. Т.е. динамеческий массив противен тем, кто привык всё делать руками :)

Дож писал(а):Безусловно, предложенное решение через if'ы со знанием о дженериках в рантайме — это ужасно.

Не. Там именно что в компайл тайме все IF-ы разруливаются. Ран-тайм не страдает. Это ужасно с точки зрения поддержки исходного кода.

Дож писал(а):Для дебаггера нужно отображение «машинная инструкция -> строчка в исходнике», а не наоборот, так что не очень понятно почему это должно быть проблемой.
...
Какая связь между отладчиком и типами данных в исходном коде (т.е. некоторой языковой абстракцией)?

Бряк поинты часто ставятся на основне "строчка в исходнике -> машинная инструкция".
Получается что если где-то в коде генерика поставить брякпоинт, то останавливатся должна каждая специализация.
Что в принципе терпимо, но может быть и не приятно, в том случае, если отлаживается код, где один генерик специализирован много раз. (Что кстати и должно происходить)

(Нечто подобное возникает при попытке Step-In, когда есть бряк-поинт в одной из функций, которые должны вычислить значение параметров для функции в которую Step-in и происходит. Программа остановится на бряк-поинте ещё не достингнув начальной точки процедуры.)
---------
Вынесу отдельно, т.к. прикладная часть
Дож писал(а):Во всяком случае, для невероятно частых операций «добавить элемент в массив» и «обратиться к последнему элементу массива» до сих пор нет удобных конструкций, приходится для каждого инстанса массивов вручную фигачить связки (SetLength(Length+1) и A[High(A)] соотвественно), потому что «так лучше читается».

* SetLength(length+1) - медленное зло. Нужно завести отдельную Count переменную (для логического размера), а физический размер экспоненциально увеличивать. :)
* А я использую A[ length(a)-1] :)
Вопрос: в каких алгоритмах нужно получить "последний элемент массива"?
И как должна вести себя такая функция, в том случае, если массив пуст? (runtime error? false? exception? дефолтное значение?)

Если рассматривать динамический массив, как низкоуровневую структуру, тогда нужно использовать TList. И его Последний элемент.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Лекс Айрин » 29.06.2016 19:09:21

скалогрыз писал(а):Вопрос: в каких алгоритмах нужно получить "последний элемент массива"?


например, в буфере клавиатуры, очереди сообщений... применений море.

скалогрыз писал(а):И как должна вести себя такая функция, в том случае, если массив пуст? (runtime error? false? exception? дефолтное значение?)


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

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

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

Лекс Айрин писал(а):тут два варианта... либо возвращает Nil, либо ждет появления данных

Мне кажется ты подошёл со практических алгоритмов, тогда как вопрос был про некую функцию возвращение последнего элемента массива.

В частности:
nil не прокатит, т.к. в массиве могут хранится далеко не поинтеры, а какие-нить Integer-ы.
"ждать" тоже неудобно в однопоточном приложении. (каких-то данных из неоткуда)

Добавлено спустя 3 минуты 40 секунд:
Лекс Айрин писал(а):например, в буфере клавиатуры, очереди сообщений... применений море

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

Т.е. ценность функции "взять последний элемент" чуток сомнительна, потому что непосредственно перед взятием проверяется размер массива. И доступ к последнему элементу, превращается в обращение по индексу.
Как мне кажется, её можно добавить в RTL, но в реализации её не будут использовать по следующим причинам:
* функции самой придётся дополнительно проверять размер массива. Хотя у алгоритма эта информация наверняка имеется
* функция не сможет правильно разрулить ситуации, когда размер неизвествен. Например массив передан как:
Код: Выделить всё
type
  TElemArray = array [0..0] of TElem;
  PElemArray = ^PElemArray;

procedure DoStuff(p: PElemArray; size: integer);
var
  l : TElem;
begin
  l := last( p^ );   // вернёт p^[0]  ... всегда!
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Дож » 29.06.2016 19:28:13

SetLength(length+1) - медленное зло. Нужно завести отдельную Count переменную (для логического размера), а физический размер экспоненциально увеличивать.

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

И я уверен, что такие аргументы были, в среде old-school паскалистов. И скорей всего такой код, где используеются New / Dispose / GetMem :) всё ещё существует и даже используется.

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

Бряк поинты часто ставятся на основне "строчка в исходнике -> машинная инструкция".
Получается что если где-то в коде генерика поставить брякпоинт, то останавливатся должна каждая специализация.
Что в принципе терпимо, но может быть и не приятно, в том случае, если отлаживается код, где один генерик специализирован много раз. (Что кстати и должно происходить)

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

Вопрос: в каких алгоритмах нужно получить "последний элемент массива"?

В тех, где у вас используется A[ length(a)-1]

Ну, допустим, мне было бы удобно писать как-то так:
Код: Выделить всё
Arr.Add(TObj.Create);
Arr.Last.Foo := Bar;

вместо ненужной шелухи про SetLength и Length.

И как должна вести себя такая функция, в том случае, если массив пуст? (runtime error? false? exception? дефолтное значение?)

Как должна вести себя A[ length(a)-1] для пустого массива?

Этот вопрос должен мне продемонстрировать неудачность идеи метода Last, потому что есть несколько вариантов её реализации? Так не демонстрирует же. Или что? Какой ответ от меня ожидается? Ну, я могу сказать, что чисто из логических соображений этот метод не должен использоваться в корректной программе, Range Checking в рантайме не нужен, пусть будет UB. Сейчас мы можем написать A[I] для несуществующего индекса I, программа может свалиться, а может не свалиться в зависимости от неизвестных обстоятельств, и это не является какой-то серьёзной проблемой.

Добавлено спустя 5 минут 6 секунд:
скалогрыз писал(а):* функции самой придётся дополнительно проверять размер массива. Хотя у алгоритма эта информация наверняка имеется

Безусловно, так было и так должно быть.

* функция не сможет правильно разрулить ситуации, когда размер неизвествен. Например массив передан как:
Код: Выделить всё
type
  TElemArray = array [0..0] of TElem;
  PElemArray = ^PElemArray;

procedure DoStuff(p: PElemArray; size: integer);
var
  l : TElem;
begin
  l := last( p^ );   // вернёт p^[0]  ... всегда!

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

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

Сообщение Лекс Айрин » 29.06.2016 19:35:49

скалогрыз писал(а):В частности:
nil не прокатит, т.к. в массиве могут хранится далеко не поинтеры, а какие-нить Integer-ы.


тогда проще возвратить гарантированно неиспользуемое число. Ну или проверить предварительно есть ли что в этой самой очереди. Когда я это продумывал, правда для многопоточного приложения, то проще было бы использовать стоп и эррор записи (объекты). Оба роняют поток, но с разными спецэффектами.

скалогрыз писал(а):Опять же, в обоих примерах, алгоритм используется лишь как хранилище.


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

Пред.След.

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

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

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

Рейтинг@Mail.ru