Re[17]: goto
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 11.05.05 13:23
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>goto может быть практически незаменим при генерации кода.

WH>Да и в редких случаях его можно довольно красиво использовать значительно упрощая код.
WH>Например
Автор: WolfHound
Дата: 02.12.04
попробуй переписать merge_list без goto ...


Попробовал, кажется получилось красивее чем в Вашем примере с goto:
PROCEDURE Merge(a, b: Node; less: Less): Node;
  VAR head, tail: Node;
BEGIN
  IF a = NIL THEN RETURN b END;
  IF b = NIL THEN RETURN a END;
  IF less(a, b) THEN head := a; a := a.next ELSE head := b; b := b.next END;
  tail := head;
  LOOP
    IF a = NIL THEN tail.next := b; EXIT END;
    IF b = NIL THEN tail.next := a; EXIT END;
    IF less(a, b) THEN 
      tail.next := a; tail := a; a := a.next 
    ELSE 
      tail.next := b; tail := b; b := b.next
    END
  END;
  RETURN head;
END Merge;

Если вместо less(a, b): BOOLEAN использовать min(a, b): Node, то будет еще красивее.

WH>...и с одной точкой выхода из функции.


Зачем с одной точкой выхода?
Re[18]: goto
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 11.05.05 13:30
Оценка:
СГ>min(a, b): Node, то будет еще красивее.

Хотя нет, это я погорячился, нужен именно less.
Re[18]: goto
От: WolfHound  
Дата: 11.05.05 14:15
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Попробовал, кажется получилось красивее чем в Вашем примере с goto:

Что за дурацкая привычка лепить все в одну строчку?
PROCEDURE Merge(a, b: Node; less: Less): Node;
  VAR head, tail: Node;
BEGIN
    (* Это лишнее ибо эта функция не расчитана на прямое использование
    IF a = NIL THEN 
        RETURN b 
    END;
    IF b = NIL THEN 
        RETURN a 
    END;
    *)    
    (*Дублирование кода*)
    IF less(a, b) THEN 
        head := a; 
        a := a.next 
    ELSE 
        head := b; 
        b := b.next 
    END;
    tail := head;
    LOOP
        (*лишние проверки в цикле*)
        (*если на предыдущей итерации не выполнилось less(a, b)
          то это условие никогда не выполнится*)
        IF a = NIL THEN 
            tail.next := b; 
            EXIT 
        END;
        (*если на предыдущей итерации выполнилось less(a, b)
          то это условие никогда не выполнится*)
        IF b = NIL THEN 
            tail.next := a; 
            EXIT 
        END;
        IF less(a, b) THEN 
            tail.next := a; 
            tail := a; 
            a := a.next 
        ELSE 
            tail.next := b; 
            tail := b; 
            b := b.next
        END
    END;
    RETURN head;
END Merge;

Итого: лишнии проверки в цикле и два неосуществимых пути. Это не способствует ни пониманию ни производительности.

СГ>Зачем с одной точкой выхода?

Чтобы все совсем структурно было...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[19]: Шустрики и ссылки
От: vdimas Россия  
Дата: 11.05.05 15:33
Оценка: 9 (1)
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, Сергей Губанов, Вы писали:


VD>>>Не. Делать тесты ради одного человека — это уже пребор.


СГ>>Дык, а если тесты для оберонов попросить написать того человека, разьве-ж он откажется...


IT>Если попросить его, то оберон несомненно победит.




Дать исходники и попросить перевести на оОберон — вполне нормальное дело. Надо дать человеку "высказаться по существу".
Re: Снова D: Зверёк читает мануал
От: Кодт Россия  
Дата: 11.05.05 19:34
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>К слову, эта идея (избавления от "ненужных операторов") не распространена на операторы вида op= (+=, -= и т.д.). Почему? То есть, конечно, логику в этом, видимо, можно найти... Но лень.


Логика такая, что не все домены имеют обратные операции.
Если мы реализуем группу — тогда да, на каждый плюс найдётся свой минус. Но какой декремент может быть, например, для строк? str+=tail, но не str-=tail.

Кстати, хохму придумал. Почему бы не трактовать для строк a-b как b+a, и соответственно a-=b как a=a-b=b+a, то есть прибавление к началу строки?
Перекуём баги на фичи!
Re[3]: Снова D: Зверёк читает мануал
От: Кодт Россия  
Дата: 11.05.05 20:06
Оценка: +1
Здравствуйте, Зверёк Харьковский, Вы писали:

E>>Так вот в C++ мне достаточно определить только оператор "строго меньше"...


ЗХ>...что, по сути, является определением совсем другого оператора — оператора порядка, а не оператора сравнения. Ты не застрахован от удивления в клиентском коде, когда

ЗХ>
ЗХ>Compound_Key a, b;
ЗХ>if(a < b) //так можно
ЗХ>if(a > b) //а так почему-то нельзя :(
ЗХ>


ЗХ>Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<


Тут история вот какая:
1) разные отношения
— эквивалентность, которому соответствует семейство сравнений ==, !=
— порядок, которому соответствуют < > <= >= == != (т.е. эквивалентность вытекает из порядка)
Причём для введения каждого из них необходимо и достаточно определить, соответственно, равенство ( == ) и одно из строгих неравенств ( < > )
2) отношение порядка можно задавать как предикатом неравенства (X,X)->bool, так и троичной функцией-компаратором (X,X)->{-,0,+} — эти способы взаимозаменяемы
3) троичный компаратор в роли базиса — практически удобнее, чем неравенство:
— он антисимметричен (а значит, его проще и реализовывать, и использовать)
— все операторы (включая ==) определяются через одно обращение к компаратору:
— — x>y = cmp(x,y)>0; x<=y = cmp(x,y)<=0; x==y = cmp(x,y)==0
— — x<y = less(y,x); x<=y = !less(y,x); x==y = !less(x,y) && !less(y,x)
для дорогостоящих сравнений (например, строк) это может здорово аукнуться.

То, что в STL в роли базиса был взят предикат — это, возможно, упущение авторов. Хотели добиться минимализма (типа — встроенный оператор уже есть, а компаратор потребует нового имени, да ещё и заморочек с ADL). И устроили головную боль пользователям. Хотя в этом есть некое изящество: если операторы < и > определены и согласованы, то смена направления сортировки достигается заменой less<T> на greater<T> (определённые через операторы).
Перекуём баги на фичи!
Re[4]: Снова D: Зверёк читает мануал
От: Зверёк Харьковский  
Дата: 11.05.05 22:49
Оценка:
Здравствуйте, Кодт, Вы писали:

ЗХ>>Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<


К>Тут история вот какая:

К>1) разные отношения
К>- эквивалентность, которому соответствует семейство сравнений ==, !=
К>- порядок, которому соответствуют < > <= >= == != (т.е. эквивалентность вытекает из порядка)
К>Причём для введения каждого из них необходимо и достаточно определить, соответственно, равенство ( == ) и одно из строгих неравенств ( < > )
К>2) отношение порядка можно задавать как предикатом неравенства (X,X)->bool, так и троичной функцией-компаратором (X,X)->{-,0,+} — эти способы взаимозаменяемы
К>3) троичный компаратор в роли базиса — практически удобнее, чем неравенство:
К>- он антисимметричен (а значит, его проще и реализовывать, и использовать)
К>- все операторы (включая ==) определяются через одно обращение к компаратору:
К>- — x>y = cmp(x,y)>0; x<=y = cmp(x,y)<=0; x==y = cmp(x,y)==0
К>- — x<y = less(y,x); x<=y = !less(y,x); x==y = !less(x,y) && !less(y,x)
К>для дорогостоящих сравнений (например, строк) это может здорово аукнуться.

К>То, что в STL в роли базиса был взят предикат — это, возможно, упущение авторов. Хотели добиться минимализма (типа — встроенный оператор уже есть, а компаратор потребует нового имени, да ещё и заморочек с ADL). И устроили головную боль пользователям. Хотя в этом есть некое изящество: если операторы < и > определены и согласованы, то смена направления сортировки достигается заменой less<T> на greater<T> (определённые через операторы).


Наблюдение верное. И даже в некоторой мере очевидное. Но тут есть еще 2 фактора:
1) как-никак, компаратор редко удается изящно написать. В этой ветке приводилось достаточно примеров того, насколько неизящен унутре этот самый компаратор.
2) иногда (часто?) между объектами типа определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай). Соответственно, получится либо "частично определенный" компаратор (который возвращает либо 0 либо не 0), что опять же может запутать юзера; либо два оператора — компаратор и равенство (как собственно и сделано в D, имеющем opEqual и opCmp), что уже несколько дискредитирует всю задумку.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[2]: Снова D: Зверёк читает мануал
От: Зверёк Харьковский  
Дата: 11.05.05 22:49
Оценка:
Здравствуйте, Кодт, Вы писали:

ЗХ>>К слову, эта идея (избавления от "ненужных операторов") не распространена на операторы вида op= (+=, -= и т.д.). Почему? То есть, конечно, логику в этом, видимо, можно найти... Но лень.


К>Логика такая, что не все домены имеют обратные операции.

К>Если мы реализуем группу — тогда да, на каждый плюс найдётся свой минус. Но какой декремент может быть, например, для строк? str+=tail, но не str-=tail.

К>Кстати, хохму придумал. Почему бы не трактовать для строк a-b как b+a, и соответственно a-=b как a=a-b=b+a, то есть прибавление к началу строки?


Я не то имел в виду, когда говорил об избавлении от ненужных операторов. Слияние не operator+ и operator-, а operator+ и operator+=
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[16]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
От: vdimas Россия  
Дата: 11.05.05 23:49
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Про управление памятью я уже говорил. Отсуствие ЖЦ — это конечно недостаток, но управление памятью в Дельфи отнимало не бьльше чем при пронраммировании на С++. Умные указатели и т.п. — это все костыли.


Умный указатель, это "заместитель" по GoF. Все паттерны по сути — костыли, они же трюки и приемчики.

Управление памятью в Дельфи отнимает не больше чем в С++ только в GUI. И там и там оно вообще ничего не отнимает ибо много чего берет на себя библиотека и явно их вызывать почти никогда не нужно. Если же речь шла об активном динамическом создании/удалении объектов, то в дельфи — это приличный объем кода на ровном месте (писал когда-то на Дельфи иерарахические структуры описаний графических примитивов — то еще удовольствие ).
Re[17]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
От: vdimas Россия  
Дата: 11.05.05 23:57
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>VB6 использовался (да и сейчас используется) для простых

C>GUI-интерфейсов. В бизнес-логике VB6 я чего-то не встречал.

Да не, "там" очччень дохрена на VB/VBA всякого понаписано. Ситуация с бизнес-приложениями в тех же штатах вообще комическая с нашей т.з. Там или откровенные примитивы типа QuickBook, или сразу монстры типа SAP. Весь промежуточный провал — кто во что горазд. У нас в этой нише прочно сидит 1С, это на порядок более качественное решение чем весь тот сброд, что существует у них (по большей части на VB писанный, и сервера приложений в т.ч !!!). Дотнет, кстати, весьма неплохо подходит как раз для заполнения этой ниши, предоставляя единообразный масштабируемый фреймворк для всех уровней.

C>Мне не очень понятна, например, в отношении C++Builder'а.


Это вообще старый и больной вопрос. До сих пор считаю, что ставка на ObjectPascal была ошибочной. Им стоило двигать в визуальном-виндовом направлении свой С++, который был одним из лучших на то время. Расстановка сил на данный момент могла бы быть несколько другой.
Re[12]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
От: vdimas Россия  
Дата: 12.05.05 00:04
Оценка: +5
Здравствуйте, Сергей Губанов, Вы писали:

СГ>2) Не замучаетесь на каждый чих писать все новые и новые аналоги классов ResGuard (лишние сущности)? Использование структурной конструкции finally избавляет от этой лишней писанины и структурирует программу.


Это зависит от того, на какую глубину ты способен структурироваться.

Обычное дело:
создать ресурс №1.
использовать ресурс №1.
проверить условие.
создать ресурс №2.
использовать ресурс №2.
проверить условие.
создать ресурс №3.
использовать ресурс №3.
проверить условие.
создать ресурс №4.
использовать ресурс №4.
проверить условие.


и т.д., порой получается большой итоговый №.

Со всякими scope-контоллерами подобные алгоритмы не представляют трудностей, записываются "как под диктовку". В случае try-finally мы должны либо городить новый уровень вложенности на каждый №, либо усложнять блок finally, проверяя, что мы успели создать, а что нет. Получаем скорее деструктуризацию, чем структуризацию.
Re[18]: Шустрики и ссылки
От: VladD2 Российская Империя www.nemerle.org
Дата: 12.05.05 01:37
Оценка: +1
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Дык, а если тесты для оберонов попросить написать того человека, разьве-ж он откажется...


Ловлю на слове.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
От: IT Россия linq2db.com
Дата: 12.05.05 02:28
Оценка: +1
Здравствуйте, vdimas, Вы писали:

V>Да не, "там" очччень дохрена на VB/VBA всякого понаписано. Ситуация с бизнес-приложениями в тех же штатах вообще комическая с нашей т.з. Там или откровенные примитивы типа QuickBook, или сразу монстры типа SAP. Весь промежуточный провал — кто во что горазд. У нас в этой нише прочно сидит 1С, это на порядок более качественное решение чем весь тот сброд, что существует у них (по большей части на VB писанный, и сервера приложений в т.ч !!!).


Джавы у них много на серверах, гораздо больше чем VB.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[19]: goto
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 12.05.05 07:17
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Что за дурацкая привычка лепить все в одну строчку?


Это не дурацкая привычка.
Вы
же
не
пишите
по
одному
слову
на
одной
строчке,
а пишите так как удобнее читать.

WH>Итого: лишнии проверки в цикле и два неосуществимых пути. Это не способствует ни пониманию ни производительности.


Не могу с Вами согласиться.
Эффективная реализации процедуры less, может быть, например, такой:
  PROCEDURE NodeLess(a, b: Node): BOOLEAN;
  BEGIN
    RETURN a.key < b.key
  END NodeLess;

т.е. внутри нее a и b не проверяются на неравенство NIL.
Отсюда следует, что прежде чем вызвать less(a, b) надо быть точно уверенным, что ни a ни b не равны NIL.

(a # NIL) & (b # NIL) — предусловие вызова less(a, b).

Стало быть цикл:
  LOOP
    IF a = NIL THEN tail.next := b; EXIT END;
    IF b = NIL THEN tail.next := a; EXIT END;
    IF less(a, b) THEN 
      tail.next := a; tail := a; a := a.next 
    ELSE 
      tail.next := b; tail := b; b := b.next
    END
  END;

написан правильно, нет ни одной лишней проверки, и нет неосуществляемых путей.

1) less(a, b) вызывается только тогда когда (a # NIL) & (b # NIL) = TRUE
2) Оба пути в IF равновероятны на случайных данных.
Re[13]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 12.05.05 07:28
Оценка:
Здравствуйте, vdimas, Вы писали:

V>...либо усложнять блок finally, проверяя, что мы успели создать, а что нет...


Вы правы, но наполовину. Дело в том, что проверить перед уничтожением объекта был ли он создан, вообще-то, еще ни кому ни когда не вредило в любом случае, не зависимо от того есть finally или нет его.
Re[5]: Снова D: Зверёк читает мануал
От: Кодт Россия  
Дата: 12.05.05 07:37
Оценка: +1
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>Наблюдение верное. И даже в некоторой мере очевидное. Но тут есть еще 2 фактора:

ЗХ>1) как-никак, компаратор редко удается изящно написать. В этой ветке приводилось достаточно примеров того, насколько неизящен унутре этот самый компаратор.

Предикат — ещё менее изящен
Например, поэлементное (в т.ч. лексикографическое) сравнение выглядит так
int cmp(A a, A b)
{
  int c;
  c = cmp(a.x, b.x); if(c) return c;
  c = cmp(a.y, b.y); if(c) return c;
  ...
  return 0;
}

bool less(A a, A b)
{
  if(less(a.x, b.x)) return true; if(less(b.x, a.x)) return false;
  if(less(a.y, b.y)) return true; if(less(b.y, a.y)) return false;
  ...
  return false;
}


ЗХ>2) иногда (часто?) между объектами типа определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай).


Как это?! Если есть порядок, то автоматически есть и равенство.
Другое дело, что можно ввести несколько разных равенств/порядков (пример для строк: порядки с учётом регистра, без учёта регистра, по созвучию, по контрольной сумме).
В этом случае необходимо и достаточно определить внешние функции/функторы.

ЗХ>Соответственно, получится либо "частично определенный" компаратор (который возвращает либо 0 либо не 0), что опять же может запутать юзера; либо два оператора — компаратор и равенство (как собственно и сделано в D, имеющем opEqual и opCmp), что уже несколько дискредитирует всю задумку.


Задумку дискредитирует то, что
— в С++ операторы между собой не связаны
— а в D, где связь есть, не пошли до конца (скажем, могли потребовать: если определён opCmp, то opEqual определяется автоматически и не подлежит перекрытию)
Перекуём баги на фичи!
Re[20]: goto
От: WolfHound  
Дата: 12.05.05 07:45
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Это не дурацкая привычка.

СГ>Вы же не пишите по одному слову на одной строчке, а пишите так как удобнее читать.
Не надо путать естественные языки и языки программирования.

СГ>Не могу с Вами согласиться.

А придется.
СГ>Эффективная реализации процедуры less, может быть, например, такой:
Это не имеет значения.
СГ>Отсюда следует, что прежде чем вызвать less(a, b) надо быть точно уверенным, что ни a ни b не равны NIL.
Условия вызова исходной функции таковы что на вход всегда подаются коректные, отсортированые списки состоящие хотябы из одного элемента.

СГ>Стало быть цикл:

СГ>
СГ>  LOOP
СГ>    IF a = NIL THEN tail.next := b; EXIT END;
СГ>    IF b = NIL THEN tail.next := a; EXIT END;
СГ>    IF less(a, b) THEN 
СГ>      tail.next := a; tail := a; a := a.next 
СГ>    ELSE 
СГ>      tail.next := b; tail := b; b := b.next
СГ>    END
СГ>  END;
СГ>

СГ>написан правильно,
Правильно но не эффективно.
Разберем его.
Допустим в начале цикла списки a и b содержат элементы.
Те ни одно из условий
    IF a = NIL THEN tail.next := b; EXIT END;
    IF b = NIL THEN tail.next := a; EXIT END;

не выполнится.
Далие происходит проверка
    IF less(a, b) THEN

Теперь если это условие выполнилось то мы из списка a забираем один элемент при этом мы не модифицируем список b.
Далие переходим на начало списка. Так как мы не меняли список b то условие
    IF b = NIL THEN tail.next := a; EXIT END;

гарантировано не выполнится.
Вот вам один неосуществимый путь и одна лишняя проверка.

Тоже самое касается другого списка.
СГ>нет ни одной лишней проверки, и нет неосуществляемых путей.
Почемуто в моей реализацие на одну проверку в цикле меньше.

СГ>1) less(a, b) вызывается только тогда когда (a # NIL) & (b # NIL) = TRUE

СГ>2) Оба пути в IF равновероятны на случайных данных.
В этом цикле не два, а 6 путей из которых 2 невозможны.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[14]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
От: WolfHound  
Дата: 12.05.05 07:51
Оценка: +2
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Вы правы, но наполовину. Дело в том, что проверить перед уничтожением объекта был ли он создан, вообще-то, еще ни кому ни когда не вредило в любом случае, не зависимо от того есть finally или нет его.

Эта проврека пишется один раз в деструкторе.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Снова D: Зверёк читает мануал
От: Кодт Россия  
Дата: 12.05.05 07:56
Оценка: +1
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>Я не то имел в виду, когда говорил об избавлении от ненужных операторов. Слияние не operator+ и operator-, а operator+ и operator+=


Это опять накладывает ненужные ограничения. А именно, требует, чтобы тип результата был равен типу левого операнда.
L& operator += (      L& lhs, const R& rhs) { lhs = lhs + rhs;         return lhs; }
L  operator +  (const L& lhs, const R& rhs) { L res = lhs; res += rhs; return res; }

Самый сильный пример того, где это мешает — boost::spirit, где можно складывать унарные функции и скаляры, порождая новые унарные функции.
Перекуём баги на фичи!
Re[21]: goto
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 12.05.05 08:07
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Вот вам один неосуществимый путь и одна лишняя проверка.


дошло...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.