Re[3]: Inline records
От: Pavel Dvorkin Россия  
Дата: 13.10.09 07:38
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Для дальнейшего я буду использовать шарп, но аналогичные грабли есть и в твоих любимых плюсах.

S>Сравним следующие две строки:
S>
S>int a, b;
S>a = GetSomeInt();
S>GetSomeInt(out b); // в плюсах был бы соответственно &b
S>

S>Одинакова ли семантика первой и второй строчки? Нет, неодинакова. а получает значение ровно один раз, а в b происходит неопределённое количество присваиваний.

Расшифруй , пожалуйста, фразу, ввиду того, что она просто непонятна сама по себе. Что значит "в b происходит неопределённое количество присваиваний" ? В b вообще ничего не может происходить, это не код. Или ты хочешь сказать, что b здесь присваивание происходит несколько раз ? Тогда почему ?

void Func(char& p)
{
p = 'a';
}

char p;
Func(p);

Где второе присваивание p ? При вызове передается адрес, а не значение. Внутри присваивание. Больше ничего.

S>Это может играть важную роль в тех случаях, когда аргумент в процессе действия GetSomeInt изменяется еще где-то.


А если а во время a = GetSomeInt(); тоже где-то меняется ? В чем разница ? Кстати, как это они меняются в однопоточном приложении или кто им позволил без синхронизации меняться в многопоточном ?

S>И, как следствие, мы имеем разные ограничения на безопасность типов. Для a мы можем применить любой тип, совместимый по присваиванию с int, например — double.


А это уже просто специфика операции присваивания, которая прямого отношения к вызову функции не имеет . Вызов функции сам по себе, а дальше присваивание, а там правила совместимости типов

float f;
int i;

f = i; // так же можно писать ?
f = SomeIntFunc(i); // ну и так можно по той же причине
With best regards
Pavel Dvorkin
Re[4]: Inline records
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.10.09 08:12
Оценка: +1 -1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Расшифруй , пожалуйста, фразу, ввиду того, что она просто непонятна сама по себе. Что значит "в b происходит неопределённое количество присваиваний" ? В b вообще ничего не может происходить, это не код. Или ты хочешь сказать, что b здесь присваивание происходит несколько раз ? Тогда почему ?


PD>void Func(char& p)

PD>{
PD> p = 'a';
PD>}

PD>char p;

PD>Func(p);

PD>Где второе присваивание p ? При вызове передается адрес, а не значение. Внутри присваивание. Больше ничего.


Даже если одно, то функция может наследить в том числе сразу за p, или перед p. А в случае char p = Func(), это не грозит.

PD>А если а во время a = GetSomeInt(); тоже где-то меняется ? В чем разница ? Кстати, как это они меняются в однопоточном приложении или кто им позволил без синхронизации меняться в многопоточном ?

Где написано что приложение однопоточное? Да и речь идет о семантике вызова, а не о том, есть ли там синхронизация. Семантика разная, в этом Sinclair прав!
Re[4]: Inline records
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.10.09 08:25
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>Где второе присваивание p ?

Неужто сам не догадываешься?
Ок, показываю (следи за руками):
void Func(int &sum, int start, int end)
{
  for(int i=start; i<end; i++)
    sum*= i;
}

Сколько раз присваивается sum? Заметь, кстати, что компилятор C#, в отличие от C++, отличает ref от out — для последнего он требует определяющего присванивания. Т.е. мы не знаем точно, сколько раз присваивается sum, но знаем, что не меньше одного:
void Func(out int sum, int start, int end)
{
  sum=start; // тут опять тонкости definite assignment, связанные с out - компилятор не даёт программисту полагаться на начальное значение этого параметра
  for(int i=start; i<end; i++)
    sum*= i;
}


PD>А если а во время a = GetSomeInt(); тоже где-то меняется ? В чем разница ?

В том, что язык не даёт GetSomeInt читать промежуточные значения a в процессе работы. То есть тело GetSomeInt изолировано от a.

PD>Кстати, как это они меняются в однопоточном приложении или кто им позволил без синхронизации меняться в многопоточном?

Элементарно они меняются. Допустим, эта функция вызывает callback. А тело callback уже запросто в том же потоке меняет a непредсказуемым образом.

Про другой поток я и не говорю — тело функции Func никак не может узнать, нужно ли синхронизировать доступ к sum и если нужно, то как. Потому что sum может быть псевдонимом для локальной переменной на стеке конкретного потока, для поля объекта в динамически распределённой памяти, или вообще для глобальной статической переменной.
Поэтому типобезопасность требует точного соответствия типа алиаса и типа фактического аргумента.

PD>А это уже просто специфика операции присваивания, которая прямого отношения к вызову функции не имеет . Вызов функции сам по себе, а дальше присваивание, а там правила совместимости типов


PD>float f;

PD>int i;

PD>f = i; // так же можно писать ?

PD>f = SomeIntFunc(i); // ну и так можно по той же причине
в том то и дело. Писать f = SomeIntFunc(i) — можно. А вот так — тебе не даст компилятор (насколько я помню C++):
SomeIntFunc(i, &f)

При условии, что функция определена вот таким образом:
void SomeIntFunc(int a, int &b)
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Inline records
От: Pavel Dvorkin Россия  
Дата: 13.10.09 08:26
Оценка: :)
Здравствуйте, samius, Вы писали:


S>Даже если одно, то функция может наследить в том числе сразу за p, или перед p. А в случае char p = Func(), это не грозит.


Можно чуть точнее ? Перед p — это где, до вызова ? До этого мне дела нет, меня не интересует, чему равен p до вызова вообще. После вызова ? Поезд ушел, пишите письма.

PD>>А если а во время a = GetSomeInt(); тоже где-то меняется ? В чем разница ? Кстати, как это они меняются в однопоточном приложении или кто им позволил без синхронизации меняться в многопоточном ?

S>Где написано что приложение однопоточное? Да и речь идет о семантике вызова, а не о том, есть ли там синхронизация. Семантика разная, в этом Sinclair прав!

Семантика , может, немного и отличается, но меня интересуют исключительно практические различия, а их практически нет . Проще говоря, я не вижу чем

(int a, float b) F()

мне может быть полезнее чем

void F(int&a, float&b)
With best regards
Pavel Dvorkin
Re[6]: Inline records
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.10.09 08:57
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, samius, Вы писали:



S>>Даже если одно, то функция может наследить в том числе сразу за p, или перед p. А в случае char p = Func(), это не грозит.


PD>Можно чуть точнее ? Перед p — это где, до вызова ? До этого мне дела нет, меня не интересует, чему равен p до вызова вообще. После вызова ? Поезд ушел, пишите письма.

Перед p — это по отрицательному смещению относительно адреса p. Но ключевое тут может курсивом. В здравом уме никто так делать не станет, но с другой стороны, никто и не запретит.

PD>Семантика , может, немного и отличается, но меня интересуют исключительно практические различия, а их практически нет . Проще говоря, я не вижу чем


PD>(int a, float b) F()


PD>мне может быть полезнее чем


PD>void F(int&a, float&b)


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

Если программист по сути одиночка, то он сам расставляет мины, сам их и обходит и ни на что не жалуется. Если в команде присутствуют люди, которые не способны постичь далеко идущий высший замысел, то это обычно и приносит проблемы.
Re[7]: Inline records
От: Pavel Dvorkin Россия  
Дата: 13.10.09 09:07
Оценка:
Здравствуйте, samius, Вы писали:

PD>>Можно чуть точнее ? Перед p — это где, до вызова ? До этого мне дела нет, меня не интересует, чему равен p до вызова вообще. После вызова ? Поезд ушел, пишите письма.

S>Перед p — это по отрицательному смещению относительно адреса p.

А мне какое дело до этого ? Если при этом p не перекрывается — на здоровье. Если перекрывается — нечего ерундой заниматься.

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


Не запретит. Ерундой заниматься никто не запрещает, но это многими способами можно сделать


PD>>(int a, float b) F()


PD>>мне может быть полезнее чем


PD>>void F(int&a, float&b)


S>Вызвав такой метод очень легко что-нибудь где-нибудь испортить, особенно если переменные лежат не на стеке.


Какой ? Второй ? Ничего тут испортить нельзя. Если, конечно, не брать там указатели и не гонять их как попало. Но так можно везде испортить.
With best regards
Pavel Dvorkin
Re[8]: Inline records
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.10.09 09:11
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, samius, Вы писали:


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


PD>Не запретит. Ерундой заниматься никто не запрещает, но это многими способами можно сделать


PD>>>(int a, float b) F()


PD>>>мне может быть полезнее чем


PD>>>void F(int&a, float&b)


S>>Вызвав такой метод очень легко что-нибудь где-нибудь испортить, особенно если переменные лежат не на стеке.


PD>Какой ? Второй ? Ничего тут испортить нельзя. Если, конечно, не брать там указатели и не гонять их как попало. Но так можно везде испортить.


Ну а первый способ таки исключает способы отрубить шашкой большой палец ноги (хоть и не себе), а следовательно полезнее.
Re[5]: Inline records
От: Pavel Dvorkin Россия  
Дата: 13.10.09 09:19
Оценка:
Здравствуйте, Sinclair, Вы писали:

В основном ты прав, но ИМХО все это эффекты второго порядка. Я согласен, что писать придется несколько иначе и эти эффекты надо учитывать. Но , на мой взгляд, эти отличия второго порядка недостаточны, чтобы вводить новое понятие в язык, поскольку пусть не на 100%, но на 99.9% мы уже имеем то же самое иным способом.
With best regards
Pavel Dvorkin
Re[9]: Inline records
От: Pavel Dvorkin Россия  
Дата: 13.10.09 09:48
Оценка:
Здравствуйте, samius, Вы писали:


PD>>Какой ? Второй ? Ничего тут испортить нельзя. Если, конечно, не брать там указатели и не гонять их как попало. Но так можно везде испортить.


S>Ну а первый способ таки исключает способы отрубить шашкой большой палец ноги (хоть и не себе), а следовательно полезнее.


Меня, честно сказать, очень мало интересуют все эти проблемы "как бы чего не испортить". Не хотите испортить — пишите аккуратно и не портите. Если мне некие средства предложат, позволяющие сделать то. что я делаю сейчас, более элегантным способом при не худшей эффективности, я буду это изучать и использовать. Если же речь идет о синтаксических изысках, тотальной защите от всевозможных угроз или же неэффектиных, пусть и красивых решениях — это мне не интересно.
With best regards
Pavel Dvorkin
Re[6]: Inline records
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.10.09 09:53
Оценка: +4
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>В основном ты прав, но ИМХО все это эффекты второго порядка. Я согласен, что писать придется несколько иначе и эти эффекты надо учитывать.
Ты, похоже, так и не понял, о чём я говорю.
Я говорю, что "несколько иначе" делает фичу "возврат множества значений через &-аргументы" необоснованно неудобной. "Эффекты", о которых я написал, должен учитывать не программист, а язык программирования. И язык таки это делает — я написал, как именно.

Но учёт этих эффектов второго порядка компилятором вынуждает его накладывать на код ограничения уже первого порядка.
Простейшая штука — результат функции, которая возвращает "целую 2d-точку", не получается присвоить "плавающей 2d-точке". В отличие от простого случая возврата единственного аргумента.
Я так думаю, что если бы в С++ запретили возвращать значения вообще, и потребовали всегда в таких случаях передавать результат через &-аргументы, то ты бы быстро оценил этот "второй порядок".
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Inline records
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.10.09 09:55
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Меня, честно сказать, очень мало интересуют все эти проблемы "как бы чего не испортить". Не хотите испортить — пишите аккуратно и не портите. Если мне некие средства предложат, позволяющие сделать то. что я делаю сейчас, более элегантным способом при не худшей эффективности, я буду это изучать и использовать. Если же речь идет о синтаксических изысках, тотальной защите от всевозможных угроз или же неэффектиных, пусть и красивых решениях — это мне не интересно.


А здесь речь как раз не об эффективности (исполнения кода), а как раз о том, что бы не испортить, не перепутать, не рисовать крестики чтобы не забыть, и т.п. Об удобвстве и безопасности, в основном.
Re[7]: Inline records
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.10.09 09:57
Оценка: +1 :)
Здравствуйте, Sinclair, Вы писали:

S>Я так думаю, что если бы в С++ запретили возвращать значения вообще, и потребовали всегда в таких случаях передавать результат через &-аргументы, то ты бы быстро оценил этот "второй порядок".

Ага, и еще после каждого вызова проверять HRESULT! Что-то это мне напоминает
Re[11]: Inline records
От: Pavel Dvorkin Россия  
Дата: 13.10.09 10:45
Оценка: -1
Здравствуйте, samius, Вы писали:

S>А здесь речь как раз не об эффективности (исполнения кода), а как раз о том, что бы не испортить, не перепутать, не рисовать крестики чтобы не забыть, и т.п. Об удобвстве и безопасности, в основном.


Ну я и говорю, что ИМХО эти игры не стоят того, чтобы ради них менять серьезно язык.
With best regards
Pavel Dvorkin
Re[12]: Inline records
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.10.09 10:55
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ну я и говорю, что ИМХО эти игры не стоят того, чтобы ради них менять серьезно язык.


На это возразить нечего, остается только принять к сведению.
Re[7]: Inline records
От: Pavel Dvorkin Россия  
Дата: 13.10.09 10:56
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:

PD>>В основном ты прав, но ИМХО все это эффекты второго порядка. Я согласен, что писать придется несколько иначе и эти эффекты надо учитывать.
S>Ты, похоже, так и не понял, о чём я говорю.
S>Я говорю, что "несколько иначе" делает фичу "возврат множества значений через &-аргументы" необоснованно неудобной. "Эффекты", о которых я написал, должен учитывать не программист, а язык программирования. И язык таки это делает — я написал, как именно.

Да все я понял, просто я считаю эти эффекты маловажными.

S>Но учёт этих эффектов второго порядка компилятором вынуждает его накладывать на код ограничения уже первого порядка.

S>Простейшая штука — результат функции, которая возвращает "целую 2d-точку", не получается присвоить "плавающей 2d-точке". В отличие от простого случая возврата единственного аргумента.

Присвоить все равно нельзя. Можно лишь получить результат как целую точку, а потом через конструктор получить плавающую. В любом случае будет 2 объекта.

S>Я так думаю, что если бы в С++ запретили возвращать значения вообще, и потребовали всегда в таких случаях передавать результат через &-аргументы, то ты бы быстро оценил этот "второй порядок".


Ну и что ?


class IPoint {
public :
    int x, y;
};

class FPoint {
public :
    float x, y;
    FPoint(IPoint& ip)
    {
        x = ip.x;
        y = ip.y;
    }
};
IPoint GetPoint()
{
    IPoint p;
    p.x = p.y = 0;
    return p;
}

void GetPointByRef(IPoint& ip)
{
    ip.x = ip.y = 0;
}


int _tmain(int argc, _TCHAR* argv[])
{
    FPoint fp = GetPoint();

    IPoint ip;
    GetPointByRef(ip);
    FPoint fp1 = ip;
}




Принципиальной разницы не вижу.
With best regards
Pavel Dvorkin
Re[8]: Inline records
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.10.09 11:37
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:
S>>Простейшая штука — результат функции, которая возвращает "целую 2d-точку", не получается присвоить "плавающей 2d-точке". В отличие от простого случая возврата единственного аргумента.
PD>Присвоить все равно нельзя. Можно лишь получить результат как целую точку, а потом через конструктор получить плавающую. В любом случае будет 2 объекта.
Что значит "всё равно"? Еще раз привожу примитивный пример:
double f = GetSomeInt(); // работает
(double f) = GetSomeInt(); // не работает 
// мы помним, что строчка выше - всего лишь извращённый плод моего сознания, алиас для 
GetSomeInt(&f); // не работает, потому что &double не приводится к &int

Меня не интересует, что там происходит "за кадром". Код расширения инта до флоата подставлен компилятором. Если я поменяю там float на double, или, упаси байт, на какой-нибудь extended, то мне не придётся переписывать код. (Под "там" я имею в виду декларацию f — а она может случиться в совершенно другом месте. Например, это поле какой-то структуры, которой я параметризовал шаблонную функцию, в которой сделан вызов GetSomeInt()). И я всё еще имею гарантии статической проверки совместимости типов.

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

А вот более реалистичный пример
(int modulo, int reminder) = IntDivide(arg, divisor); 
// не работает, если arg и divisor - byte; 
// при очевидном определении IntDivide как 
template<classname T>
void IntDivide(T arg, T divisor, T &modulo, T &remainder)
// вместо этого мне нужно вручную выписывать нудные промежуточные присваивания
// хотя вот такой код будет работать безо всяких проблем:
int modulo = arg / divisor; // здесь сработает очевидное расширение байта до инта
int remainder = arg % divisor; // но делить придётся дважды, вместо быстрой операции, которая получает сразу оба числа.

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

PD>Ну и что ?


PD>Принципиальной разницы не вижу.

Ну да. Только я хочу иметь возможность всю эту кунсткамеру ликвидировать движением брови — то, на что я хочу тратить одну строчку, ты предлагаешь выписывать в целую страницу. На которой, кстати, ты сделал две ошибки (возможно, намеренных), и при этом всё еще не поддерживаешь IPoint<double>.
Понятно, что мой пример с modulo и remainder решается путём введения именованного класса DivisionResult, с соответствующими конструкторами и т.п — аналогично твоему примеру.
Но это всё — мучительный boilerplate. Хочется-то получить всё то же самое забесплатно, а не так, чтобы приходилось всё-всё писать руками.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Inline records
От: Трурль  
Дата: 13.10.09 11:49
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:


S>Для дальнейшего я буду использовать шарп, но аналогичные грабли есть и в твоих любимых плюсах.

S>Сравним следующие две строки:
S>
S>int a, b;
S>a = GetSomeInt();
S>GetSomeInt(out b); // в плюсах был бы соответственно &b
S>

S>Одинакова ли семантика первой и второй строчки? Нет, неодинакова. а получает значение ровно один раз, а в b происходит неопределённое количество присваиваний.

В Аде в подобном случае наблюдается полная эквивалентность.
a, b : Integer;
a = GetSomeInt();
GetSomeInt(b);
Re[9]: Inline records
От: Pavel Dvorkin Россия  
Дата: 13.10.09 11:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Меня не интересует, что там происходит "за кадром"


А меня именно это интересует, а все эти синтаксические тонкости — не очень. Я свою точку зрения подробно объяснил вот здесь

http://rsdn.ru/forum/philosophy/3566935.1.aspx
Автор: Pavel Dvorkin
Дата: 13.10.09


И ИМХО не надо вводить в язык дополнительные сущности, пока не станет ясно, что без них обходиться нельзя. Именно нельзя. А не "мне хотелось бы это написать в одну строку, а не 3"


PD>>Ну и что ?


PD>>Принципиальной разницы не вижу.

S>Ну да. Только я хочу иметь возможность всю эту кунсткамеру ликвидировать движением брови — то, на что я хочу тратить одну строчку, ты предлагаешь выписывать в целую страницу.

Меня мало интересует количество строк.

>На которой, кстати, ты сделал две ошибки (возможно, намеренных), и при этом всё еще не поддерживаешь IPoint<double>.


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

S>Но это всё — мучительный boilerplate. Хочется-то получить всё то же самое забесплатно, а не так, чтобы приходилось всё-всё писать руками.


Бесплатный сыр бывает только в мышеловках
With best regards
Pavel Dvorkin
Re[4]: Inline records
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.10.09 12:12
Оценка:
Здравствуйте, Трурль, Вы писали:

Т>В Аде в подобном случае наблюдается полная эквивалентность.

Т>
Т>a, b : Integer;
Т>a = GetSomeInt();
Т>GetSomeInt(b); 
Т>

А там есть definite assignment? Какие ограничения на использование b накладываются на тело GetSomeInt?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Inline records
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.10.09 12:46
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А меня именно это интересует, а все эти синтаксические тонкости — не очень. Я свою точку зрения подробно объяснил вот здесь

Это не синтаксис, а семантика.

PD>И ИМХО не надо вводить в язык дополнительные сущности, пока не станет ясно, что без них обходиться нельзя. Именно нельзя. А не "мне хотелось бы это написать в одну строку, а не 3"

И каков критерий "нельзя"? К примеру — зачем вообще ввели какие-то шаблоны? Ведь можно очень удобно просто написать столько версий функции Max(), сколько типов аргументов нас интересует — не так ли?
Собственно, единственное, что делают шаблоны — сокращают объем записи для функций типа Max. Ничего другого они не делают.

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

Да, на всякий случай поясню: я не предлагаю "тащить в язык всё, что в голову придёт". Любая фича должна начинать с "-500 баллов", чтобы этот барьер мешал попаданию мусора. Только если фича реально полезна, она наберёт баллов и попадёт в Долину Исполнения. Но твои критерии, имхо, чрезмерно строги.

На всякий случай напомню, что, как хорошо известно еще со времён тезиса Чёрча, обойтись можно вообще практически безо всего. Первый же тьюринг-полный язык программирования автоматически сделал все остальные языки ненужными. Поэтому мерятся они не тем, что "нового" можно сделать на этом языке, а тем, насколько мало усилий нужно для написания "старого". 100% фич реальных языков программирования сделаны только для сокращения количества строчек, и больше ни для чего.

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

Ну, я так и подумал. Впрочем, мой аргумент ты очень хорошо подчеркнул — даже "минимальный демонстрационный" пример получился достаточно громоздким, чтобы объяснить сомневающимся все преимущества нормального решения.

PD>Бесплатный сыр бывает только в мышеловках

Ну-ну. Предлагаю отказаться от бесплатного сыра типа компайл-тайм проверки типов или перегрузки операторов. Наверно, это мышеловка — надо вернуться в старый добрый K&R C без этих новомодных фишек вроде описания типов аргументов прямо в месте декларации функции.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.