@JM when writing code for others (as I often do) it is typical to reserve the first arg for the most critical input, say the data in a statistical test and leave the remaining args for extra tweaking. Thus, the ordering is important. I typically write multiple definitions but was wondering if it is possible to do in one go.
–
Andy RossFeb 10 '12 at 6:32

There's also the possibility of strict typing for your optional arguments. If your optional arguments cannot have the head Rule or RuleDelayed, the typing would prevent options being interpreted as optional arguments...
–
Ｊ. Ｍ.Feb 10 '12 at 6:37

2

@JM I often use arg_?(Not[OptionQ[#]]&) to cover the Rule and RuleDelayed cases. This doesn't work though if I have optional args with default settings.
–
Andy RossFeb 10 '12 at 7:01

See my answer for how I believe that pattern can be used.
–
Mr.Wizard♦Feb 10 '12 at 7:43

@MrWizard I guess I'm just not getting it.. its 2:00 am here so that may be why :) What I'm seeing from your example is obvious, the 3rd arg will not admit anything smaller than 5. But !OptionQ will exclude only Rule, {}, and RuleDelayed, (I think).
–
Andy RossFeb 10 '12 at 8:09

@Andy I mean that if the condition fails the entire definition of f does not match.
–
Mr.Wizard♦Feb 10 '12 at 8:27

A bit late-to-the-party post, and complementary to the other solutions. Several answers addressed the question quite well IMO. I had my shot on a similar one here, with a solution similar to the one by @Mr.Wizard. But now I just want to stress one subtle point missed by other answers: using OptionQ will leak evaluation for functions which are HoldAlland take optional arguments and options. As an example, consider a modified solution of @Mr.Wizard:

Note by the way that we had here to inject nr. In my solution in the linked Mathgroup thread, I used notOptionQ[x_] := ! OptionQ[x];, and the patterns looked like _?notOptionQ, so for this one injecting is unnecessary. In any case, try this code:

f[1, Print["*"], "g" -> 10]

You will see that printing happens as a part of the pattern-matching procedure. To avoid that, one should use this pattern instead:

nr = Except[_?(Function[elem, OptionQ[Unevaluated[elem]], HoldAll])];

Parentheses around Function are mandatory, and injecting is still required in this approach. The f redefined with this pattern does not leak evaluation:

f[1, Print["*"], "g" -> 10]
(*
==> 10[Hold[1 + Print["*"] + 3]]
*)

Admittedly, the case of Hold*-functions is not that often in practice, but I thought this subtlety should be mentioned here as well.

As always you take it to another level.
–
Mr.Wizard♦Feb 10 '12 at 10:12

@Mr.Wizard Thanks! So, back the the good old name? I must admit I got used to Mr.Wizard and the transition to Spartacus in our correspondence wasn't easy, so I am happy now. Congrats with becoming a mod, by the way! This will surely help make this site a better place.
–
Leonid ShifrinFeb 10 '12 at 10:20

Here's another possibility that makes use of a more involved pattern to delimit the arguments from the options. It seems to me that people writing "function definitions" are inclined to think of them rigidly in that way, commonly forgetting that these are still just patterns and can be used (and abused) as such. However, bearing in mind the true nature of these definitions can be useful in circumstances like this:

In fact, I wasn't able to trip this method up at all, which makes me slightly suspicious that I didn't try enough test cases. Can anyone else point out some shortcomings of this approach?

Edit

In response @Mr.Wizard's comments, I thought it best to clarify the following:

Why use argumentDelimiter, rather than Hold or HoldComplete?

Because argumentDelimiter is created inside a Module, its uniqueness can be guaranteed. As a result there is no possibility for conflict when one wishes to define functions that accept arguments wrapped with Hold etc. This approach is commonly seen in packages, although in that case a suitable symbol will usually be created in the package`Private` context once and for all rather than relying on Module because of the associated overheads.

Isn't Shortest redundant?

In principle, yes; however, since OptionsPattern[] may also make use of Shortest, in my opinion it is better to avoid unexpected conflicts by explicitly requiring the shortest possible sequence of arguments. As documented for Shortest, in case of two competing Shortest patterns appearing in the same expression, the one that appears first has higher priority, so anything that can match OptionsPattern[] always will in this case.

What if the optional but non-option arguments also happen to match OptionsPattern[]?

In this case one has problems regardless of using this technique, and I would consider it to be a limitation of OptionsPattern[] that invalid options also match. To avoid this situation, one must use @Mr.Wizard's suggestion instead of OptionsPattern[], i.e.:

Note that Options[f] must be set before evaluating this definition so that validOptionsPattern[f] has the correct value. (At least for the time being, because making a validOptionsPattern[] that works exactly like OptionsPattern[] except for validating the options seems to be non-trivial.)

So everything appears to work correctly. However, if your optional arguments could also be interpreted as valid option values, I would consider that situation ill-defined and as such outside the scope of this answer.

+1. I would add however that depending on one's perspective, your own In[6] := lines shows this "tripping up" which is why I provided the methods that I did.
–
Mr.Wizard♦Feb 12 '12 at 5:30

Also, what is the reason for using argumentDelimiter rather than Hold or HoldComplete?
–
Mr.Wizard♦Feb 12 '12 at 5:36

1

@MrWizard In principle Shortest should be redundant but I don't know if OptionsPattern[] makes use of Shortest, so per the documentation of Shortest (first Shortest wins) I used it anyway. And I used a unique symbol to avoid conflicts with functions that take Hold/HoldComplete as part of their normal arguments.
–
Oleksandr R.Feb 12 '12 at 5:43

1

I agree that this is normal behavior. I was simply looking at the corner case where one of the named arguments should be in the form of a rule, as you asked us to point out shortcomings and it's the only one I can see.
–
Mr.Wizard♦Feb 12 '12 at 5:44

2

Good stuff - +1. I often use Hold or HoldComplete to simply separate options from arguments, like f[Hold[x_,y_,x_],opts:OptionsPattern]. This allows me to not make fHoldAll (assuming I want to hold x,y and z). The advantage is that I can call it as f[Hold[a,b,c],opts] and this will match if opts stores some options. Otherwise, I'd have to make fHoldAll and call it as f[a,b,c,Evaluate[opts], and in practice it is very easy to forget Evaluate and get bugs, particularly if I expose the function to the user, who can not be expected to remember about Evaluate.
–
Leonid ShifrinFeb 12 '12 at 10:41

I too like Rojo's answer. And Mr. Wizard's answer is intriguing as always. A third possibility is adding the condition that the Heads of second and third arguments are not Rule after the LHS. So, the following also works

Mathematica is a registered trademark of Wolfram Research, Inc. While the mark is used herein with the limited permission of Wolfram Research, Stack Exchange and this site disclaim all affiliation therewith.