# Named patterns in Except

Bug introduced in 8 or earlier and fixed in 10.4.0

Bug isn't present in version 5.2

I don't think I quite understand how Except works.

I want to define $f(a,b) = (a-b)\ln(a-b)$, with the special case $f(a,a)=0$. Except, the function shouldn't evaluate if either $a$ or $b$ is zero.

I tried:

ClearAll[f]
f[Except[0, a_], Except[0, a_]] := 0;
f[Except[0, a_], Except[0, b_]] := (a - b) Log[a - b];


But for some reason DownValues[f] only reports one definition:

DownValues[f]
(* { HoldPattern[ f[Except[0, a_], Except[0, b_]]] :> (a - b) Log[a - b] } *)


This is bad because if the user inputs f[x,x], I get Infinity::indet errors.

Question What did I do wrong, and how do I make definitions with Except?

• I'm tempted to say this is a bug. In any way, this is not a case of one pattern having more priority than the other or so. If you change the order of the definitions you'll see the last one is always kept. It seems that Mathematica (incorrectly) sees both patterns as equivalent. – Sjoerd C. de Vries Dec 12 '15 at 12:27
• I agree that this is a bug. InternalComparePatterns returns "Equivalent" for the two cases which is clearly not correct. – Simon Woods Dec 12 '15 at 12:49
• @SimonWoods too bad this is a bug. Add the 'bugs' tag? – QuantumDot Dec 14 '15 at 8:49
• Sent bug report to Wolfram – QuantumDot Dec 14 '15 at 23:28
• With Mathematica 5.2 I observe the expected behavior but with 8.0.4 I reproduce the bug. – Alexey Popkov Dec 15 '15 at 8:04

Another way to get two definitions is to only use Except on the first argument for the case where the arguments are identical.

Clear[f]

f[Except[0, a_], a_] := 0

f[Except[0, a_], Except[0, b_]] := (a - b) Log[a - b]


Annoyingly it doesn't matter the order for the definitions it comes out like this:

DownValues@f
(* {HoldPattern[f[Except[0, a_], Except[0, b_]]] :> (a - b) Log[a - b],
HoldPattern[f[Except[0, a_], a_]] :> 0} *)


So in order to get the right behaviour you have to do

DownValues[f] = Reverse@DownValues@f
(* {HoldPattern[f[Except[0, a_], a_]] :> 0,
HoldPattern[f[Except[0, a_], Except[0, b_]]] :> (a - b) Log[a - b]} *)


Now

f[3, 1]
f[3,0]
f[2,2]
f[0,0]


gives

2 Log[2]
f[3,0]
0
f[0,0]

• if you do f[a_, Except[0, a_]] := 0 it takes care of the DownValue order issue. – george2079 Dec 14 '15 at 20:22

It seems that f[Except[0, a_], Except[0, a_]] isn't considered doubled argument while this

f[a : Except[0], a : Except[0]] is. So the former isn't considered special case and is overwritten by your next definition.

I can't explain properly but seems to be expected.

ClearAll[f];
f[a_, a_] := 0  (*or f[a : Except[0], a : Except[0]] if f[0,0] should give f[0,0]*)
f[a : Except[0], b : Except[0]] := {a, b}

f[1, 2]
f[0, 1]
f[0, 0]
f[1, 1]

{1,2}
f[0,1]
0
0

• Yes, that's what I need, thanks. Can you explain what went wrong with what I did, too? – QuantumDot Dec 12 '15 at 11:08
• @QuantumDot I edited the answer, still without full explanation. – Kuba Dec 12 '15 at 11:40
• Another workaround is to use a trivial condition to stop the definition being overwritten, e.g. f[Except[0, a_], Except[0, a_]] /; True := 0` – Simon Woods Dec 12 '15 at 17:57