20 марта 2008

Ошибки и method chaining

If you can make one heap of all you winnings
And risk it on one turn of pitch-and-toss,
And lose, and start again at your beginnings
And never breathe a word about your loss;
If you can force your heart and nerve and sinew
To serve you turn long after they are gone,
And so hold on when theirs nothing in you
Except the Will which says to them: "Hold on!"
R. Kipling. If

Прочитал однажды заметку о минимизации ошибок (вот вам ещё продолжение), внутренне покивал и занёс в шареды. А сегодня окончательно оформилась мысль, когда читал список изменений в ruby 1.9.
Когда я писал плагины к weechat'у, столкнулся с невозможностью использовать method chaining везде, где этого хочется. А всё почему? Потому что такая архитектура, дизайн, если хотите.
Конкретнее. Возьмём какую-нибудь функцию строки, например


str.gsub!(pattern, replacement) => str or nil
str.gsub!(pattern) {|match| block } => str or nil

Она возвращает строку или nil. А это, чёрт побери, объекты разных классов! И если вдруг вернулся nil, то вся правая часть цепи после него идёт нафиг, и сам скрипт идёт нафиг, ибо NoMethodError. Если бы она возвратила пустую строку, то вся цепь бы тихо умерла, никому ничего не сказав, а скрипт бы дальше пошёл. Но не судьба. В итоге - нарастание уродливых if'ов там, где они нафиг не нужны.

7 комментариев:

semka комментирует...

(Заранее прошу прощения у твоего мозга)
Но в хаскеле есть такая штука. как монада Maybe. Она именно для таких случаев идеально подходит.
Когда тебе нужно состыковать разные типы ты просто пишешь:

f x :: Integer -> Maybe Integer
f x = x | x > 0 = Just x
| otherwhise = Nothing

В итоге ты получишь на выходе значение Integer завёрнутое в Just, или Nothing. Они оба значения одного типа и все крайне довольны (:

semka комментирует...

Ну ясен перец я накосячил в семь утра:
f :: Integer -> Maybe Integer
f x | x > 0 = Just x
| otherwise = Nothing

PhoeniX комментирует...

так и знал, что там хорошо, где меня нет

semka комментирует...

Дак ты это.
Напиши эмуляторй Мэйби.
Тут всё досточно прозрачно, пусть возвращает контейнерный класс Maybe, а внутри у него сделай подходящую логику.

semka комментирует...

Вот например. Руби довольно гибкий для таких выкрутасов (:

PhoeniX комментирует...

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

semka комментирует...

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