Re[22]: error is not an exception
От: IT Россия linq2db.com
Дата: 29.11.05 15:45
Оценка: -3
Здравствуйте, Cyberax, Вы писали:

>> Так может такие проверки должны быть штатными и использоваться не

>> только в режиме отладки?

C>А зачем? assert показывает ошибки программиста, а не пользователя. То

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

Для библиотечного кода эти проверки должны присутствовать и как правило присутствуют, загляни хотя бы в исходники .NET FW.

C>В рельной жизни assert'ы обычно оставляют в бэта-версиях, и выкидывают в релизах.


В реальной жизни фича отладчика, о которой я говорил выше, позволяет отловить всё тоже самое и без всякого замусоривания кода макросами. В общем, в ASSERT похоже тоже можно относить к устаревшим средствам и правилам типа венгерки, SELECT* и единственного return.
Если нам не помогут, то мы тоже никого не пощадим.
Re[26]: Что вы предлагаете на замену эксепшенов?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.11.05 15:56
Оценка:
Здравствуйте, IT, Вы писали:

IT>Сейчас чего-нибудь изобразим.


Написали Вы много, но принципиальной разницы с предыдущим примером нет.

MODULE RsdnUI;

  IMPORT StdLog, Errors := RsdnErrors, AccountManager := RsdnAccountManager;
  
  PROCEDURE WithdrawalAndGetBalance*;
    VAR newBalance: REAL; err: Errors.List;
  BEGIN
    IF AccountManager.WithdrawalAndGetBalance("12345", 1.0E2, newBalance, err) THEN
      StdLog.String("New balance is: "); StdLog.Real(newBalance); StdLog.Ln
    ELSE
      StdLog.String("Oops: "); StdLog.Ln;
      Errors.Print(err)
    END
  END WithdrawalAndGetBalance;

END RsdnUI.


MODULE RsdnAccountManager;

  IMPORT Errors := RsdnErrors;
  
  TYPE
    AccountService = RECORD
      (*...*)
    END;

    AccountDataAccessor = RECORD
      (*...*)
    END;

  ...

  PROCEDURE (VAR this: AccountService) WithdrawalAndGetBalance (accountNumber: ARRAY OF CHAR; amount: REAL; OUT rest: REAL; VAR err: Errors.List): BOOLEAN, NEW;
    VAR r: BOOLEAN; accessor: AccountDataAccessor;
    (*...*)
    PROCEDURE Do (): BOOLEAN;
      VAR ignored: Errors.List; (* ignored errors for steal-methods *)
    BEGIN
      IF accessor.GetBalance(accountNumber, rest, err) THEN
        IF rest >= amount THEN
          IF accessor.ChargeForService(accountNumber, 10, err) THEN
            rest := rest - amount - 10;
            IF (rest > 1.0E6) & accessor.StealSomeForMe(accountNumber, 1.15, ignored) THEN rest := rest - 1.15 END;
            IF (rest > 1.0E7) & accessor.StealSomeForHomelessPeople(accountNumber, 1.15, ignored) THEN rest := rest - 1.15 END;      
            RETURN accessor.SetBalance(accountNumber, rest, err)
          END
        ELSE
          err := Errors.NewList(Errors.NewError("You are freaking bankrupt!"), err); (* Вот такое вот "кидание исключения" *)
        END
      END;
      RETURN FALSE
    END Do;
    (*...*)
  BEGIN r := ValidateAccountNumber(accountNumber, err) & ValidateAmount(amount, err);
    IF r THEN
      accessor.Init;
      r := accessor.BeginTransaction(err) & Do() & accessor.CommitTransaction(err);
      accessor.Close
    END;
    RETURN r
  END WithdrawalAndGetBalance;

  ...
  
  PROCEDURE WithdrawalAndGetBalance* (accountNumber: ARRAY OF CHAR; amount: REAL; OUT rest: REAL; VAR err: Errors.List): BOOLEAN;
    VAR r: BOOLEAN; service: AccountService;
  BEGIN r := ValidateAccountNumber(accountNumber, err) & ValidateAmount(amount, err);
    IF r THEN
      service.Init;
      r := service.WithdrawalAndGetBalance(accountNumber, amount, rest, err);
      service.Close
    END;
    RETURN r
  END WithdrawalAndGetBalance;

  ...
  
END RsdnAccountManager.


MODULE RsdnErrors;

  IMPORT StdLog;
  
  CONST
    max = 256;
    
  TYPE
    Error* = POINTER TO EXTENSIBLE RECORD
      desc*: ARRAY max OF CHAR;
    END;
    
    List* = POINTER TO RECORD
      head-: Error; 
      tail-: List
    END;

  PROCEDURE NewError* (desc: ARRAY OF CHAR): Error;
    VAR e: Error;
  BEGIN ASSERT(LEN(desc) < max, 20);
    NEW(e); e.desc := desc$; RETURN e
  END NewError;

  PROCEDURE NewList* (head: Error; tail: List): List;
    VAR u: List; 
  BEGIN ASSERT(head # NIL, 20);
    NEW(u); u.head := head; u.tail := tail; RETURN u
  END NewList;
  
  PROCEDURE Print* (err: List);
  BEGIN
    WHILE err # NIL DO 
      StdLog.String(err.head.desc); StdLog.Ln; err := err.tail
    END
  END Print;
  
END RsdnErrors.
Re[7]: Что вы предлагаете на замену эксепшенов?
От: Sergey J. A. Беларусь  
Дата: 29.11.05 15:58
Оценка: :)
Здравствуйте, Сергей Губанов, Вы писали:

Вариант с исключениями:

PROCEDURE Proc (param: Param): BOOLEAN;
BEGIN
  ...
  DoSmth(param);
    ...
  IF b # TRUE THEN
        THROW NEW NewMyError('Proc: что-то не так с B');
    END
END Proc;


У вашего варианта оверхед — 16/9*100 = 177% !!!
... << RSDN@Home 1.2.0 alpha rev. 619>>
Re[30]: Что вы предлагаете на замену эксепшенов?
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 29.11.05 16:17
Оценка:
Здравствуйте, Privalov, Вы писали:

P>Еще раз: у нас нет ни малейшего представления о функции f(x). Поэтому если функция не определена в какой-то точке интервала — это исключительная ситуация.


Любая функция в некоторой области либо регулярна, либо не регулярна; определена или не определена; вычислима или не вычислима. Вы говорите что представления у нас о ней нет, это означает что мы должны думать о ней самое худшее. А раз так, то она может возвращать кроме чисел еще и nonNumber, plusInfinity, minusInfinity. До кучи, пусть она еще возвращает значение nonCalculable — нельзя вычислить.

СГ>>Если заранее известно, что процедура-функция f(x) может быть не определена ...


P>Не известно.


А мне, например, это известно.
Re[12]: Вот подумалось
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.11.05 16:47
Оценка: +2
Здравствуйте, vdimas, Вы писали:

V>Сделаю акцент еще раз на том факте, что корректное поведение программы в случае использования множественного return в неожиданных местах обычно обеспечивается доп. ср-вами самого языка. В С++ это автоматический вызов деструкторов локальных объектов (что крайне удобно, т.к. эти деструкторы вызываются только для реально инициализированных локальных переменных), в Java/C# есть try-finally для анаолгичных целей (не столь элегантно, но тоже вполне можно использовать).


V>Таким образом, верификация даже такого кода может быть полной.

Погоди, верификация и корректность работы компилятора — не одно и то же. Язык просто даёт нам некие автоматически работающие механизмы и не более того. И там и там есть оговорки использования и т.п. Можно и в деструкторе RAII исключение пульнуть.

Другое дело, что верификация невозможна без спецификации, которой должна соответствовать программа. Нет спецификации — верификация невозможна. Вывал AV в некоторых ситуациях может расцениваться как штатное и запланированное поведение. То есть, сначала нужна полная спецификация: что можно, чего нельзя и т.п. Но такая спецификация по сложности сопоставима с самой программой, то есть, получим ту же проблему, но в профиль: языки спецификации, наследование спецификаций (множественное vs одиночное), синтаксический оверхед при специфицировании поведения и т.п.

V> Другое дело, что мы не сможем верифицировать отдельно взятый участок (вернее можем, поясню далее), т.е. необходимо больше информации, о том, что происходит "неявно" для случая С++.


Да ну? А что, в случае Java/C# работа GC уже стала 100% детерминированной? А полиморфный код тоже 100% сможем верифицировать?

V>Однако, и здесь нас ожидают бенефиты. Мы можем построить верификацию кода иерархически, т.е. проверифицировать сначала "прочистку", а затем код, использующий ее неявный вызов. Ввиду того, что целевой код неплохо сокращается в случае множественного return (или использования exceptions как продвинутой разновидности), мы можем получить как раз больше возможностей для верификации на "реальных объемах".


Не, гиблая затея на любых объёмах. Примерно такое же ожидание панацеи, как её в своё время ожидали от перехода к языкам высокого уровня. Просто проблемы сместятся с одного уровня на другой. Всё равно задач адекватного учёта внешних условий и построения точных формулировок никто не снимет.
<<RSDN@Home 1.1.4 stable SR1 rev. 568>>
Music: Mike Oldfield — Moonlight Shadow

Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[27]: Что вы предлагаете на замену эксепшенов?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 29.11.05 17:05
Оценка: +1 :)
Здравствуйте, Сергей Губанов

Самое время синтаксический оверхед померять
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[28]: Что вы предлагаете на замену эксепшенов?
От: IT Россия linq2db.com
Дата: 29.11.05 17:42
Оценка: 1 (1) +1 :))
Здравствуйте, eao197, Вы писали:

E>Самое время синтаксический оверхед померять


Обязательно померяем И развернём его однострочный код, чтобы строчки посчитать, и количество ветвлений программы учтём. И даже поставим на вид то, что тырить без проверки результата не хорошо. Ну а уж за незакрытую транзакцию будем пинать ногами от всей души
Если нам не помогут, то мы тоже никого не пощадим.
Re[23]: error is not an exception
От: Cyberax Марс  
Дата: 29.11.05 17:59
Оценка: +2
IT wrote:

> C>А зачем? assert показывает ошибки программиста, а не пользователя. То

> C>есть ни при каком варианте работы событий пользователь не должен его
> C>получить, а значит и включать его не надо.
> Для библиотечного кода эти проверки должны присутствовать и как
> правило присутствуют, загляни хотя бы в исходники .NET FW.

Стоп. В FW куча проверок пост/пред-условий — это вполне нормально, если
клинет может передать неправильное значение. В случае FW клинетом
является пользовательское приложение.

Assertы нужны для проверки "невозможных" случаев, типа:
string str="adfhjadkjf";
string str2="adsfkjds";
string str3=str+str2;
assert(str3.size()!=0);

При нормальной работе оператора "+" срабатывание assert'а невозможно,
соответственно заменять его на exception — нет смысла.

Или так:
class fast_string
{
    void append(const string_base &_other)
    {
       assert(_begin!=_end); //Check invariant.
       ....
    }
};

В данном случае проверяется инвариант класса — существование хотя бы
одного символа (с кодом 0). Если он нарушен — то это уже ошибка
программиста библиотечного класса или побочный эффект какой-нибудь
глобальной ошибки.

> C>В рельной жизни assert'ы обычно оставляют в бэта-версиях, и

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

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

> В общем, в ASSERT похоже тоже можно относить к устаревшим средствам и

> правилам типа венгерки, SELECT* и единственного return.

НЕТ! Тогда стоит к устаревшим правилам отнести и хороший стиль
программирования. В конце концов, он в .NET не нужен....

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[24]: error is not an exception
От: IT Россия linq2db.com
Дата: 30.11.05 01:32
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Assertы нужны для проверки "невозможных" случаев, типа:


Это всё легко покрывается юнит-тестами. Или ты их заменяешь асёртами?

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


C>Ну да, просто заменить на замусоривание исключениями.


Зачем? Предусловия в библиотечном или, например, в серверном коде проверять всё равно надо. А прикладной код нужно просто не лениться тестировать. В независимости от того используются асёрты или нет.

>> В общем, в ASSERT похоже тоже можно относить к устаревшим средствам и

>> правилам типа венгерки, SELECT* и единственного return.

C>НЕТ! Тогда стоит к устаревшим правилам отнести и хороший стиль программирования. В конце концов, он в .NET не нужен....


Зачем передёргивать? Или ты хочешь сказать, что хороший стиль и асёрты — это синонимы?

ЗЫ. Не хочу с тобой продолжать бодаться, всё равно ни мне тебя, ни тебе меня похоже не переубедить. Скажу только, что лично я, никакой практической пользы от асёртов сегодня не вижу. Речь идёт о .NET/C#. Такое моё сугуболичное ИМХО. Пойду лучше Серёгу за забытый ролбэк отстегаю
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[27]: Что вы предлагаете на замену эксепшенов?
От: IT Россия linq2db.com
Дата: 30.11.05 03:51
Оценка: 264 (19) +1
Здравствуйте, Сергей Губанов, Вы писали:

IT>>Сейчас чего-нибудь изобразим.


СГ>Написали Вы много,


А ты думал ты в сказку попал. Хватит в солдатиков в песочнице играться, welcome to the real world.

СГ>но принципиальной разницы с предыдущим примером нет.


А вот это мы сейчас и узнаем

Непонятно почему ты пропустил целый лэйер, но да бог с ним. Даже и с ним твой код рабочим назвать нельзя. Точнее он будет работать, но только в чистом, глубоком вакууме, т.к. увлёкшись бесконечными if'ами и &'ми ты совсем забыл сделать Rollback транзакции в случае ошибки. Ошибки двух методов StealSomeXXX ты тоже почему-то решил не обрабатывать. Отговорки типа ну я мол только идею продемонстрировал не принимаются. Впрочем, как раз её ты и "продемонстрировал" — сам понатыкал сосен и сам же в них запутался.

А теперь давай перепишем твой код на C# так чтобы он по идее был рабочим и можно было хоть что-то хоть как-то сравнивать. На строчки скупиться не будем (я же в своём примере не экономил). Я буду писать в своём стиле, но придерживаясь твоей идее. Любые замечания по существу принимаются.

Итак, первый слой — UI. Мой код из предыдущего примера.

void WithdrawalAndGetBalance()
{
    try
    {
        decimal newBalance = AccountManager.WithdrawalAndGetBalance("12345", 100m);
        Console.WriteLine("New balance is: {0}", bewBalance);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Oops: " + ex.Message);
    }
}

Твой вариант (по твоей идее).

void WithdrawalAndGetBalance()
{
  decimal newBalance;
  Errors  err = null;

  if (AccountManager.WithdrawalAndGetBalance("12345", 100m, out newBalance, ref list))
    Console.WriteLine("New balance is: {0}", bewBalance);
  else
  {
    if (err != null)
      Console.WriteLine("Oops: " + err.Message);
    else
      Console.WriteLine("Just oops :xz:");
  }
}

Счёт:
lines: 7:12
if/else/&: 0:4

AccountManager. Мой пример.

public static decimal WithdrawalAndGetBalance(string accountNumber, decimal amount)
{
  Validate(accountNumber);
  Validate(amount);

  return new AccountService().WithdrawalAndGetBalance(accountNumber, amount);
}

Твой вариант.

public static bool WithdrawalAndGetBalance(string accountNumber, decimal amount, out decimal newBalance, ref Errors err)
{
  return Validate(accountNumber, ref err) &&
         Validate(amount, ref err) &&
         new AccountService().WithdrawalAndGetBalance(accountNumber, amount, out newBalance, ref err);
}

Здесь я для наглядности перенёс вызовы на разные строчки, иначе текст не помещался на экран. В общем, далее слишком длинные строки я буду переносить.

lines: 4:3
if/else/&: 0:3
params: 2:4 (output: 0:2)

Но это всё цветочки. Вот они ягодки.

AccountService. Мой пример.

public decimal WithdrawalAndGetBalance(string accountNumber, decimal amount)
{
  Validate(accountNumber);
  Validate(amount);

  using (AccountDataAccessor dataAccessor = new AccountDataAccessor())
  {
    dataAccessor.BeginTransaction();

    decimal balance = dataAccessor.GetBalance(accountNumber);

    if (balance < amount)
      throw new BalanceException("You are freaking bankrupt!");

    balance -= amount;

    dataAccessor.SetNewBalance(accountNumber, balance);

    if (balance > 1000000m)
      dataAccessor.StealSomeForMe(accountNumber, 1.15m);

    balance -= 1.15m;

    if (balance > 10000000m)
      dataAccessor.StealSomeForHomelessPeople(accountNumber, 0.15m);

    balance -= 0.15m;

    dataAccessor.ChargeForService(accountNumber, 10m);
 
    balance -= 10m;

    dataAccessor.CommitTransaction();
 
    return balance;
  }
}

Твой вариант.

delegate bool Do();

public bool WithdrawalAndGetBalance(string accountNumber, decimal amount, out decimal newBalance, ref Errors err)
{
  newBalance = 0m;

  if (Validate(accountNumber, err) && Validate(amount, ref err))
  {
    AccountDataAccessor dataAccessor = new AccountDataAccessor();

    if (dataAccessor.Open(ref err))
    {
      if (dataAccessor.BeginTransaction(ref err))
      {
        if (new Do(delegate()
        {
          if (dataAccessor.GetBalance(accountNumber, out newBalance, ref err))
          {
            if (newBalance < amount)
            {
              err := Errors.NewList(Errors.NewError("You are freaking bankrupt!"), err); // Вот такое вот "кидание исключения"
              return false;
            }
            else
            {
              newBalance -= amount;

              if (dataAccessor.SetNewBalance(accountNumber, newBalance, ref err))
              {
                if (balance > 1000000m)
                {
                  if (dataAccessor.StealSomeForMe(accountNumber, 1.15m, ref err) == false)
                    return false;

                  balance -= 1.15m;
                }

                if (balance > 10000000m)
                {
                  if (dataAccessor.StealSomeForHomelessPeople(accountNumber, 0.15m, ref err) == false)
                    return false

                  balance -= 0.15m;
                  }

                if (dataAccessor.ChargeForService(accountNumber, 10m, ref err))
                  {
                    balance -= 10m;
                    return true;
                }
              }
            }
          }
          }())
        {
          if (dataAccessor.CommitTransaction(ref err))
          {
            dataAccessor.Close();
            return true;
          }
          else
          {
            dataAccessor.Close();
            return false;
          }
        }

        dataAccessor.RollbaсkTransaction();
      }

      dataAccessor.Close();
    }

    return false;
  }
}

lines: 35:71
if/else/&: 3:16 (9 уровней вложенности)
params: 2:4 (output: 0:2)

Нормально, да? Мало того что я на него потратил примерно на порядок больше времени, так ещё после того как я его закончил мне захотелось плакать

Итого имеем. Увеличение количество строк кода в два раза. Усложнение логики за счёт ветвления кода в 5 раз. В принципе, это и есть реальные, даже несколько заниженные цифры. Код начинает ветвиться и разрастаться с ужасающей быстротой, так же быстро теряется наглядность и появляются повторяющиеся фрагменты типа dataAccessor.Close() в примере. Уж извини, старался держаться в рамках твоей идеи. Для того, чтобы это хоть как-то контролировать в реальной жизни (а не в песочнице), некоторые проверки начинают пропускаться или просто забываться делаться с соответствующими последствиями. При внесении изменений в такой, уже казалось бы отлаженный код, внести новый баг — это обычное дело. Чтобы этого избежать, нужно тщательнейшим образом разобраться в этом бреде и делать всё максимально аккуратно, а это время, много времени.

Код с исключениями, как нетрудно заметить, имеет линейную структуру, прост и нагляден. Сделать ошибку в нём трудно, вносить изменения просто.

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

Но это ещё не всё.

AccountDataAccessor. Мой код.

public decimal GetBalance(string accountNumber)
{
  return (decimal)ExecuteScalarSp("GetBalance", accountNumber);
}
  
public void SetNewBalance(string accountNumber, decimal amount)
{
  ExecuteNonQuerySp("SetBalance", accountNumber, amount);
}
  
public void StealSomeForMe(string accountNumber, decimal amount)
{
  ExecuteNonQuerySp("StealSomeForMe", accountNumber, amount);
}
  
public void StealSomeForHomelessPeople(string accountNumber, decimal amount)
{
  ExecuteNonQuerySp("StealSomeForHomelessPeople", accountNumber, amount);
}

public void ChargeForService(string accountNumber, decimal amount)
{
  ExecuteNonQuerySp("ChargeForService", accountNumber, amount);
}

Твой вариант.

public bool GetBalance(string accountNumber, out newBalance, ref Errors err)
{
  // oops!!! А ExecuteScalarSp параметра Errors не поддерживает.
  // Ну дятлы её какие-то писали, не додумались до такой классной идее.
  //
  ///////////return (decimal)ExecuteScalarSp("GetBalance", accountNumber);
}

// остальные упсы поскипаны.

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

Да, кстати, использование ref и out параметров считается признаком плохого дизайна. FxCop на это заявляет "Consider a design that does not require that 'parameter_name' be an out parameter".
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[28]: Что вы предлагаете на замену эксепшенов?
От: dshe  
Дата: 30.11.05 08:16
Оценка:
Здравствуйте, IT, Вы писали:

В целом согласен, однако последний аргумент не совсем удачен.

IT>Но это ещё не всё.


IT>AccountDataAccessor. Мой код.


IT>
IT>public decimal GetBalance(string accountNumber)
IT>{
IT>  return (decimal)ExecuteScalarSp("GetBalance", accountNumber);
IT>}
  
IT>

IT>Твой вариант.

IT>
IT>public bool GetBalance(string accountNumber, out newBalance, ref Errors err)
IT>{
IT>  // oops!!! А ExecuteScalarSp параметра Errors не поддерживает.
IT>  // Ну дятлы её какие-то писали, не додумались до такой классной идее.
IT>  //
IT>  ///////////return (decimal)ExecuteScalarSp("GetBalance", accountNumber);
IT>}

IT>// остальные упсы поскипаны.
IT>

IT>В случае со "стандартной" ExecuteScalarSp, чтобы сохранить лицо, тебе скорее всего придётся написать длиннючий switch на все возможные коды возврата и подобрать к ним более менее вменяемые сообщения.

Насколько я понимаю, проблемы возникаеют когда встречаются два взаимоисключающий подхода (обработки исключений, в данном случае). Если бы стиль ref-out был общепринятым, то и ExecuteЧего-То-ТамSp его бы тоже поддерживал. И в этом случае пришлось бы написать длиннючий switch для того, чтобы Errors err преобразовать в исключения.

IT>Да, кстати, использование ref и out параметров считается признаком плохого дизайна. FxCop на это заявляет "Consider a design that does not require that 'parameter_name' be an out parameter".


Полагаю, FxCop не знает об использования стиля ref-out как альтернативы исключениям. И если ref-out плох, то отнюдь не потому, что FxCop его не понимает. Если бы более удобного подхода обработки исключений не было, чем ref-out, то и FxCop на него бы не ругался.
--
Дмитро
Re[25]: error is not an exception
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 30.11.05 08:49
Оценка:
Здравствуйте, IT, Вы писали:

IT>Это всё легко покрывается юнит-тестами. Или ты их заменяешь асёртами?


Чего-то не понял а Вашей шутки. Конечно, безусловно, однозначно, в любую погоду никакие юнит-тесты в принципе не способны заменить ассерты. Грамотно расставленные ассерты предусловия, инвариантов и постусловия — это доказательство правильности программы вообще, а юнит-тесты — лишь свидетельство, что данные конкретные тесты проходят, но не доказательство правильности программы вообще.
Re[26]: error is not an exception
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 30.11.05 08:53
Оценка: +4
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Грамотно расставленные ассерты предусловия, инвариантов и постусловия — это доказательство правильности программы вообще...


Абсурд. ИМХО.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[31]: Что вы предлагаете на замену эксепшенов?
От: Privalov  
Дата: 30.11.05 08:58
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Любая функция в некоторой области либо регулярна, либо не регулярна; определена или не определена; вычислима или не вычислима. Вы говорите что представления у нас о ней нет, это означает что мы должны думать о ней самое худшее. А раз так, то она может возвращать кроме чисел еще и nonNumber, plusInfinity, minusInfinity. До кучи, пусть она еще возвращает значение nonCalculable — нельзя вычислить.


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

СГ>>>Если заранее известно, что процедура-функция f(x) может быть не определена ...


P>>Не известно.


СГ>А мне, например, это известно.


Откуда?
Re[32]: Что вы предлагаете на замену эксепшенов?
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.11.05 09:53
Оценка: 3 (1) +1
Здравствуйте, Privalov, Вы писали:

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


СГ>>Любая функция в некоторой области либо регулярна, либо не регулярна; определена или не определена; вычислима или не вычислима. Вы говорите что представления у нас о ней нет, это означает что мы должны думать о ней самое худшее. А раз так, то она может возвращать кроме чисел еще и nonNumber, plusInfinity, minusInfinity. До кучи, пусть она еще возвращает значение nonCalculable — нельзя вычислить.


P>Вообще-то в таких случаях исключительную ситуацию создает аппаратура.

P>Я молчу о том, что вычисления компьютерные чуточку отличаются от вычислений на бумаге, и какая-нибудь бяка вполне может выскочить на ровном месте.
Да дело то не в том, что бяка может выскочить на неровном месте, а в том, что реальное программирование всегда происходит в режиме недостаточной информации. Сегодня мы были полностью уверены в том, что функция возвращает только числа, и полностью определена на всем интервале. А завтра прибежал заказчик и сказал, что под "полностью определена на всем интервале" он имел в виду "кроме, быть может, счетного множества точек".
Я уже говорил, что параноидальное программирование вредно. Потому что вместо написания
s = 0;
foreach(x in xRange)
  foreach(y in yRange(x))
    { 
     s+= f(x)*f(y);
    }
return s;

мы вынуждены писать
  foreach(x in xRange)
      foreach(y in yRange(x))
        { 
            X = f(x);
            if (X == nonNumber) 
                return nonNumber;
            Y = f(y);
            if (Y == nonNumber) 
                return nonNumber;
            XY = X*Y;
            if (XY == infinity)
              return infinity;
            s+=XY;
            if (s == infinity)
              return infinity
        }
    }

Это я еще простое выражение взял. А если бы там было что-то типа f(x, y)*g(x) + f(y, x)*f(x, y)+g(y)/g(x*y), то можно было б просто удавиться от всех этих ветвлений.

На самом деле ситуация еще хуже — даже если мы параноидально предположили, что функция может возвращать infinity и nonNumber помимо нормальных чисел, совершенно не факт, что заказчику завтра не захочется отличать plusInfinity от minusInfinity. И все эти требования невозможно заранее зафиксировать. Но академическое программирование чуждо этих нелепых подробностей — в нем на построение программы отводится бесконечное время, потому что цена ресурсов равна нулю. Бесплатные студенты потратят 0 рублей на написание как 100 строк, так и 1000.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[33]: Что вы предлагаете на замену эксепшенов?
От: Privalov  
Дата: 30.11.05 10:30
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Да дело то не в том, что бяка может выскочить на неровном месте, а в том, что реальное программирование всегда происходит в режиме недостаточной информации.


[...]

Мне-то это понятно. Я, правда, не всегда могу нормально объяснять. За что мне время от времени еще в институте снижали оценки на экзаменах. Да и сейчас на всяких там совещаниях я мало разговариваю.
Re[29]: Что вы предлагаете на замену эксепшенов?
От: AndrewJD США  
Дата: 30.11.05 10:51
Оценка: +1
Здравствуйте, dshe, Вы писали:


D>Насколько я понимаю, проблемы возникаеют когда встречаются два взаимоисключающий подхода (обработки исключений, в данном случае). Если бы стиль ref-out был общепринятым, то и ExecuteЧего-То-ТамSp его бы тоже поддерживал. И в этом случае пришлось бы написать длиннючий switch для того, чтобы Errors err преобразовать в исключения.


Не всегда. Например стороняя либа возвращает какие-то свои ошибки, а нам необходимо преобразовать их в коды ошибок/исключения которые используются в приложении
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[34]: Что вы предлагаете на замену эксепшенов?
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.11.05 11:13
Оценка:
Здравствуйте, Privalov, Вы писали:
P>Мне-то это понятно. Я, правда, не всегда могу нормально объяснять. За что мне время от времени еще в институте снижали оценки на экзаменах. Да и сейчас на всяких там совещаниях я мало разговариваю.
А ты в форумы пиши
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[35]: Что вы предлагаете на замену эксепшенов?
От: Privalov  
Дата: 30.11.05 11:55
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А ты в форумы пиши


Вот, пытаюсь.
Re[29]: Что вы предлагаете на замену эксепшенов?
От: IT Россия linq2db.com
Дата: 30.11.05 12:12
Оценка:
Здравствуйте, dshe, Вы писали:

D>Насколько я понимаю, проблемы возникаеют когда встречаются два взаимоисключающий подхода (обработки исключений, в данном случае). Если бы стиль ref-out был общепринятым, то и ExecuteЧего-То-ТамSp его бы тоже поддерживал. И в этом случае пришлось бы написать длиннючий switch для того, чтобы Errors err преобразовать в исключения.


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

D>Полагаю, FxCop не знает об использования стиля ref-out как альтернативы исключениям. И если ref-out плох, то отнюдь не потому, что FxCop его не понимает. Если бы более удобного подхода обработки исключений не было, чем ref-out, то и FxCop на него бы не ругался.


Это просто более громоздкая конструкция. В том же примере можно было создать err в вызывающем методе и передавать его обычным способом. Т.е. out/ref параметров практически всегда можно избежать и их наличие очень точный индикатор проблем в дизайне.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.