> Yes, the final callback is always called, but if an error is passed to the > callback by any of the main steps in the "sequence ladder", it will > immediately jump to the final callback and not execute further steps.
OK. >> What do you mean? The compiler does deduce the type of Funcs. > > > If you look at where I call Waterfall() in main, you'll see I had to > manually specify (Callback cb) instead of just (cb); since it didn't know > that the Funcs... were of type AsyncFunc you can use std.typetuple.allSatisfy with a helper template: enum isAsyncFunc(T) = is(T == AsyncFunc); ... (Funcs...)(Funcs funcs) if (allSatisfy!(isAsyncFunc, Funcs)) { ... } >> (cb) { cb(null, "one");} is possible, but that means it's a function >> template, not a function. >> You can get this syntax by making the callbacks template arguments, >> which means they must be known at compile-time. Is that OK with you or >> do you need the possibility to define the callbacks at runtime? > > > The goal was to do as much as possible at compile time. Could you elaborate > on this a bit. I guess the answer is, yes, it's okay with me. I mean, it's possible to get a (cb){ some code } syntax, but as that define a function template, it has no real type: it cannot be a runtime argument, only an alias template parameter. That means that all callbacks must be defined in your code, none can come from user input or runtime computation. > > >> I don't get it: none of your callbacks have a return type per se: they >> all return 'void'. >> Do you want callbacks that really return something? > > > Yes, the callbacks at step0 should output a type in the result which is > specific to step0, and then that type should be fed in as a secondary > parameter to step1. > > I didn't get that far, as I was already stuck. OK, I get it. > thanks for your patience! Well, we are there to explain :-) I'll have try and code something. If I can get it to work, I'll post it there.