LINUX.ORG.RU

Про рестарты.

 


1

4

Вот я бесконечно далек от концепции рестартов (потому что не кодер). Но всё же я попытался впилить их в свой прожект (сначала это был декодер музыки в flac, а теперь оно ещё и немного понимает wav, а потом, может, будет понимать wavpack и ape).

Итак, ситуация. Вначале flac файла есть метаданные: обязательный блок streaminfo и прочие. Если какие-то блоки моя библиотека не понимает или они битые, то считыватель блока кидает condition 'flac-bad-metadata, а функция выше по стеку предоставляет рестарт: не консить такой блок к возвращаемому списку блоков и поправить позицию потока, из которого идет чтение. Вот код:

(defun open-flac (stream)
  ;; Checking if stream is flac stream
  (let ((bitreader (make-reader :stream stream)))
    (if (/= +flac-id+ #+x86_64 (read-bits 32 bitreader)
                      #-x86_64 (bitreader.be-bignum:read-bits 32 bitreader))
        (error 'flac-error :message "Stream is not flac stream"))

    (let (metadata-list)
     (do (last-block)
         (last-block)
       
       (setq last-block
             (restart-case
              (let ((metadata (metadata-reader bitreader)))
                (push metadata metadata-list)
                (metadata-last-block-p metadata))
              (skip-malformed-metadata (c)
                                       (let ((metadata (flac-metadata c)))
                                         (fix-stream-position bitreader metadata)
                                         (metadata-last-block-p metadata))))))
     (values
      (reverse metadata-list)
      bitreader))))

Так вот вопрос: нормальная ли практика предоставить конечному пользователю функцию open-flac, рестарт (или функцию-обертку) skip-malformed-metadata и condition flac-bad-metadata, чтобы он сам связал этот рестарт с этим условием (т.е. сделал handler-bind) и мог бы точно знать, есть ли у него битые/неизвестные блоки? Или лучше сделать функцию open-flac такой:

(defun open-flac (stream &key skip-malformed) «Если ошибка, то молча пропускаем» ...)? Или есть третий вариант?

Декодер работает и есть на жидхабе, если чё. Ещё он умеет дергать хидер из wav и расжимать g.711.


Ответ на: комментарий от archimag

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

anonymous
()
Ответ на: комментарий от anonymous

Я вот тоже не могу понять, зачем нужны рестарты.

Тут всё просто, не можешь понять - не пользуйся.

Касательно обсуждения у Страуструпа, Страуструп всегда последовательно следовал (во всяком случае, он об этом постоянно говорит) принципу «вы не должны платить за то, что не используете», что практически сразу ставит крест на рестартах в контексте C++. Кроме того, цена обработки исключений в C++ итак очень высока. Поэтому в C++ рестарты безусловно не нужны. Но делать на основе этого заключение, что рестарты вообще не нужны и не имеют никакой пользы, это надо иметь «выдающиеся» мыслительные способности.

archimag ★★★
()
Ответ на: комментарий от archimag

При интерактивной разработке эксепшоны - это боль. В C++, Java и т.д. рестарты, безусловно, не нужны. В, например, Clojure их ппц как не хватает.

naryl ★★★★★
()
Последнее исправление: naryl (всего исправлений: 1)
Ответ на: комментарий от archimag

Так в том-то и дело, что в D&E Старуструп пишет о совсем других причинах, в том числе и о том, что процитировано выше. Семантика возобновления не приносит пользу, а может и навредить(при проектировании), в разработке надежных систем. Это подтверждается опытом и исследованиями. Специфика языка в данном случае ни при чем. Тем более, что рестарты можно реализовать достаточно эффективно и они не будут сказываться на коде, который их не использует.

anonymous
()
Ответ на: комментарий от naryl

Для чего, например? Передавайте «стратегию» обработки доп. параметром или храните в локально памяти треда. Если так уж нужно. Хотя я не вижу профита и буду рад, если вы его покажите. По лиспу читал разную литературу, читал SICP, а конкретно по CL читал PCL и делал кучу хелловордов разной сложности. Серьезной практике на лиспе не имею, профессионально использую C, C++, Python, чуть-чуть Erlang, сейчас немного scala(но это под вопросом).

anonymous
()
Ответ на: комментарий от anonymous

Это подтверждается опытом и исследованиями
исследованиями

лол

Специфика языка в данном случае ни при чем.

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

naryl ★★★★★
()
Ответ на: комментарий от vasily_pupkin

Ничем не напоминают проверяемые исключения рестарты

Речь была о том, чтобы запускаемые рестарты были _частью типа функции_. Если твои ассоциативные цепочки не дотягиваются от этого до checked exceptions, это твоя проблема.

tailgunner ★★★★★
()
Ответ на: комментарий от naryl

Способ разработки никого не волнует. Вопрос в функционировании уже готовой системы. Там возобновления не нужны.

anonymous
()
Ответ на: комментарий от anonymous

Семантика возобновления не приносит пользу
а может и навредить(при проектировании)

Ваша интерпретация написанного смехотворна. В C++ добрая половина свойств не приносит пользы (в большинстве случаев) и может сильно навредить (в ещё большем количестве случаев). Это не те причины, которым когда-либо руководствовался Страуструп.

Это подтверждается опытом и исследованиями.

Ага, опытом одного человека в определённой области, при чём, давным-давно, в то время и сборка мусора была чем-то вредным и опасным.

archimag ★★★
()
Ответ на: комментарий от archimag

Это не те причины, которым когда-либо руководствовался Страуструп.

Однако выше цитировали именно Страуструпа. Так что Ваши выдумки никому не интересны.

Ага, опытом одного человека в определённой области, при чём, давным- давно, в то время и сборка мусора была чем-то вредным и опасным.

Если бы вы прочли ту главу, то поняли бы, что не одного. Там несколько таких примеров, в том числе со ссылками. О сборщике мусора вообще в этой главе не слова(о нем написано в другой). И это былу уже в начале 90х, а люди, которых спрашивали, работали не с С++, а с системами и языками, поддерживающими исключения, рестарты и их аналоги.

Так что прочтите сначала. А еще лучше просто приведите пример, где вам понадобились рестарты и чем передача ответственного за обработку объекта(в том или ином виде) была бы хуже.

anonymous
()
Ответ на: комментарий от anonymous

Если бы вы прочли ту главу, то поняли бы, что не одного.

Я читал эту книгу полностью и не один раз. Страуструп то мужик умный, в отличии от местной публики, он вообще никогда не говорит, что то или иное «вообще не нужно», он всегда говорит в контексте С++ и тех целей, который он перед собой ставил.

И это былу уже в начале 90х, а люди, которых спрашивали,
работали не с С++, а с системами и языками, поддерживающими
исключения, рестарты и их аналоги.

Что за языки то были? Что-нибудь дожило до наших дней?

А еще лучше просто приведите пример

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

archimag ★★★
()
Ответ на: комментарий от anonymous

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

Да, знакомо. Бывал как-то в компании, использующей Erlang...

naryl ★★★★★
()

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

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

Это плохой дизайн. А если вам нужно «возвращаться», то просто передавайте объект, способный исправить ситуацию без раскрутки стека и дергайте его вместо исключения. Можно передавать различные стратегии обработки ошибок и все такое прочее. А «обычные» исключения не трогайте - они хорошо делают свою работу.

anonymous
()
Ответ на: комментарий от naryl

Нет, я из тех, кто не подменяет понятия. Если для системы такие штуки бесполезны, то какой смысл это обсуждать? В процессе разработки используйте что угодно. Это можно сделать разными способами, но это не имеет отношения к архитектуре системы.

anonymous
()
Ответ на: комментарий от anonymous

Можно передавать различные стратегии обработки ошибок и все такое прочее.

так а внутри-то эти ф-ии как должны быть устроены? Дай угадаю..

while True:
  try:
    aqcuire_resource()
    break
  except FileNotFound:
    create_file()
    continue
  except ...:
    do_smth_else()
    continue
  except PermissionError:
    raise

Фу такие лесницы плодить на каждую строчку «рабочего» кода.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

так а внутри-то эти ф-ии как должны быть устроены? Дай угадаю..

Они тупо не могут быть устроены так. Вот так - могут:

def some_condition_handler(*args):
  print "Случилось some_condition:", args
  # а тут мы пытаемся исправить дело
tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

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

Мне вот ещё хочется поэкспериментировать с software transactional memory: типа исправить ситуацию и откатить код вновь на начало опасного участка. Не знаю на сколько это рабочее..

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

окей, а после исправления что делать?

А после исправления придется возвращаться к началу блока (тот же while). Это всё же не рестарты, а «что-то вроде» них.

Мне вот ещё хочется поэкспериментировать с software transactional memory: типа исправить ситуацию и откатить код вновь на начало опасного участка.

Либо это не STM, либо... я надеюсь, ты читал хотя бы всё, упомянутое здесь

tailgunner ★★★★★
()
Ответ на: комментарий от true_admin
run :: (a -> IO b) -> a -> (a -> e -> Maybe a) -> IO b
run f x recover = f `onException` (\e -> recover a e >>= \my -> case my of Nothing -> throw e; Just y -> run f y recover)

относится ли это каким-нибудь боком к лисповым рестартам я не знаю.

qnikst ★★★★★
()
Последнее исправление: qnikst (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Читал когда-то, это не тот STM, конечно. Я просто рассуждаю в слух.

Очевидно что при таком подходе обработка ошибок должна вестись в каком-то внешнем конексте чтобы при «откате» не откатилась и она. В общем, транзакции должны быть вложенные.

true_admin ★★★★★
()
Ответ на: комментарий от qnikst

Это всё хорошо когда идёт однотипная поточная обработка данных.

А вот что делать если есть блок кода который может выкидывать веер разных эксепшенов в разных местах... Впрочем, возможно, надо подходить с другой стороны к этому вопросу. Например, сокращать этот самый веер и писать «традиционным» способом.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

ок согласен. данный вариант «проиграет» все действия заново.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

true_admin вроде как имеет достаточно скилов на попробовать и решить стоит ли оно того

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

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

после оценки на поиграть - можно уже и предлагать, во всяком случае для новых проектов/подпроектов. Ну а команде, во всяком случае я, предлагать по объективным причинам этого не могу.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

команде, во всяком случае я, предлагать по объективным причинам этого не могу.

И я не могу. Точнее, могу, но это фейл с вероятностью 146%.

tailgunner ★★★★★
()
Ответ на: комментарий от true_admin

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

anonymous
()
Ответ на: комментарий от anonymous

Кстати, думаю, что можно сделать декоратор соответствующий.

Интересная мысль. Тут есть одно важное преимущество - декоратор находится рядом с функцией и нет проблем с чтением сырцов.

Покажи мне, как бы ты хотел использовать рестарты в питоне

Увы, подходящий пример «из жизни» пока не нашёл.

true_admin ★★★★★
()
Ответ на: комментарий от qnikst

haskell достаточно простой язык.

и дружелюбный, только друзей отбирает особым образом :)

true_admin ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.