Re: for vs goto vs ... (не холивар)
От: Roman Odaisky Украина  
Дата: 22.01.14 13:50
Оценка: 4 (1) +1
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>наверняка многие сталкивались с подобным сценарием когда думаешь искусственный

J>цикл или goto...

J>есть некая функция которая скачивает из интернета файл

J>иногда сервер закрывает соединение не отдав весь файл
J>я делаю новый запрос с полем Range: дабы докачать "хвост"
J>и иногда сервер отвечает кодом 404 Not Found у меня вылетает исключение
J>которое надо перехватить на месте получить новую ссылку на этот же файл
J>и докачать файл

А цикл же всё равно нужен, чтобы ограничить количество попыток скачивания.

Псевдопитонокод:
def get_http_chunk(params, offset):
    for i in range(MAX_RETRIES_ON_404):
        try:
            link = generate_link(params)
            http_response = do_http_request(link, headers = { "Range": "bytes={}-".format(offset) })
            total_length = get_total_length_from_content_range_header(http_response)
            return http_response.data(), total_length
        except HttpError as e:
            if e.code != 404:
                 raise
    raise NuNeSmogla()

def get_file(params):
    data = bytearray()
    for i in range(MAX_DOWNLOAD_ATTEMPTS):
        new_data, total_length = get_http_chunk(params, offset=len(data))
        data.append(new_data)
        if len(data) == total_length:
            return data
    raise NuNeSmogla()

и безо всяких искусственных control flow statements.

Код с goto потом будет труднее поддерживать. Например, захочешь прикрутить то же ограничение количества попыток, и куда тебе ставить это ++i? Или запись в лог после неудачной попытки, особенно в случае, когда goto repeat будет несколько?
До последнего не верил в пирамиду Лебедева.
Re: for vs goto vs ... (не холивар)
От: antropolog  
Дата: 23.01.14 10:12
Оценка: 1 (1) +1
Здравствуйте, jyuyjiyuijyu, Вы писали:

вся проблема в исключениях, они не нужны в read_internet_file. Вот так бы это выглядело с кодами возврата:

for ( result = read_internet_file(generate_link()); 
      result == http_code::not_found; 
      result = read_internet_file(generate_link()) )
{ 
  log( "Yet another try..." ); 
}

if ( result != http_code::ok200 )
  throw http_exception( result );
Re: for vs goto vs ... (не холивар)
От: VVV Россия  
Дата: 21.01.14 22:15
Оценка: +1 -1
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>
J>void f()
J>{
J>    // declare collect & progress var's

J>repeat:

J>    generate_link()

J>    try
J>    {
J>        read_internet_file(link)
J>    }

J>    catch (web_exception& e)
J>    {
J>        if (e.code == http_code::not_found)
J>        {
J>            goto repeat;
J>        }
J>        throw;
J>    }
J>}
J>


Вариант с goto легче понимается — буквально с первого прочтения; вариант же с break и continue более сложен для понимания — с четверга полудня по вечер пятницы такой код никто фиксить или рефакторить не будет, отложат на вторник.. Мой выбор — с goto.
Re[5]: for vs goto vs ... (ну почти не холивар)
От: Vzhyk  
Дата: 23.01.14 09:06
Оценка: +2
Здравствуйте, CEMb, Вы писали:

CEM>Печаль про goto в том, что с ним легче в дедлок угодить и логику запутать, но если использовать его по месту, то всё ок. Откуда взялись все эти "нельзя!", непонятно... сдаётся мне, не обошлось очередной методологией ради методологии.

Вообще правило одно, если тебе захотелось использовать goto, подумай 7 раз почему и нет ли более понятного решения без goto.
Re[3]: for vs goto vs ... (не холивар)
От: Evgeny.Panasyuk Россия  
Дата: 21.01.14 23:01
Оценка: +1
Здравствуйте, jyuyjiyuijyu, Вы писали:

VVV>>Вариант с goto легче понимается — буквально с первого прочтения; вариант же с break и continue более сложен для понимания — с четверга полудня по вечер пятницы такой код никто фиксить или рефакторить не будет, отложат на вторник.. Мой выбор — с goto.

J>если честно с goto мне тоже нравится
J>ой рискую я сейчас наставят мне минусов

Если тебе нравится вариант с goto, если тебе он кажется более понятным — используй его, не комплексуй (конечно если в твоей команде нет каких-то жёстких guidelines на эту тему).
Например, вот что говорит Александр Степанов про goto: 1
Автор: Evgeny.Panasyuk
Дата: 04.04.13
, 2. Или например у Дональда Кнута есть интересная статья на эту тему.
Re: for vs goto vs ... (не холивар)
От: B0FEE664  
Дата: 22.01.14 09:24
Оценка: +1
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>наверняка многие сталкивались с подобным сценарием когда думаешь искусственный

J>цикл или goto...
Желание добавить goto или break в цикле говорит о том, что возможно пора добавить новую функцию. Последнее бывает затруднительно только при наличии большого числа тесно связанных переменных.

  Скрытый текст
J>
J>void f()
J>{
J>    // declare collect & progress var's

J>repeat:

J>    generate_link()

J>    try
J>    {
J>        read_internet_file(link)
J>    }

J>    catch (web_exception& e)
J>    {
J>        if (e.code == http_code::not_found)
J>        {
J>            goto repeat;
J>        }
J>        throw;
J>    }
J>}
J>


J>как лучше организовать тело функции ?

Я бы так написал:

enum ReadInternetFileResult
{
  eNotFound,
  eSuccess
};


ReadInternetFileResult ReadInternetFile(LinkType& link)
{
    try
    {
        read_internet_file(link)
    }
    catch (web_exception& e)
    {
        if (e.code == http_code::not_found)
        {
            return eNotFound;
        }
        throw;
    }
    return eSuccess;
}


void f()
{
    // declare collect & progress var's

    do
    {
        generate_link();

    }while(eNotFound == ReadInternetFile(link));
}
И каждый день — без права на ошибку...
Re[5]: for vs goto vs ... (не холивар)
От: Evgeny.Panasyuk Россия  
Дата: 22.01.14 12:58
Оценка: +1
Здравствуйте, Vzhyk, Вы писали:

EP>>Если тебе нравится вариант с goto, если тебе он кажется более понятным — используй его, не комплексуй (конечно если в твоей команде нет каких-то жёстких guidelines на эту тему).

V>Только вот, если побьют потом, пенять будет он на себя.

Так ведь за битого двух небитых дают

V>В коде по смыслу цикл, даже его метка об этом говорит, зачем код извращать на сокрытие цикла? Чтоб никто не догадался?


По смыслу там действительно цикл. Я о том, что пусть делает так как ему нравится.
Я бы наверное весь control flow отделил бы от логики:
repeat_until_whatever([&]
{
    generate_link();
    read_internet_file(link);
});
for vs goto vs ... (не холивар)
От: jyuyjiyuijyu  
Дата: 21.01.14 17:25
Оценка:
наверняка многие сталкивались с подобным сценарием когда думаешь искусственный
цикл или goto...

попробую объяснить на примере скачивания файла из сети

есть некая функция которая скачивает из интернета файл
иногда сервер закрывает соединение не отдав весь файл
я делаю новый запрос с полем Range: дабы докачать "хвост"
и иногда сервер отвечает кодом 404 Not Found у меня вылетает исключение
которое надо перехватить на месте получить новую ссылку на этот же файл
и докачать файл

вопрос в том как организовать тело функции самое очевидное это

void f()
{
    // declare collect & progress var's

repeat:

    generate_link()

    try
    {
        read_internet_file(link)
    }

    catch (web_exception& e)
    {
        if (e.code == http_code::not_found)
        {
            goto repeat;
        }
        throw;
    }
}


есть менее очевидный вариант но зато без goto

void f()
{
    // declare collect & progress var's

    for (;;)
    {
        generate_link()

        try
        {
            read_internet_file(link)
            break
        }

        catch (web_exception& e)
        {
            if (e.code == http_code::not_found)
            {
                continue;
            }
            throw;
        }
    }
}


как лучше организовать тело функции ?

спасибо
Re: for vs goto vs ... (не холивар)
От: Stanislav V. Zudin Россия  
Дата: 21.01.14 18:13
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>наверняка многие сталкивались с подобным сценарием когда думаешь искусственный

J>цикл или goto...

J>как лучше организовать тело функции ?


bool g(link)
{
    try
    {
        read_internet_file(link);
    }
    catch (web_exception& e)
    {
        if (e.code == http_code::not_found)
        {
            return false;
        }
        throw;
    }

    return true;
}

void f()
{
    // declare collect & progress var's

    for (;;)
    {
        generate_link();
        if (g(link))
            break;
    }
}
_____________________
С уважением,
Stanislav V. Zudin
Re: for vs goto vs ... (не холивар)
От: TarasB  
Дата: 21.01.14 18:23
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:


J>как лучше организовать тело функции ?


bool f(web_error *err)
{
  for (;;)
  {
    generate_link();
    if (read_internet_file(link, err))
      return true;
    else if (err->code==http_code::not_found)
      continue; 
    else
      return false;  
  }
  return true;
}
Re[2]: for vs goto vs ... (не холивар)
От: jyuyjiyuijyu  
Дата: 21.01.14 18:26
Оценка:
Здравствуйте, Stanislav V. Zudin, Вы писали:

не тогда придется состояние передавать а там около 4-5 параметров получается
да и искуственно это как то лепить for там где он не нужен...

вам так не кажется ?
Re[2]: for vs goto vs ... (не холивар)
От: jyuyjiyuijyu  
Дата: 21.01.14 18:31
Оценка:
Здравствуйте, TarasB, Вы писали:

нет if неполучится код библиотечный кидает исключение мне тогда придется внутри read_internet_file ставить catch
Re[3]: for vs goto vs ... (не холивар)
От: TarasB  
Дата: 21.01.14 18:34
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

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


J>нет if неполучится код библиотечный кидает исключение мне тогда придется внутри read_internet_file ставить catch


Хреново, тогда я бы написал второй вариант из 1го сообщения.
Re[3]: for vs goto vs ... (не холивар)
От: Stanislav V. Zudin Россия  
Дата: 21.01.14 18:36
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>не тогда придется состояние передавать а там около 4-5 параметров получается

J>да и искуственно это как то лепить for там где он не нужен...

Почему же не нужен?
Если сперва писать комментарии (что собираешься делать), а потом вбивать код, то получается вполне естественно:

// ПОКА ФАЙЛ НЕ ПОЛУЧЕН
{
   // СГЕНЕРИТЬ ССЫЛКУ
   // ЗАПРОСИТЬ ФАЙЛ
}


Цикл здесь очень даже уместен.

Насчет состояния...
иногда приходится заводить "контекст" и прогонять его через несколько уровней. Там может храниться дофига параметров, которые локальны по своей сути и их не вынесешь в описание класса, но которые дорого вычислять на каждом уровне.
_____________________
С уважением,
Stanislav V. Zudin
Re: for vs goto vs ... (не холивар)
От: dilmah США  
Дата: 21.01.14 18:40
Оценка:
J>как лучше организовать тело функции ?

монады уже предлагали?
Re[2]: for vs goto vs ... (не холивар)
От: jyuyjiyuijyu  
Дата: 21.01.14 19:15
Оценка:
Здравствуйте, Stanislav V. Zudin, Вы писали:

в вашем случае элегантней даже было бы сделать так

SVZ>void f()
SVZ>{
SVZ>    // declare collect & progress var's

SVZ>    do
SVZ>    {
SVZ>        generate_link();
SVZ>        
SVZ>    } while (!read_internet_file(link));
SVZ>}
SVZ>


единственное что меня напрягает в этом случае это передача состояния туда сюда
Re[3]: for vs goto vs ... (не холивар)
От: niXman Ниоткуда https://github.com/niXman
Дата: 21.01.14 19:36
Оценка:
это что получается, только меня одного смущает то, что приложение будет заблокировано пока файл качается?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: for vs goto vs ... (не холивар)
От: Vzhyk  
Дата: 21.01.14 19:45
Оценка:
Здравствуйте, niXman, Вы писали:

X>это что получается, только меня одного смущает то, что приложение будет заблокировано пока файл качается?

Возможно — это требуемой по ТЗ поведение.
Re[4]: for vs goto vs ... (не холивар)
От: jyuyjiyuijyu  
Дата: 21.01.14 19:47
Оценка:
Здравствуйте, niXman, Вы писали:

X>это что получается, только меня одного смущает то, что приложение будет заблокировано пока файл качается?


это консольное к тому же внутри read_internet_file рисуется прогресс так что все нормально)
Re[2]: for vs goto vs ... (не холивар)
От: jyuyjiyuijyu  
Дата: 21.01.14 22:39
Оценка:
Здравствуйте, VVV, Вы писали:

VVV>Вариант с goto легче понимается — буквально с первого прочтения; вариант же с break и continue более сложен для понимания — с четверга полудня по вечер пятницы такой код никто фиксить или рефакторить не будет, отложат на вторник.. Мой выбор — с goto.


если честно с goto мне тоже нравится
ой рискую я сейчас наставят мне минусов
Re[2]: for vs goto vs ... (не холивар)
От: Vzhyk  
Дата: 22.01.14 07:52
Оценка:
Здравствуйте, VVV, Вы писали:

VVV>Вариант с goto легче понимается — буквально с первого прочтения; вариант же с break и continue более сложен для понимания — с четверга полудня по вечер пятницы такой код никто фиксить или рефакторить не будет, отложат на вторник.. Мой выбор — с goto.

Нет, не легче. В коде по смыслу цикл, значит и нужно писать цикл, а уж что там for, do, while выбирать по вкусу. А вот goto тут ни к селу ни к городу.
Re[4]: for vs goto vs ... (не холивар)
От: Vzhyk  
Дата: 22.01.14 07:56
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Если тебе нравится вариант с goto, если тебе он кажется более понятным — используй его, не комплексуй (конечно если в твоей команде нет каких-то жёстких guidelines на эту тему).

Только вот, если побьют потом, пенять будет он на себя.
В коде по смыслу цикл, даже его метка об этом говорит, зачем код извращать на сокрытие цикла? Чтоб никто не догадался?
Re[3]: for vs goto vs ... (не холивар)
От: TarasB  
Дата: 22.01.14 08:17
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>если честно с goto мне тоже нравится

J>ой рискую я сейчас наставят мне минусов

Он по смыслу меньше подходит.
Смысл — "долбимся к адресу, пока либо не продолбились, либо не долбанулись". Очевидно, что это цикл.
Re: for vs goto vs ... (не холивар)
От: uzhas Ниоткуда  
Дата: 22.01.14 10:42
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>наверняка многие сталкивались с подобным сценарием когда думаешь искусственный

J>цикл или goto...
для меня goto так же как и char* — слишком низкоуровневая конструкция языка. я стараюсь (и другим советую) использовать более высокоуровневые средства типа std::string, for\while
например:
/**
Returns
true if file was read
false if file cannot be reached by generated link (error 404)
throws exception in case of other problem
*/
bool generate_and_read()
{
  auto link = generate_link();
  try
  {
    read_internet_file(link);
    return true;
  }
  catch (web_exception& e)
  {
    if (e.code == http_code::not_found)
      return false;
    throw;
  }

  //unreachable code
  return true;
}

void f()
{
  //here we can add limit for attempt number
   while (!generate_and_read())
   {
     //empty body
   }
}
Re[4]: for vs goto vs ... (не холивар)
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 22.01.14 13:16
Оценка:
Здравствуйте, niXman, Вы писали:

X>это что получается, только меня одного смущает то, что приложение будет заблокировано пока файл качается?


If everything you have is a hammer... :D
Re[3]: объект-механизм
От: Erop Россия  
Дата: 22.01.14 18:36
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>единственное что меня напрягает в этом случае это передача состояния туда сюда


Можно сделать так: http://rsdn.ru/forum/cpp/2298750
Автор: Erop
Дата: 12.01.07
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: объект-механизм
От: jyuyjiyuijyu  
Дата: 22.01.14 19:15
Оценка:
Здравствуйте, Erop, Вы писали:

я так понимаю вы имеете ввиду что то вроде этого ?

void f()
{
    // declare collect & progress var's

    do
    {
        generate_link()

    } while (!read(link))

    auto read = []()
    {
        try
        {
            read_internet_file(link)
            return true
        }

        catch (web_exception& e)
        {
            if (e.code != http_code::not_found)
                throw
        }
        return false
    }
}


да проблема с передачей контекста снимается но вот если лямбда будет достаточно большенькая то не айс наверное будет
Re[5]: объект-механизм
От: Erop Россия  
Дата: 22.01.14 19:59
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>я так понимаю вы имеете ввиду что то вроде этого ?


Зачем так сложно? просто будет объект, в полях которого будет контекст, а функции "сгенерировать ссылку", "докачать из текущей", "скачать из текущей" и т. п. будут его методами...

То есть клиентский код будет типа строить экземпляр такого объекта и звать у него метод "скачай", метод будет возвращать скачал ли он в конце концов или ничего не будет возвращать. А внутри он будет иметь цикл, например такой :
  if(! load_from_url( get_cur_url() ) ) {
    while( make_alterntive_url() && try_to_load_rest_of_file_from( get_cur_url() ) )
      ;
  }


Всё будет просто, понятно, и контекст копировать не надо будет, он будет просто в полях объекта лежать...
Но если охота, то можно, конечно, и в лямбду поля завернуть.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: объект-механизм
От: jyuyjiyuijyu  
Дата: 22.01.14 20:42
Оценка:
Здравствуйте, Erop, Вы писали:

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

стоит ли овчинка выделки ?
Re[7]: объект-механизм
От: Erop Россия  
Дата: 22.01.14 20:50
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>заводить отдельный класс для неявной передачи контекста между двумя функциями

Это не неявная передача контекста, это реализация всего функционала по скачиванию файла. Пространство имён и структура с контекстом в одном флаконе...
Ты же всё равно заводил бы какую-то функцию для этого дело? На у тут будет не функция в глобальном пространстве имён, а объект-механизм. В чём принципиальная разница? Зато он инкапсулирует все потроха...

J>вместо одного goto ...

Я конкретно в этом случае не вижу проблемы от готу. Правда мне так кажется, что если всё делать через циклы, то выходит лучше, но и с гото код понятный.
Другое дело, если у тебя часто возникает нужда в гото, это нехороший признак...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: for vs goto vs ... (ну почти не холивар)
От: CEMb  
Дата: 23.01.14 03:00
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

J>>если честно с goto мне тоже нравится

J>>ой рискую я сейчас наставят мне минусов

EP>Если тебе нравится вариант с goto, если тебе он кажется более понятным — используй его, не комплексуй (конечно если в твоей команде нет каких-то жёстких guidelines на эту тему).


Печаль про goto в том, что с ним легче в дедлок угодить и логику запутать, но если использовать его по месту, то всё ок. Откуда взялись все эти "нельзя!", непонятно... сдаётся мне, не обошлось очередной методологией ради методологии.
Re[5]: for vs goto vs ... (ну почти не холивар)
От: jazzer Россия Skype: enerjazzer
Дата: 23.01.14 03:21
Оценка:
Здравствуйте, CEMb, Вы писали:

CEM>Откуда взялись все эти "нельзя!", непонятно... сдаётся мне, не обошлось очередной методологией ради методологии.


Они взялись в те далекие времена, когда goto использовалась для всего подряд, включая прыжки из середины одной функции в середину другой.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: for vs goto vs ... (не холивар)
От: TarasB  
Дата: 23.01.14 12:49
Оценка:
Здравствуйте, antropolog, Вы писали:

A>
A>for ( result = read_internet_file(generate_link()); 
A>      result == http_code::not_found; 
A>      result = read_internet_file(generate_link()) )
A>{ 
A>  log( "Yet another try..." ); 
A>}


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