0
$\begingroup$

Overloading functions for different types of parameters is very powerful. I can easily write different versions of a function depending on the function parameters being Integer, Real, Complex, Sring List and so on.

Now I want to write function which operates on data structures looking like this:

{_String, _List} Example: {"my data structure", {1,2,3,4,5}}

My function shall also operate either

  • two strings (containing file names) plus an optional third one which can be either "CSV" or "TSV"

Examples: f["file1","fiel2"] or f["file1","fiel2","TSV"]

or on

  • an arbitrary number>2 of strings (containing file names but neither "CSV" or "TSV") plus an optional last parameter which can be either "CSV" or "TSV"

Examples: f["file1","fiel2","file3"] or f["file1","fiel2","file3","TSV"]

  • or a string (containing a file name) as first parameter, a data structure of the type described above as second one plus an optional third one which can be either "CSV" or "TSV"

Examples: f["file1",{"my data structure", {1,2,3}}] or f["file1",{"my data structure", {1,2,3}}, "CSV"]

I did it like this:

Remove[f]; dataStruct={_String, _List}; f[a_String, b_String, type_:"CSV"]:=Print["1. variant with two Strings, type=", type]; f[a_String, b:dataStruct, type_:"CSV"]:=Print["2. variant with String and dataStruct, type=", type]; f[a:dataStruct, b:dataStruct, type_:"CSV"]:=Print["3. variant with two dataStruct, type=", type]; f[{a_String, b_String, ___String}, type_:"CSV"]:=Print["4. variant with List of Strings, type=", type]; f["foo", "bar"] f["foo", "bar", "CSV"] 

work as expected.

f["foo", "bar", "metrics"] 

returns the last parameter "metrics" as type instead of matching the fourth definition.

f["foo", {"bar", {}}] f["foo", {"bar", {}}, "CSV"] 

invoke the second definition

f[{"foo", {1, 2}}, {"bar", {3, 4, 5}}] 

takes the third variant.

How can I cope with this?

$\endgroup$
2
  • $\begingroup$ Aren't you missing the enclosing List in your "metrics" example? $\endgroup$ Commented Dec 1, 2022 at 23:55
  • $\begingroup$ Yes, your observation is perfectly right! f[{"foo", "bar", "metrics"}] and f[{"foo", "bar", "metrics"}, "CSV"] use the fourth definition! $\endgroup$ Commented Dec 2, 2022 at 12:36

1 Answer 1

1
$\begingroup$

One way would be to use symbols for the filetype (it will force disambiguation):

Remove[g]; dataStruct = {_String, _List}; g[a_String, b_String, type_Symbol : CSV] := Print["1. variant with two Strings, type=", type]; g[a_String, b : dataStruct, type_Symbol : CSV] := Print["2. variant with String and dataStruct, type=", type]; g[a : dataStruct, b : dataStruct, type_Symbol : CSV] := Print["3. variant with two dataStruct, type=", type]; g[a_String, b_String, ___String, type_Symbol : CSV] := Print["4. variant with List of Strings, type=", type]; 

g["foo", "bar", "metrics"] gives 4. variant with List of Strings, type=CSV

Another would be to use options instead of default arguments:

Remove[h]; Options[h] = {MyFileType -> "CSV"}; dataStruct = {_String, _List}; h[a_String, b_String, OptionsPattern[]] := Print["1. variant with two Strings, type=", OptionValue[MyFileType]]; h[a_String, b : dataStruct, OptionsPattern[]] := Print["2. variant with String and dataStruct, type=", OptionValue[MyFileType]]; h[a : dataStruct, b : dataStruct, OptionsPattern[]] := Print["3. variant with two dataStruct, type=", OptionValue[MyFileType]]; h[a_String, b_String, ___String, OptionsPattern[]] := Print["4. variant with List of Strings, type=", OptionValue[MyFileType]]; 

h["foo", "bar", "metrics"] gives 4. variant with List of Strings, type=CSV

h["foo", {"bar", {}}, MyFileType -> "TSV"] gives 2. variant with String and dataStruct, type=TSV

Another would be to use more specific representations than String, maybe a special head. But without knowing your semantics, I have no specific suggestion along those lines.

I generally avoid default argument values. It seems to inevitably bump up against ambiguities as your method signatures evolve. Without further info, I think options is probably the cleanest way to go.

$\endgroup$
1
  • $\begingroup$ Thank you lericr for your detailed discussion and two alternative advices. The first one, to request a Symbol for the default argument is more handy since it requires less changing of existing code and it is less typing. However, the comment above your reply shows that I also fell for a catastrophic clerical error. Nevertheless, many thanks! $\endgroup$ Commented Dec 2, 2022 at 12:51

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.