Sign up ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I'd like to define a function with several optional arguments, some of which default to the value supplied for other arguments. For example, I'd like to be able to write something like

f[x_, y_: 0, z_: y] := {x, y, z}

and have

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


{{1, 2, 2}, {1, 0, 0}}

Instead I get

{{1, 2, y}, {1, 0, y}}

Can I make a default for an optional argument the value of another argument? If not, what's the best approach for accomplishing this?

share|improve this question
Are you an R user? I love this feature in R ... never seen it in any other language. – Gabriel Dec 4 '12 at 20:41

5 Answers 5

up vote 16 down vote accepted

You can't easily do this with optional arguments (but see Leonid's answer for a work around), but you can use the fact that you can have multiple definitions for a given function:

f[x_, y_:0] := {x, y, y}
f[x_, y_, z_] := {x, y, z}

will do what you want.

For further use of this style you could also do this as:

f[x_] := {x, 0, 0}
f[x_, y_] := {x, y, y}
f[x_, y_, z_] := {x, y, z}

which makes the "pattern" of your function even more explicit

share|improve this answer

Yes you can, although this is not completely trivial:

  f[x_, y_: 0, z_: yy] := Block[{yy = y}, {x, y, z}]

What is happening here is that I set the default to a local variable, which I then dynamically set (via Block) to a second argument. So,


(*  {{1,2,2},{1,0,0}}  *)
share|improve this answer
ohhhhh didn't realize this works. Any thoughts on why Mathematica color codes the yy in the block red? Seems to think it is not used. Man this is soooo sweet you get the R behavior as well, you can make the default arguments expressions like 1/yy etc. Thanks for this! – Gabriel Dec 4 '12 at 21:01
@Gabriel Well, a number of constructive uses of nested scoping constructs formally create variable collisions. Those who use that stuff know exactly how they are resolved, but it makes sense for the highlighter to generally warn about those. In this particular case, the way it works is that Block does localize the special variable created by Module, not the top-level yy, so things are fine. – Leonid Shifrin Dec 4 '12 at 21:06
@Gabriel Sure, no problem :) – Leonid Shifrin Dec 4 '12 at 21:07
man thought I had this question in the bag ... then the giants come round ;-) – Gabriel Dec 4 '12 at 21:17
@Gabriel One must be careful with saying "x is impossible in Mathematica", I think most of us got into this trap at least once. Never say never :) – Leonid Shifrin Dec 4 '12 at 21:20

A less elegant version than Gabriel's, and a less economic than Leonid's, using ReplaceAll:

f[x_, y_: 0, z_: Automatic] := {x, y, z /. Automatic -> y}
share|improve this answer
super cute :-) +1 – Gabriel Dec 4 '12 at 22:46
Very nice, +1. The reason I did not go this way is that you will have to hunt down all occurrences of z and replace them with z/.Automatic -> y, and if you forget some, there isn't any easy way to see that, so for functions with more complex / larger bodies this will be harder to maintain. But for a simple function, this is quite elegant. – Leonid Shifrin Dec 4 '12 at 23:03
@Leonid yes, you are right, but I had the vision of Options in front of my eyes :) Of course that involves a Module and a local variable to replace z everywhere, as you have pointed out. – István Zachar Dec 5 '12 at 20:36

Already late to the party, but here is another approach:

f[x_, y_: Automatic] :=
    If[y === Automatic, {x, x}, {x, y}]

Another Optional trick is the following:

f[x : (y_) : 1] := {x, y}

Here the colon is used twice. Once as shorthand for Pattern and once as shorthand for Optional. This is not appropriate for you question. I just wanted to mention it.

Edit 1:

Since optional arguments are all about pattern matching, here a list of possible patterns and allowed syntax:

InputForm  | FullForm
x          |  x
_*x        |  Times[Blank[], x]
(_.)*x     |  Times[Optional[Blank[]], x]
_          |  Blank[]
x*_        |  Times[x, Blank[]]
_x         |  Blank[x]
x . _      |  Dot[x, Blank[]]
_ . x      |  Dot[Blank[], x]
_.         |  Optional[Blank[]]
x*(_.)     |  Times[x, Optional[Blank[]]]
x_.        |  Optional[Pattern[x, Blank[]]]
_:x        |  Optional[Blank[], x]
x_         |  Pattern[x, Blank[]]
x:(_.)     |  Pattern[x, Optional[Blank[]]]
x /. _     |  ReplaceAll[x, Blank[]]
x /. _.    |  ReplaceAll[x, Optional[Blank[]]]
_ /. x     |  ReplaceAll[Blank[], x]
_. /. x    |  ReplaceAll[Optional[Blank[]], x]

Edit 2:

Another alternative is the following:

Default[f] = def;
f[x_, y_.] := Block[{def = x}, {x, y}]

Probably this is the best form of all I've listed here.

share|improve this answer

I think a good way to handle this is to pass the arguments back to the function. This is very similar to what Gabriel already proposed, but when the RHS is more complex it will be cleaner. Unlike Leonid's method it does not rely on Symbol evaluation and will therefore work inside held constructs.


f[x_, y_: 0]  := f[x, y, y]
f[x_, y_, z_] := Hold[x, y, z]


f[5, 7]
Hold[5, 0, 0]

Hold[5, 7, 7]

If the actual RHS were longer you can see why one would not wish rewrite it for the optional case:

f[x_, y_, z_] :=
  -x^3 - x^4 - x^3 y + 3 x^2 z + 3 x^3 z + 3 x^2 y z - 3 x z^2 - 3 x^2 z^2 - 
    3 x y z^2 + z^3 + x z^3 + y z^3
share|improve this answer

Your Answer


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.