Oberon space
General Category => Общий раздел => Тема начата: valexey от Апрель 17, 2012, 11:16:24 pm
-
Предположим у нас нет никаких исключений. Также у нас нет монад и вообще мы не можем использовать выражения (expressions) чтобы связать вычисения, только чистые statement'ы. И у нас есть код, последовательность вызова функций. Каждая функция возвращает код ошибки. Если код nil, значит все хорошо и нужно продолжать вычисления дальше. Если же нет, то нужно напечатать что-то в лог и прекратить вычисление.
Если делать тупо в лоб, то получается как-то так:
err = f1()
if (nil == err) {
err = f2()
if (nil == err) {
err = f3()
if (nil == err) {
...
}
} else {
logError();
}
} else {
logError();
}
То есть куча вложенных if'ов на ровном месте и радостное перемешивание кода логики с кодом обработки ошибок.
Есть такой распространненный паттерн решения этой задачки:
err = f1()
if (err!=nil) {
logError()
return
}
err = f2()
if (err!=nil) {
logError()
return
}
err = f3()
if (err!=nil) {
logError()
return
}
Откровенно говоря, он мне тоже не нравится (хотя читается несколько лучше предыдущего) - код и логика опять смешаны. И опять туча дублирующегося кода.
Кто как справлялся с таким вот когда (и если) доводилось сталкиваться?
-
Кто как справлялся с таким вот когда (и если) доводилось сталкиваться?
Сталкивался многократно. Как справлялся - никак. :(
-
Кто как справлялся с таким вот когда (и если) доводилось сталкиваться?
Если выбирать из зол - то я бы выбрал досрочные ретурны. Либо варианты с проверками на кажом шаге (еслм надо до
-
(опять форум сглючил)
Кто как справлялся с таким вот когда (и если) доводилось сталкиваться?
Если выбирать из зол - то я бы выбрал досрочные ретурны. Либо вариант с проверками на кажом шаге (если надо дойти до конца функции):
err = f1();
if (!err)
err = f2();
if (!err)
err = f3();
-
Во втором случае, чтобы понять что после первой (n - ной) ошибки дальше не отрабатывает, приходится просматривать весь код до конца, в первом случае сразу понятно. Хотя я использую оба варианта.
Наверное как вариант, можно предложить в каждую функцию передавать параметр ошибки, и если он есть, то внутри функции уже не отрабатывать. В этом случае в каждой вложенной функции будет только одна подобная проверка ,что имхо достаточно разграничит логику от обработки ошибок
-
Наверное как вариант, можно предложить в каждую функцию передавать параметр ошибки, и если он есть, то внутри функции уже не отрабатывать.
Передавать не всегда обязательно. Можно просто иметь некую "глобальную" переменную err, например, поле объекта, а вызываться будут его методы.
-
Во втором случае, чтобы понять что после первой (n - ной) ошибки дальше не отрабатывает, приходится просматривать весь код до конца, в первом случае сразу понятно. Хотя я использую оба варианта.
Во втором случае тоже не надо, а вот в варианте влада - надо. То есть в третьем случае.
Наверное как вариант, можно предложить в каждую функцию передавать параметр ошибки, и если он есть, то внутри функции уже не отрабатывать. В этом случае в каждой вложенной функции будет только одна подобная проверка ,что имхо достаточно разграничит логику от обработки ошибок
Не, к сожалению не пойдет - функции эти не только мои, но и библиотечные, которые я менять не могу.
-
Можно ещё вот так извратиться.
if (f1() == nil &&
f2() == nil &&
f3() == nil) {
...
} else {
logError();
}
-
Можно ещё вот так извратиться.
if (f1() == nil &&
f2() == nil &&
f3() == nil) {
...
} else {
logError();
}
А это уже противоречит изначальной постановке задачи, ибо связывает вычисления через выражение. :-)
Поясню почему такое ограничение наложено - у нас ведь скорее всего будут не просто вызовы функций, но и другие statement'ы между ними. То есть без обработки ошибок это нечто вроде:
f1()
a:=c-d
f2()
g; v; z;
f3()
-
Можно ещё вот так извратиться.
if (f1() == nil &&
f2() == nil &&
f3() == nil) {
...
} else {
logError();
}
А это уже противоречит изначальной постановке задачи, ибо связывает вычисления через выражение. :-)
Как раз-таки изначальной постановке задачи оно не противоречит : ).
-
А можно ещё так:
err = f1()
if (nil == err) {
wrap_f2()
} else {
logError();
}, где wrap_f2() - это обёртка над f2(), прилегающими командами и обработкой ошибки. (Там внутри ещё будет вызван wrap_f3()).
-
раз-таки изначальной постановке задачи оно не противоречит : ).
Противоречит.
Предположим у нас нет никаких исключений. Также у нас нет монад и вообще мы не можем использовать выражения (expressions) чтобы связать вычисения, только чистые statement'ы.
-
Предположим у нас нет никаких исключений. Также у нас нет монад и вообще мы не можем использовать выражения (expressions) чтобы связать вычисения, только чистые statement'ы. И у нас есть код, последовательность вызова функций. Каждая функция возвращает код ошибки. Если код nil, значит все хорошо и нужно продолжать вычисления дальше. Если же нет, то нужно напечатать что-то в лог и прекратить вычисление.
Если делать тупо в лоб, то получается как-то так:
err = f1()
if (nil == err) {
err = f2()
if (nil == err) {
err = f3()
if (nil == err) {
...
}
} else {
logError();
}
} else {
logError();
}
То есть куча вложенных if'ов на ровном месте и радостное перемешивание кода логики с кодом обработки ошибок.
Есть такой распространненный паттерн решения этой задачки:
err = f1()
if (err!=nil) {
logError()
return
}
err = f2()
if (err!=nil) {
logError()
return
}
err = f3()
if (err!=nil) {
logError()
return
}
Откровенно говоря, он мне тоже не нравится (хотя читается несколько лучше предыдущего) - код и логика опять смешаны. И опять туча дублирующегося кода.
Кто как справлялся с таким вот когда (и если) доводилось сталкиваться?
Вот мой вариант обработки ошибок:
MODULE PrivErrTypes;
CONST
OK* = 0;
ERR_NO_MEM* = 101;
ERR_INVALID_MODE* = 201;
TYPE
ErrorStatus* = POINTER TO RECORD
code*: INTEGER;
location*: INTEGER;
END;
END PrivErrTypes.
MODULE PrivErrChecks;
IMPORT ETypes := PrivErrTypes, StdLog;
VAR
res: ETypes.ErrorStatus;
p: POINTER TO ARRAY 100 OF REAL;
a: INTEGER;
PROCEDURE Message(IN s: ARRAY OF CHAR);
BEGIN
StdLog.String(s); StdLog.Ln
END Message;
PROCEDURE LogReport;
VAR s: ARRAY 256 OF CHAR;
BEGIN
IF res.code # ETypes.OK THEN
CASE res.code OF
ETypes.ERR_NO_MEM: s := "No enough memory for completing of operation."
| ETypes.ERR_INVALID_MODE: s := "Invalid mode."
END;
Message("ERROR: " + s$)
END
END LogReport;
PROCEDURE Check1Passed (): BOOLEAN;
BEGIN
NEW(p);
IF p = NIL THEN
res.code := ETypes.ERR_NO_MEM; res.location := 0C1H
END;
RETURN res.code = ETypes.OK
END Check1Passed;
PROCEDURE Check2Passed (): BOOLEAN;
BEGIN
IF a < 0 THEN
res.code := ETypes.ERR_INVALID_MODE; res.location := 0C2H
END;
RETURN res.code = ETypes.OK
END Check2Passed;
PROCEDURE Run*;
VAR passed: BOOLEAN;
BEGIN
res.code := ETypes.OK; res.location := 0;
passed := Check1Passed();
passed := passed & Check2Passed();
IF passed THEN
Message("All tests passed successfully!")
ELSE
LogReport
END
END Run;
BEGIN
IF res = NIL THEN NEW(res) END;
a := -1; (* causing test to fail *)
END PrivErrChecks.
! PrivErrChecks.Run
-
Ага. Я слишком вскользь прочёл. Тут речь о каких-то монадах.
Пускай valexey сам решает подходит или нет. ;)
-
Вот мой вариант обработки ошибок:
...
passed := Check1Passed();
passed := passed & Check2Passed();
...
Опять связывание вычислений через выражение. Не годится по выше изложенным соображениям. Также не годится в случае если функция возвращает больше одного значения (в некоторых языках так можно):
err, res = f1()
В этом случае f1() засунуть в качестве операнда выражения уже не получится.
-
Ага. Я слишком вскользь прочёл. Тут речь о каких-то монадах.
Пускай valexey сам решает подходит или нет. ;)
Ненене, монады как раз нельзя :-) Твой код:
passed := Check1Passed();
passed := passed & Check2Passed();
Это и есть по сути монада. То есть связывание вычислений через выражение.
-
А эти ограничения имеют практический или теоретический (академический) характер?
Чем они обоснованы? Ведь операцию умножения тоже можно запретить. Но нафига?
-
А эти ограничения имеют практический или теоретический (академический) характер?
Чем они обоснованы? Ведь операцию умножения тоже можно запретить. Но нафига?
Ограничения чисто практические. Причины с примерами я приводил выше.
-
Ещё как вариант (пускай и не всегда применимый) - действовать как большинтсво компиляторов при синтаксическом разборе. Встретил ошибку - не беда, добавил в список и пошёл дальше. В конце прохода (или при накомплении некого критического числа ошибок) - остановился и выплюнул накопленный список. Кому надо :D , знает куда смотреть.
-
Ага. Я слишком вскользь прочёл. Тут речь о каких-то монадах.
Пускай valexey сам решает подходит или нет. ;)
Ненене, монады как раз нельзя :-) Твой код:
passed := Check1Passed();
passed := passed & Check2Passed();
Это и есть по сути монада. То есть связывание вычислений через выражение.
Откуда взят запрет на связывание вычислений через выражения? Если он взят с потолка, то мой вариант должен подойти.
-
Вот мой вариант обработки ошибок:
...
passed := Check1Passed();
passed := passed & Check2Passed();
...
Опять связывание вычислений через выражение. Не годится по выше изложенным соображениям. Также не годится в случае если функция возвращает больше одного значения (в некоторых языках так можно):
err, res = f1()
В этом случае f1() засунуть в качестве операнда выражения уже не получится.
В предложенных мною конструкциях (внутри булевой функции) можно использовать любые комбинации других возвращающих функций. Главное, вернуть статус: Успех или Неудача.
-
В предложенных мною конструкциях (внутри булевой функции) можно использовать любые комбинации других возвращающих функций. Главное, вернуть статус: Успех или Неудача.
Тогда придется в эти булевы функции заворачивать каждые две-пять строчек интересующего кода. То есть этих вспомогательных функций будет примерно столько же сколько строк кода без обработки ошибок. По моему, это слишком большой оверхед.
Собственно это первое что я пытался сделать когда начал бороться за читабельность кода.
PS. Вот в такие вот моменты я жутко завидую тем кто пишет на хаскелле.
-
PS. Вот в такие вот моменты я жутко завидую тем кто пишет на хаскелле.
... или на ассемблере... одна простая "макро-обёрка" вызова... и радуемся... :)
-
PS. Вот в такие вот моменты я жутко завидую тем кто пишет на хаскелле.
... или на ассемблере... одна простая "макро-обёрка" вызова... и радуемся... :)
Ну, не ассемблере, а таки макроасме :-) Но а вообще любому языку можно с макросистемой я в данном случае сильно завидую - тут даже макросов Сишных хватит. Но увы, в целевом языке нет ни макросов ни парадигмы "все есть выражение". То есть такой дубовенький императивный язычок. Сильно более дубовый в этом плане нежели Си.
-
А есть ли возможность вызывать код в виде строки (привожу аналог из 1С):
ФункцияОбертка(Вычислить("ВызываемаяФункция"), Выполнить("ДополнительныйТекстОбработкиКода")). В данном случае все можно сделать в одной функции, правда код будет в виде текста, что не очень удобно
-
А есть ли возможность вызывать код в виде строки (привожу аналог из 1С):
ФункцияОбертка(Вычислить("ВызываемаяФункция"), Выполнить("ДополнительныйТекстОбработкиКода")). В данном случае все можно сделать в одной функции, правда код будет в виде текста, что не очень удобно
Нет, функции eval (http://en.wikipedia.org/wiki/Eval) нет. Просто потому, что в этом случае пришлось тащить с собой компилятор.
-
Не пронял, зачем нужна переменная еrr (по смыслу содержит указатель возвращаемый мелкими функциями....) вполне можно и без него .. или нет?
-
Не пронял, зачем нужна переменная еrr (по смыслу содержит указатель возвращаемый мелкими функциями....) вполне можно и без него .. или нет?
Это код ошибки. И функции не мелкие.
-
Уродский код, и потом, я про то, что он нигде не используется... а насчет того, большие функции или маленькие пофигу - один черт каждая вызывается ровно один раз (либо не вызывается вообще)...
-
Уродский код, и потом, я про то, что он нигде не используется... а насчет того, большие функции или маленькие пофигу - один черт каждая вызывается ровно один раз (либо не вызывается вообще)...
Ничего не понял. Он используется (как минимум его проверяют на nil). Для пущего использования замени logError() на logError(err);
err = f1()
if (nil == err) {
err = f2()
if (nil == err) {
err = f3()
if (nil == err) {
...
}
} else {
logError(err);
}
} else {
logError(err);
}
-
Уродский код, и потом, я про то, что он нигде не используется... а насчет того, большие функции или маленькие пофигу - один черт каждая вызывается ровно один раз (либо не вызывается вообще)...
Или ты про какой код вообще? Те функции что у меня (f1, f2, f3 ...) используются много где, ибо библиотечны.
-
В предложенных мною конструкциях (внутри булевой функции) можно использовать любые комбинации других возвращающих функций. Главное, вернуть статус: Успех или Неудача.
Тогда придется в эти булевы функции заворачивать каждые две-пять строчек интересующего кода. То есть этих вспомогательных функций будет примерно столько же сколько строк кода без обработки ошибок. По моему, это слишком большой оверхед.
Собственно это первое что я пытался сделать когда начал бороться за читабельность кода.
PS. Вот в такие вот моменты я жутко завидую тем кто пишет на хаскелле.
В приведённом мною код проверок выглядит "линейно". Его легче читать и воспринимать, чем древовидный, с отступами.
А что подразумевается под "оверхедом"?
P.S. Попробую подумать о других вариантах позже вечером.
-
А теперь понятно, (недоумевал почему не использовался if (f0() !=nil ) напрямую.... но ладно, вы привели 2 неэквивалентных способа -
Первый ДОПУСКАЕТ выполнение инструкций внутри процедуры ПОСЛЕ блока if ов, второй НЕТ.
Имеет смысл выделить блок второго способа в Отдельную функцию возвращающую код
ErrCode Check(){
}
А вашей основной функции будет нечто: Log(Check())...
-
т.е. в этом случае вы получаете желаемое разделение (ценой небольшой работы ручками)
-
Почему уродский - НЕНАВИЖУ когда в качестве значений по алгоритму осмысленных констант используются предопределенные константы общего вида - nil, NULL уж лучше "магические" числа
-
А теперь понятно, (недоумевал почему не использовался if (f0() !=nil ) напрямую.... но ладно, вы привели 2 неэквивалентных способа -
Первый ДОПУСКАЕТ выполнение инструкций внутри процедуры ПОСЛЕ блока if ов, второй НЕТ.
Это уже мелочи - один к другому приводится простым засовыванием блока в функцию. Это рраз. Два - даже в случае с return'ами во многих языках я смогу гарантировать исполнение определенного кода перед завершением работы данной функции где бы этот return не приключился.
-
См. сообщение выше... что вам не нравится в предложенном способе?
-
Имеет смысл выделить блок второго способа в Отдельную функцию возвращающую код
ErrCode Check(){
}
А вашей основной функции будет нечто: Log(Check())...
От этого второй способ красивей (читабельней) не станет. Либо я что-то не понял в предложеном методе. Дай пожалуйста переделанный код второго способа.
-
ErrCode Check(){
err = f1();
if (err!=nil) {
return err;
}
err = f2();
if (err!=nil) {
return err;
}
err = f3();
if (err!=nil) {
return err;
}
}
.... в основной процедуре
.....
.....
merr=Check();
......
Log(merr);
....
-
ErrCode Check(){
err = f1();
if (err!=nil) {
return err;
}
err = f2();
if (err!=nil) {
return err;
}
err = f3();
if (err!=nil) {
return err;
}
}
.... в основной процедуре
.....
.....
merr=Check();
......
Log(merr);
....
Это не решает проблему нечитабельности тела функции Check.
-
Зато решает проблему - вашу проблему разделения логики минимальными средствами
:D Ваше желание конфетку съесть и на ... сесть похвально... но надо быть реалистом. :(
-
Зато решает проблему - вашу проблему разделения логики минимальными средствами
:D Ваше желание конфетку съесть и на ... сесть похвально... но надо быть реалистом. :(
Нет не решает. Вся логика радостно оказывается в функции Check. Логика в коде, если выкинуть обработку ошибок, ровно вот такая:
f1()
f2()
f3()
(аргументы в функции подставить по вкусу)
Вместо этого мне предлагается писать такое:
err = f1();
if (err!=nil) {
return err;
}
err = f2();
if (err!=nil) {
return err;
}
err = f3();
if (err!=nil) {
return err;
}
Где логика радостно перемешана с обработкой ошибок.
-
Вот это
f1()
f2()
f3()
и то что у вас в шапке топика - СОВЕРШЕННО РАЗЛИЧНЫЕ ВЕЩИ (вы уж разберитесь с тем что вам нужно,..)
-
Где логика радостно перемешана с обработкой ошибок.
В поставленных условиях (исключений нет, макросов нет, вообще ничего нет) трудно изобрести что-то новое. Чисто вкусовые вариации... Если бы можно было компилятор покрутить, то можно было бы пофантазировать... хотя кончилось бы все скорее всего поддержкой исключений.
-
Вот это
f1()
f2()
f3()
и то что у вас в шапке топика - СОВЕРШЕННО РАЗЛИЧНЫЕ ВЕЩИ (вы уж разберитесь с тем что вам нужно,..)
Одно и то же. Мне нужно что бы f2 выполнялось когда f1 успешен. и так далее. Но эта связка (условность выполнение f2) это не логика приложения. То есть это не то, что должно выпирать.
-
не правильная постановка вопроса - уместнее использовать фразу "добиться оптимального решения" - оно всегда есть в КОНКРЕТНОМ случае - а уж вопрос насколько оно оптимальное... я вот , например, почитал в этом топике мнение Алексея.... ну и высказался ... насчет "конфетки".
-
Где логика радостно перемешана с обработкой ошибок.
В поставленных условиях (исключений нет, макросов нет, вообще ничего нет) трудно изобрести что-то новое. Чисто вкусовые вариации... Если бы можно было компилятор покрутить, то можно было бы пофантазировать... хотя кончилось бы все скорее всего поддержкой исключений.
Ну, defer есть :-) Еще паника есть (которую можно поймать - похоже на исключения). Но мне кажется что паниковать по поводу и без - плохой тон. Функции высшего порядка есть :-)
-
Вот это
f1()
f2()
f3()
и то что у вас в шапке топика - СОВЕРШЕННО РАЗЛИЧНЫЕ ВЕЩИ (вы уж разберитесь с тем что вам нужно,..)
Одно и то же. Мне нужно что бы f2 выполнялось когда f1 успешен. и так далее. Но эта связка (условность выполнение f2) это не логика приложения. То есть это не то, что должно выпирать.
Охох... Алексей .. если вам нужно 3 вызова подряд - if по ЛОГИКЕ не нужны... ЕСЛИ НЕТ то НИКУДА ВЫ ОТ НИХ НЕ ДЕНЕТЕСЬ в особенности если вы должны сделать что то ПОСЛЕ этих вызовов - это есть ЛОГИКА АЛГОРИТМА. у вас к ЛОГИКЕ ОБРАБОТКИ ОШИБКИ относится вызов функции Log() который я убрал из логики алгоритма... И хватит... на это... достало - вы...это.... довольно неконструктивны....
-
Охох... Алексей .. если вам нужно 3 вызова подряд - if по ЛОГИКЕ не нужны... ЕСЛИ НЕТ то НИКУДА ВЫ ОТ НИХ НЕ ДЕНЕТЕСЬ в особенности если вы должны сделать что то ПОСЛЕ этих вызовов - это есть ЛОГИКА АЛГОРИТМА. у вас к ЛОГИКЕ ОБРАБОТКИ ОШИБКИ относится вызов функции Log() который я убрал из логики алгоритма... И хватит... на это... достало - вы...это.... довольно неконструктивны....
Ну да, ну да. Это все равно что писать вместо вот такого:
if (a&&b&&c&&d) {...}писать такое:
if (a) {
if (b) {
if (c) {
if (d) {
...
}
}
}
}
-
;) Ага придуриваемся.... а что, мне тоже весело...
-
;) Ага придуриваемся.... а что, мне тоже весело...
Ну, я не знаю какая у тебя цель участия в этой дискуссии, а у меня цель очень простая - мне нужно сделать свой код более читабельным. Причем не абстрактный код вообще, а вполне конкретный его кусок. Причем желательно это было сделать вчера. Как видишь, цель сугубо практическая.
-
:D Если прочитать ВСЕ ваши требования (... по этому топику)... целей у вас... как бы это выразится помягче .. достаточно много (например, избежание "радостного смешивания") и не все они разумные в контексте налагаемых вами ограничений.. впрочем, по этому поводу я уже высказался... все.
-
Ну, defer есть :-)
Тогда я бы точно склонился к варианту с досрочными ретурнами. Дейкстра (точнее его толкование труЪ оберощиками) идет лесом.
-
делать тупо в лоб
Советую делать тупо в лоб с многократно вложенными if, но только диагностику ошибки делать сразу, а не где-то там в else через сто строчек.
err = f1();
if (err != nil)
{
logError("f1 failed", err);
}
else
{
//...
//...
//...
err = f2();
if (err != nil)
{
logError("f2 failed", err);
}
else
{
//...
//...
//...
err = f3();
if (err != nil)
{
logError("f3 failed", err);
}
else
{
//...
//...
//...
err = f4();
if (err != nil)
{
logError("f4 failed", err);
}
else
{
//...
//...
//...
err = f5();
if (err != nil)
{
logError("f5 failed", err);
}
else
{
//...
//...
//...
}
}
}
}
}
-
Ну, defer есть :-)
Тогда я бы точно склонился к варианту с досрочными ретурнами. Дейкстра (точнее его толкование труЪ оберощиками) идет лесом.
Одна проблема в Обероне07(с его ЕДИНСТВЕННЫМ RETURN -ом ) вам не дадут даже сделать этого... ;D
-
делать тупо в лоб
Советую делать тупо в лоб с многократно вложенными if, но только диагностику ошибки делать сразу, а не где-то там в else через сто строчек.
err = f1();
if (err != nil)
{
logError("f1 failed", err);
}
else
{
//...
//...
//...
err = f2();
if (err != nil)
{
logError("f2 failed", err);
}
else
{
//...
//...
//...
err = f3();
if (err != nil)
{
logError("f3 failed", err);
}
else
{
//...
//...
//...
err = f4();
if (err != nil)
{
logError("f4 failed", err);
}
else
{
//...
//...
//...
err = f5();
if (err != nil)
{
logError("f5 failed", err);
}
else
{
//...
//...
//...
}
}
}
}
}
:D ;D А вот по Алексею это НИЗЗЯ ибо здесь "радостно смешиваются" две различные логики ;D
-
Советую делать тупо в лоб с многократно вложенными if, но только диагностику ошибки делать сразу, а не где-то там в else через сто строчек.
2valexey: я ж говорю, чисто вкусовые вариации - для меня, например, код Сергея абсолютно нечитаем :)
-
Одна проблема в Обероне07(с его ЕДИНСТВЕННЫМ RETURN -ом ) вам не дадут даже сделать этого... ;D
А там и defer нету ;) Так что там, скорее всего, я бы выбрал вариант "с проверками до конца".
-
Акаки там есть варианты акромя вашего (лестница)? ;)
-
Кто нибудь знает , есть ли в каком -нибудь Обероне - нечто на вроде AnyProc -указателя на произвольную процедуру?
-
Можно реализовать встроенную процедуру "приведение процедуры". : )
-
Раз радостное смешение логик не катит, то тогда прямая дорога к грустному конечному автомату.
-
Функции высшего порядка есть :-)
То есть, задача под какой-то конкретный язык, а не в общем случае? Тогда стоило добавить это в условие задачи.
-
Функции высшего порядка есть :-)
То есть, задача под какой-то конкретный язык, а не в общем случае? Тогда стоило добавить это в условие задачи.
Хотелось получить более-менее общий метод решения подобного на классе схожих императивных языков.
А так - язык Go. Но, по моему, это поможет мало, просто потому, что никто кроме меня тут на нем вроде бы не пишет.
-
Раз радостное смешение логик не катит, то тогда прямая дорога к грустному конечному автомату.
Вот это грамотный ответ... :) Правда здесь можно обсудить.. в какой степени можно эмулировать исключения средствами некоторого внешнего модуля (например, аккумуляция ситуаций во внешнем хранилище с возможностью пост обработки)... и что это может дать
-
Раз радостное смешение логик не катит, то тогда прямая дорога к грустному конечному автомату.
Угу. Я думал об этом. Цикл, внутри case. Ну и поехали. По сути тут case играет роль goto с вычисляемой меткой.
В результате отказался - избыточно мощный и общий инструмент, следовательно больше шансов совершить ошибку. То есть если конечный автомат тут использовать, то нужно его специальным образом оформить. Как его оформить поприличнее я так и не придумал.
-
внутри case.
А зачем нам чемодан? Ведь есть же функции высшего порядка? Или это функции американского высшего порядка? Типа: "теперь вы равноправны, но на юге шерифу на глаза лучше не попадайтесь".
-
внутри case.
А зачем нам чемодан? Ведь есть же функции высшего порядка? Или это функции американского высшего порядка? Типа: "теперь вы равноправны, но на юге шерифу на глаза лучше не попадайтесь".
Я могу ошибаться, но по моему функции высших порядков не заменят кейс. Заменить кейс может паттерн матчинг (ака сопоставление с образцом).
-
В общем случае, навероное - да, не заменят. Но если рассматривать конечный автомат как последовательность "действие - переход", то переход-к-новому-действию можно заменить на вызов нужной функции. Функции, есс-но, нужно передать в параметрах (может, есть альтернативы, но я их пока не придумал). Думаю, получится упрощённый лиспо-подобный интерпретатор.
-
А такой способ не пройдет -пусть мы имеем
простейший обьект TWarder с одним полем - ErrCode, конструктором устанавливающем его в nil, и методом WardProc(f:WardedProc) -который может менять ErrCode (в зависимости отего текущего значения вызывая f либо нет ), тогда работу фрагмент можно представить ввиде:
.......
MyWarder:=TWvarder.Create()
......
MyWarder.WardProc(f0());
MyWarder.WardProc(f1());
MyWarder.WardProc(f2());
.....
обработка ошибок...
Case MyWarder.ErrCode of
err1:Log(err1,'f0()')
err2:Log(err2,'f1()')
.....
-
Сама WardProc имеет простейший вид
Procedure TWarder.WardProc (f:WardedProc)
Begin
IF ErrCode=nil then ErrCode:=f()
End;
-
В Паскале такая хрень проходит, в Обероне, даже простейшем.. тоже должна...
-
... так что я явно поторопился с "Одна проблема в Обероне07(с его ЕДИНСТВЕННЫМ RETURN -ом ) вам не дадут даже сделать этого... ;D". ;)
-
А с другой стороны, свел задачу к форме которую хотел Valexey?- но , как и ожидалось, от if а избавиться не удалось...
-
А чё, мне понравилось, пожалуй попробую в будущем задейстововать :), правда тут без кейса можно (тем более в 1с его нет)