Which function definition is used to evaluate an expression that matches the lefthand side of more than one definition?

In a case like this:

f[a_] := a;
f[{a_, b_}] := a;


I'm wondering whether I should expect f[{2, 3}] to return {2,3} or 2, because:

MatchQ[{2, 3}, a_] == MatchQ[{2, 3}, {a_, b_}]


Is the behaviour in this situation defined, or should I avoid this at all costs?

-
I thought I recalled a simple question in similar form to this one but the only (open) question I could find is the yet-unanswered: (8619) -- I do feel that this question is a duplicate but I'll not close immediately in case others disagree. – Mr.Wizard Jul 27 '14 at 12:32
@Mr.Wizard I feel that at the level of the example, the question is best answered by the documentation in the tutorial set Transformation Rules And Definitions Overview, in particular The Ordering of Definitions. The linked question seeks a deeper answer. The community might close the question as "easily found in the documentation." – Michael E2 Jul 27 '14 at 14:18
@MichaelE2 I retract my recommendation for closure. I think this question is sufficiently different, and further I think it is (just) obscure enough not to warrant closure as easily found in the documentation. – Mr.Wizard Jul 27 '14 at 14:35
@Mr.Wizard I agree. With the obsolescence of The Virtual/Mathematica Book (html‌​, pdf, 24M) -- the tutorial I linked above is from "Core Language"/Part 2 -- it's hard to know what basic things are easily found. Now we have Fast Introduction for Programmers, but it doesn't include ordering of definitions. – Michael E2 Jul 27 '14 at 15:17

Look at the DownValues of f to see how Mathematica will proceed:

DownValues[f]

{HoldPattern[f[{a_, b_}]] :> a, HoldPattern[f[a_]] :> a}


OR

?f


So, though you defined f[a_] := a first, the other definition is more specific, hence is applied first. If Mathematica cannot decide it will use the definitions in the order they were entered.

From the documentation:

The transformation rules associated with a particular symbol s are always stored in a definite order, and are tested in that order when they are used. Each time you make an assignment, the corresponding transformation rule is inserted at the end of the list of transformation rules associated with s, except in the following cases:

• The left‐hand side of the transformation rule is identical to a transformation rule that has already been stored, and any conditions on the right‐hand side are also identical. In this case, the new transformation rule is inserted in place of the old one.

• The Wolfram Language determines that the new transformation rule is more specific than a rule already present, and would never be used if it were placed after this rule. In this case, the new rule is placed before the old one. Note that in many cases it is not possible to determine whether one rule is more specific than another; in such cases, the new rule is always inserted at the end.

However this doesn't appear to be quite the whole story. See:

And also

-
@MichaelE2. Thanks, I have added it. – RunnyKine Jul 27 '14 at 13:57
Clear[f]
f[a_] := a
f[{a_, b_}] := a


Downvalues of a symbol hold the patterns used for its evaluation.

dv = DownValues[f]

{HoldPattern[f[{a_, b_}]] :> a, HoldPattern[f[a_]] :> a}


Downvalues are searched in normal order, first to last. Therefore,

{f[{2, 3}], f[42]}

{2, 42}


Downvalues can be reordered to get a different evaluation order.

DownValues[f] = Reverse @ dv

{HoldPattern[f[a_]] :> a, HoldPattern[f[{a_, b_}]] :> a}

{f[{2, 3}], f[42]}

{{2, 3}, 42}


If a new rule is added to downvalues, it is inserted into the list of downvalues according to Mathematica's idea of specificity, but ordering of the downvalues is not otherwised changed.

f[42] := 0
DownValues[f]

{HoldPattern[f[42]] :> 0, HoldPattern[f[a_]] :> a, HoldPattern[f[{a_, b_}]] :> a}

{f[{2, 3}], f[42], f[3]}

{{2, 3}, 0, 3}


There are many situations in Mathematica where overloading function definitions in the manner you describe is extremely useful. So don't fear overloading function definitions, make it one more tool in your programming toolbox.

-