Ну если такая задача решается без корутин, это либо callback hell либо в тот же таск сложен стейтмашин, а может даже комбинация оных. В любом случае множество разрозненных функций (спагетти), где состояние явно упаковано либо в сам таск либо в callback. А тут компилятор сам вычислит что есть состояние и сам всё упакует и состыкует.
Но иногда мне кажется это порождает и вопросы. Например в линейном коде мы обычно не задумываемся о времени жизни локальных переменных. Какой нибудь intermediate result... Пусть мрёт в конце, со всеми. А coroutines кажется заставят подходить к этому более ответственно. Не нужен, избавься, иначе будет висеть в контексте до конца. Изменить семантику destruct on scope exit на destruct after last use нельзя, сайд эффекты...