It looks like this is the critical design driver. Which makes sense—it’s why we were trying to pull things into shared service functions.
I very much like the idea of having string summaries consistent across the interfaces. Is there an easy way to do that and let interfaces determine things like line breaks? I realize that’s a detail, but just wanted to note it before moving on.
We should also do that in our “check” functions in the Stan math library. Those just automatically throw exceptions. @syclik and I originally set things up with all kinds of fancy traits control a la Boost, but I think having the basic check function is nice. The problem architecturally there is that there are things like checks for positivity, but when you pass a vector, you can’t just check for positivity, then throw a message, because the message should indicate the first element of the vector was found to violate the constraint.
Is this going to be a problem for a simple breakdown into an underlying C++ check and then a wrapping report?
I completely agree. We want to reserve exceptions for truly exceptional conditions that can’t be handled by the function in which they occur. The whole point is just to provide a scope to handle the exception further up (by aborting or fixing things, perhaps logging a warning, and continuing). We absolutely don’t want to start using exceptions to mock up ordinary control flow.
I’m assuming the “analysis API” and “C++ API” the same thing? I like this decomposition into simple C++ functions that compute relevant statistics and services methods that the interfaces can use to access them. It does bring to mind the adage that you can always sell a computer scientist another layer of abstraction.
Even if it doesn’t work for everything, I think factoring the code this way to start with is a big win as the result is two simpler pieces composed together in a natural way.