3

For example, suppose that foo is defined like this.

foo[x_Integer, y_Integer] := x + y;

Then, any expression with head foo that does not match the pattern given above will remain "unevaluated". E.g., foo[3] "evaluates" to foo[3].

Although I recognize that there are situations where one may want precisely this behavior, in most of my programming I don't. Quite the contrary: I want expressions like foo[3] to be treated as malformed, IOW, as errors, and therefore to result in a loud, unequivocal failure whenever they are evaluated.

Hence, I find myself writing a lot of code of the form

foo[x_Integer, y_Integer] := x + y;
foo[___] := Abort[];

(Actually, I use a slightly embellished version of Abort[].)

But including a line like

foo[___] := Abort[];

for every function one defines adds up to a lot of hard-to-maintain clutter-code.

Does Mathematica have some other way to achieve the same thing with less clutter?

kjo
  • 11,717
  • 1
  • 30
  • 89
  • Related question: http://mathematica.stackexchange.com/q/48208/3066 – m_goldberg Dec 10 '16 at 17:37
  • 1
    Possible duplicate: http://mathematica.stackexchange.com/q/29321/12 – Szabolcs Dec 10 '16 at 17:41
  • 1
    The practice of adding a definition of the form foo[___] := ... is pretty much the standard idiom. I have never found that it produced any code maintenance problems. – m_goldberg Dec 10 '16 at 17:41
  • 1
    Abort is a rather drastic measure, and IMO not really the right solution for a reusable functions ... Unfortunately there's no one consistent way to deal with failures in Mathematica. Typical ways are: keep unevaluated and issue a message. Return $Failed, with or without a message. Return Failure[...]. In functions internal to your package: use Throw maybe. – Szabolcs Dec 10 '16 at 17:42
  • 2
    The common practice is to make a call to Message and print an informative error message. – m_goldberg Dec 10 '16 at 17:43
  • As m_goldberg notes, adding an explicit definition for "everything else" is standard practice (look at the code in the standard add-on packages, for instance). – J. M.'s missing motivation Dec 11 '16 at 02:16
  • @J.M.: If what you write is true (and I have no reason to doubt it is) then this means that Mathematica requires excessive amounts of boilerplate code to deal with an extremely common use-case; in my book, this is a sign of incompetent design. (I guess I expected better from Mathematica.) In Haskell, for example, which uses pattern-matching extensively in function definitions, any expression that does not match a pattern known to the compiler results in an error; there's no need to explicitly define a catch-all case to emit the error. – kjo Dec 11 '16 at 10:31
  • That's only if you want the "catch-all" case to do something (e.g. emit a Message) aside from coming out unevaluated; for instance, if you have a definition like f[n_Integer] := n! and you try to evaluate f[0.5], the expression is returned as is. – J. M.'s missing motivation Dec 11 '16 at 10:40
  • @J.M.:I realize that f[0.5] is returned as is. My whole point is that, in my coding at least (and apparently, per your earlier comment, in a lot of the Mathematica standard library) such way of handling f[0.5] is not desirable, thus necessitating the explicit catch-all case. – kjo Dec 11 '16 at 10:45

1 Answers1

2

Instead of foo[___] := Abort[] try this

LHS_foo := RuleCondition[Developer`CheckArgumentCount[LHS, 2, 2]; Fail];

It uses lots of undocumented functions, so it might not be to your taste.

It accomplishes @m_goldberg 's suggestion in the comments.

QuantumDot
  • 19,601
  • 7
  • 45
  • 121