Все что вы сказали - правильно, однако это НИ РАЗУ не говорит о том, что использование СОБЫТИЙ делает читабельность НИЖЕ. Вы привели 2 крохотных кусочка кода, в каждом из которых есть switch, но нет никаких комментариев, как вы себе предполагаете реальное наполнение case.
Я делаю предположение, что в случае с очередью событий вы настаиваете на том, что в этом случае автомат не выражен явно. Если мое предположение верно, то я вам сейчас покажу, что автоматы очень хорошо дружат с событиями.
void process_event(Event *event)
{
switch (fsm_state)
{
case STATE_1: state_1_process_event(event); break;
case STATE_2: state_2_process_event(event); break;
...
default:
break;
}
}
void state_1_process_event(Event *event)
{
switch (event)
{
case EV_A:
// обработка события A в состоянии 1
...
break;
case EV_B:
// обработка события B в состоянии 1
...
break;
...
}
}
void state_2_process_event(Event *event)
{
switch (event)
{
case EV_A:
// обработка события A в состоянии 2
...
break;
case EV_B:
// обработка события B в состоянии 2
...
break;
...
}
}
Таким образом, код с событиями становится эквивалентным коду с прямым сканированием, поскольку состояния автомата явно выделены. (Ведь именно на этом вы настаиваете?)
Поэтому все ваши утверждения про "сканирование" и воспринимаю скептически. Ибо вы пытались доказать мне и окружающим, что написание программы с явными автоматами -- это лучший путь, однако при этом постоянно зачем-то приводили в качестве аргументов "сканирование". Автоматы ортогональны хоть сканированию, хоть событиям. По моему мнению, события позволяют намного легче тестировать и понимать автоматы. Может быть в каких-то случаях показано именно "сканирование". Однако, и то и другое легко программируется через автоматы.
Однако, при всем при этом САМИ автоматы страдают "выворачиванием логики работы наизнанку", как вы ранее это сказали. А не события сами по себе. Да-да, именно использование автоматов делает читабельность намного хуже. Ибо приходится постоянно следить за тем куда переключается состояние и отслеживать разные ветки. Программа становится разбитой на кусочки (по кусочку на каждое состояние), только переходы между кусочками не по goto, а неявно через переменную состояния.
Более того, через автоматы можно выразить и линейный алгоритм, разбитый на несколько шагов, однако читаемость падает сразу на порядок, а то и на два. В этом случае использование protothreads или corutines с неявным автоматом, спрятанным внутри, может оказаться более читабельным.
Более того, при числе состояний где-то более 8-10, помноженном на число событий (либо проверок при сканировании) тоже около 8-10, количество взаимных комбинаций и переходов возрастает настолько, что в голове удержать модель автомата со всеми его связями становится нереально сложно. Это серьезная проблема, про которую теоретики автоматного программирования почему-то редко говорят. В этом случае помогает только уменьшение сложности за счет разбивания большого автомата на несколько меньших, использование иерархических автоматов и т.д.
Насчет "гарантировать отсутствие побочных эффектов" -- я бы поостерегся так говорить. Можем пофлудить на эту тему, но уже отдельно.