It isn't possible today for a plan author to formally signal to callers that the plan failed (surfacing an error without requiring the caller to provide distinct (and not bound by convention) code paths for "ok" vs. "error". E.g.
{code} $results = case ($plan_result = run_plan('mymodule::myplan', '_catch_errors' => true, )) { Error: { $plan_result.details['result_set'] } default: { $plan_result } } {code}
Ideally, a caller should be able to expect a consistent return type regardless of whether or not the plan failed; just like a caller can always expect an object of type ResultSet to be returned from {{run_task}}.
Allow for a moment that a plan _always_ returns an object of type PlanResult. If this is true, we can generalize success/failure based on {{$pr.ok}}, just as ResultSet handling can be based on {{$rs.ok}}. If a PlanResult is not ok (it failed), we can generalize access to the error raised via e.g. {{$pr.error}}. The PlanResult object can define a standard interface to data returned by a plan, such as defining a {{.value}} method, and the index method ({{.[]}}) for easy access to returned data keys.
A caller could then simplify their code to e.g.
{code} $result = run_plan('mymodule::myplan', _catch_errors => true, )
run_task('mymodule::next_step, $result.value.ok_set) {code} OR {code} $result['summary'] {code} OR {code} if !$result.ok { # handle it } {code}
...etc., depending on what the plan author chooses to return.
Being able to rely on the datatype returned by {{run_plan}} greatly simplifies how plan authors can call and deal with the results from running other plans.
One way of doing this might be to create a new type, PlanResult, which akin to ResultSet would come with a standard set of methods to interact with it. We could additionally define PlanResult::Error, which is still a PlanResult, but adds a {{.error}} method to access an included Error object, and would be compatible with code like {{case $result \{ Error: \{ ... \} \}}}.
We could extend {{fail_plan}} to return a PlanResult::Error, if given a PlanResult return value and an Error. Plan authors could then choose to create well-formed plans in an opt-in way.
If we didn't have to deal with existing plans I'd say just always return a PlanResult, with a little more automation around it and less effort from the plan author. Maybe it's a better enough experience to make a change in 2.0. |
|
|