Introduction
What are good (robust?, simple?, efficient?) patterns for doing this
kind of code-switching?
This answer outlines a development strategy that can produce robust and extensible method option handling. Conceptually and development-wise, it is not that simple, but it has been successfully applied in large software projects with complicated dependencies between the algorithms and their corresponding specifications. The options of NIntegrate
are a very good example.
(Note that as it was indicated in the comments of the question post, simpler option structures are of interest for OP. )
The main idea is to treat the option values given to Method
as sentences from a Domain Specific Language (DSL). One good way to explain this approach is to use of the design pattern Interpreter as a reference, see [GoF94]. The approach is robust because it allows easy extension of the grammar, and easy addition and/or variation of the interpretations of its sentences (option specifications in this case).
For more a general discussion of DSL design and interpretation see this MSE answer. (Alternatively, see [AADSL16].)
Set-up
Given the example in the question formulation let us assume that we want both saveData
methods "Addition"
and "Multiplication"
to take the option "Delimiter"
and "Addition"
to also take the method sub-option "CompensatedSummation"
(which is an option of Total
). "CompensatedSummation"
can take options on its own, say, "WorkingPrecision"
.
Strategy steps
Grammar design
First, we come up with a grammar for the Method
option. Here is an example using EBNF :
<method-opt> = ( 'Method' , <rule-arrow> ) | ( <opt-spec> | <core-method> ) ;
<opt-head> = 'Method' | 'WorkingPrecision' | 'Delimiter' ;
<core-method> = 'Addition' | 'Multiplication' | 'CompensatedSummation' ;
<opt-rule> = <opt-head> , <rule-arrow> | ( <core-method> | <opt-value> | <opt-spec> ) ;
<opt-value> = '_String' ;
<opt-spec> = '{' | <core-method> , [ ',' | <opt-list> ] | '}' ;
<opt-list> = <opt-rule> , { ',' | <opt-rule> } ;
<rule-arrow> = '->' | '\[Rule]' ;
Parsing
Next we make a parser for this EBNF. This can be done using ad-hoc programming or a parser creation/generation package like FunctionalParsers.m. The parser would produce a tree for each command. Below is a table with the parsing results of multiple commands made with the above grammar. Note that we have produced trees of the option specifications that are easier to traverse using as prescribed by the design pattern Interpreter.
The table above was made using the package FunctionalParsers.m but in the context of this answer its application is only for experimental purposes, to easily derive and try out different grammars. I think it is better the parser to be made in a more ad-hoc manner by applying the prescription of Interpreter to program a parser-interpreter function (or class) for each grammar rule. One benefit is that we can have better, more detailed handling of wrong options. (This is how it was done in NIntegrate
.)
Interpretation
At this point we are ready to program the interpretation of the parser result trees. Those trees can be interpreted in different ways in different contexts of data and function signatures.
Example
A real life example of applying this approach -- NIntegrate
's Method
option -- is discussed in this video between 25:00 and 27:30. For the Method
option parsing trees produced in NIntegrate
see the section "UPDATE" of this answer of "Determining which rule NIntegrate selects automatically".
Extensions
We might want to have a more elaborated grammar that does not parse incompatible combinations of methods and sub-methods. For example, in the table above the command 3:
"Method -> {Multiplication, Method -> {CompensatedSummation, WorkingPrecision -> 40}}"
is successfully parsed but we probably consider "Multiplication" and "CompensatedSummation" to be incompatible.
Similarly, the command 6:
"Method -> {Addition, Method -> CompensatedSummation, WorkingPrecision -> 34}"
is successfully parsed, but we probably want "WorkingPrecision" to be a valid option only to some of the methods of "Addition".
These observations lead us to the conclusion that the grammar was too simple and general since it allows too many incorrect sentences. At this point we need to decide (1) do we handle the incorrect sentences at the interpretation phase, or (2) do we make a more complicated grammar that allows successful parsing of only meaningful combinations.
I would say for both development directions it is better to have a rigorous grammar that allows only meaningful commands. The EBNF of such a grammar can be also seen as a compact API specification and functionality design.
Here is a such more detailed grammar:
<method-opt> = ( 'Method' , <rule-arrow> ) |> <opt-spec> ;
<opt-spec> = <add-method> | <mult-method> ;
<opt-head> = 'Method' | 'WorkingPrecision' | 'Delimiter' ;
<add-method> = 'Addition' | '{' | 'Addition' , [ ',' | <add-opt-list> ] | '}' ;
<mult-method> = 'Multiplication' | '{' | 'Multiplication' , [ ',' | <mult-opt-list> ] | '}' ;
<compsum-method> = 'CompensatedSummation' | '{' | 'CompensatedSummation' , [ ',' | <compsum-opt-list> ] | '}' ;
<add-opt-list> = <add-opt-rule> , { ',' | <add-opt-rule> } ;
<mult-opt-list> = <mult-opt-rule> , { ',' | <mult-opt-rule> } ;
<compsum-opt-list> = <compsum-opt-rule> , { ',' | <compsum-opt-rule> } ;
<add-opt-rule> = ( 'Method' | 'Delimiter' ) , <rule-arrow> | ( <opt-value> | <compsum-method> ) ;
<mult-opt-rule> = 'Delimiter', <rule-arrow> |> <opt-value> ;
<compsum-opt-rule> = 'WorkingPrecision', <rule-arrow> | <opt-value> ;
<opt-value> = '_String' ;
<rule-arrow> = '->' | '\[Rule]' ;
References
[GoF94] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, 1994, Addison-Wesley.
[AADSL16] Anton Antonov, "Creating and programming DSLs", (2016), MathematicaForPrediction blog at WordPress.
[AAFP] Anton Antonov, Functional Parsers topic at MathematicaForPrediction blog at WordPress.
saveData[someVars, Method->{"Addition",Method->"CompensatedSummation"}]
. $\endgroup$