Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

It is my practice to place Condition expressions on the left side of := and :> in almost every case.

  1. I find this to be more logical as it is part of the pattern

    With the exception of use inside Module, Block, or With on the RHS, which is a special case, the Condition depends only on the LHS, and therefore IMHO is more logically placed on the LHS

  2. Its behavior remains consistent when used with = and ->

    • f[x_] /; x < 5 := 1 and g[x_] /; x < 5 = 1 behave similarly
    • f[x_] := 1 /; x < 5 and g[x_] = 1 /; x < 5 behave differently
  3. The evaluation path is significantly less complicated

    Placing the condition on the RHS requires the internal use of RuleCondition and $ConditionHold which can significantly slow down simple functions.

    Clear[f, g]
    
    f[x_] /; OddQ[x] := 1
    f[x_] := 0;
    
    g[x_] := 1 /; OddQ[x]
    g[x_] := 0;
    
    f[4] //Trace
    
    {f[4], {OddQ[4], False}, 0}
    
    g[4] //Trace
    
    {g[4],{{OddQ[4],False},RuleCondition[$ConditionHold[$ConditionHold[1]],False],Fail},0}
    
    a = Range@1*^6;
    
    Timing[f /@ a;]
    Timing[g /@ a;]
    
    {0.421, Null}
    {0.655, Null}
    

Nevertheless, the documentation for Condition shows the RHS form and many experienced users also seem to favor this form.

Mathematica graphics

Which form should be standard, and why?


A brief edit: The form f[x_ /; x < 5] := 1 is what I use most often as should be clear to those who read my answers on StackOverflow. I omitted this form specifically because I didn't want to spawn a discussion (bad for SE sites) about purely-stylistic differences. I see now that this may have had the opposite effect. Rather I wish to focus this question on the apparently canonical yet IMHO inferior RHS placement and what its merits are.

share|improve this question
add comment

5 Answers

up vote 28 down vote accepted

I prefer the Condition to appear on the left-hand-side and outside the square brackets for several reasons.

Type signature

I often think of the condition as (part of) the analog of the signature in a typed language, so it should go on the left hand side.

Order of operations

I like that the elements of the function definition appear in the order in which I want them to happen:

f[x_] /; x > 0 := Sqrt[x]
  1. Look for f[x_].
  2. Check that x > 0.
  3. Return Sqrt[x].
  4. (Optional) Check any postcondition (see below).

Function contract

When an argument-checking definition of the form

f[else___] := Throw["Error in f."]

appears, a left-hand-side Condition often plays the role of a precondition in the sense of Design By Contract. A Condition can also appear on the right-hand-side and this plays the role of a postcondition:

f[x_] /; x > 0 := Sqrt[x] /; Sqrt[x] > 0

Consistency of appearance

I prefer f[x_] /; x > 0 to the alternative f[x_ /; x > 0] for consistency, because sometimes placing the Condition inside the square brackets is not possible, such as when the Condition depends on multiple arguments:

f[x_, y_] /; x > y := 1/(x - y)

Update: Rationale

I think Brett's preference of putting the Condition as close as possible to the quantity to which it applies is equally good so I want to explain why I ended up with my slightly different preference.

Basically I was writing a sequence of definitions like this, following Brett's guideline:

f[x_ /; c1[x], y_] := this
f[x_, y_ /; c2[y]] := that
f[x_, y_] /; c3[x, y] := other

Note that all of these define f[x, y]. So there are two things I didn't like about that:

  1. The key difference between each LHS is the different conditions on x and y, and these are difficult to read quickly here because they all start at different places and are mixed in with f[x_, y_].
  2. When a condition needs to change such that it suddenly starts or stops depending on x or y, I need to move it from inside the square brackets to outside or vice versa.

Now compare:

f[x_, y_] /; c1[x] := this
f[x_, y_] /; c2[y] := that
f[x_, y_] /; c3[x, y] := other

Of course, what would make even more sense would be to adhere to Brett's guideline except in special cases like above! Maybe I will try that now ...

share|improve this answer
    
+1 Since you work at Wolfram Research, do you have any thought about why only the RHS form is shown in the documentation of Condition? –  Mr.Wizard Jan 23 '12 at 15:57
4  
@Mr.Wizard In the documentation for Condition, the very first case "patt /; test" is actually the LHS form of Condition. For example patt could be x_ or f[x_]. The other two are the RHS form. –  Andrew Moylan Jan 24 '12 at 2:32
    
Very nice write up. Personally I keep the practice of keeping conditions on a single variable next to it, simply because I like to think of it as a type or interface. So some functions read h[x_List] and others will read h[x_/;x>4]. But of cause there are cases of mixed patterns as you note, which must be moved outside. –  jVincent Jun 15 '12 at 0:07
add comment

Style is a matter of taste and education. There is not a definite answer, only a personal answer. Having said that, there is another way for the condition that is common in code:

h[x_ /; OddQ[x]] := 1;
h[x_] := 0
h[4] // Trace

My personal preference is your f[] style, since I find that a good compromise between readability and closeness to the actual symbol involved. Imagine a long Module, then you'd have to scroll quite a bit to get/find the condition. The benefit of the RHS method is readability for people.

share|improve this answer
1  
This is actually the form I prefer. –  Heike Jan 23 '12 at 12:18
    
I use this form as well, preferring to keep conditions close to the pattern they apply to, but I was trying to not complicate things in my question. –  Mr.Wizard Jan 23 '12 at 12:33
    
I have updated the question with a small note attempting to focus the topic on the RHS placement. –  Mr.Wizard Jan 23 '12 at 12:40
add comment

My general preference is to put the condition as close as possible to the quantity to which it applies:

... to a single argument:

f[x_ /; x > 2, y_] := x + y

{f[1, 2], f[3, 2]}
{f[1, 2], 5}

... to a relationship between arguments:

g[x_, y_] /; x > y := x + y

{g[1, 2], g[3, 2]}
{g[1, 2], 5}

... to a value calculated during the evaluation of the function:

h[x_, y_] := Module[{z = x + y}, z^2 /; z > 3]

{h[1, 2], h[3, 2]}
{h[1, 2], 25}
share|improve this answer
    
I think this is a very sensible policy though my answer proposed a different one. –  Andrew Moylan Jan 24 '12 at 2:39
add comment

My preference is the same as Andrew's, for the consistency and layout reasons he specified. That is, put the precondition Condition after the function's pattern, f[x_, y_] /; test[x,y] := ... - even if test only depends on a single variable/blank.

But I'd like to add an extra reason for not putting the Condition inside the function brackets, which is anytime you can do that, you could use a PatternTest (?) instead. That is, instead of

f[x_/;test[x], y] := ...

you could and maybe should use

f[x_?test, y] := ...

As for putting the condition on the LHS of the rule/definition vs the RHS, I once again agree with Andrew and with Mr.Wizard's comments in the question.

share|improve this answer
3  
I favor x_ /; x<5 over x_?(#<5&) for clarity. If using a named test function I agree that PatternTest will be cleaner. –  Mr.Wizard Jan 24 '12 at 12:04
add comment

Another reason to use the LHS placement is mentioned in passing by Robby Villegas in the devcon99 presentation Working with Unevaluated Expressions:

I recommend that you hang the condition /; ... off the lhs, not the rhs, because then you can revoke the definition by plopping the whole lhs into an Unset command

For example:

f[x_] /; foo := 2 x  (* imagine a long definition *)
f[x_] /; bar := 5 x

We can clear one of the definitions using only the LHS:

Unset[f[x_] /; foo]

Definition[f]
f[x_] /; bar := 5 x

If using the RHS placement this Unset does not work:

g[x_] := 2 x /; foo
g[x_] := 5 x /; bar

Unset[g[x_] /; foo]

During evaluation of In[3]:= Unset::norep: Assignment on g for g[x_]/;foo not found. >>

$Failed
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.