# How to test if optional argument has been given?

I understand that the last call (f[1]) returns True because arg does not exist and thus SameQ tests a single argument ("ArgValue") which always returns True. Therefore no comparison can be done here at all. Now it is not possible to use ValueQ either, as arg does not exist, and thus it has no value so ValueQ[arg] would evaluate to ValueQ[]. How to test whether arg exists or not? I am aware that I can define another signature for just one argument (f[first_] := ...), but I want to solve it inside the function, if it is possible.

ClearAll[f];
f[first_, arg___] := (arg === "ArgValue");
{f[1, "ArgValue"], f[1, "NonArgValue"], f[1]}


{True, False, True}

UPDATE

In general, I want to test whether any optional argument was passed to f. Since f is in reality a quite large function with a lot of optional arguments and occasionally called with a quite complex argument structure, I decided that I do not want to create complex patterns for each case (i.e. a different signature). Insted I check inside f whether any extra argument was passed or not - which in tha baseline case means that there should be no extra argument. Thus f shouldn't return False in reality for only one argument (i.e. it still should perform some computation on its single argument), this is only for testing purposes here. A more realistic function would look like this:

ClearAll[func];
func[first_, arg___?overcomplicatedArgumentStructureQ] := Module[{...},
(* heavy computation *)
If[argExistQ[arg], (* do this *), (* do that *)];
(* some more heavy computation *)
];

-
Based on your update, I think my recommendation of {} =!= {arg} is correct. You are testing the argument on the LHS already, using a test function. Leonid's {arg} === {"ArgValue"} doesn't make sense in this case, and it also assumes a specific value for the optional argument. – Mr.Wizard Mar 19 '12 at 13:12
Leonid's answer is correct in the sense that if there is no arg given to f, it evaluates to False, else it also checks whether the given argument equals a certain value. While your solution works as well, I still prefer Leonid's way, as it does the test on the rhs and does not touch the lhs of the function definition (which I implicitly wanted). – István Zachar Mar 19 '12 at 15:12
@Mr.Wizard I did mention the comparison of {} and {arg} as a general suggestion as well, in my answer. – Leonid Shifrin Mar 20 '12 at 0:07
@Leonid In no way did I mean to disparage your answer. I simply found all of this confusing. If you find any additional value in my answer feel free to include it in yours. If you choose to do this I will delete it; otherwise I will leave it. – Mr.Wizard Mar 20 '12 at 0:28
@Mr.Wizard Thanks, but in this case I'd keep things as they are, because we clearly interpreted the problem differently. I happenned to pick the interpretation that apparently was what Istvan was after, but IMO your answer is (as always) valuable. I did not vote for it this time though, since I think it solves a slightly different problem, but it does not mean that I find no value in it. Some people may come to this question having exactly the problem which your answer addresses and mine doesn't. – Leonid Shifrin Mar 20 '12 at 0:35

Why not use something like

f[first_, arg___] := {arg} === {"ArgValue"};


For general tests, you can compare {arg} to {}, to determine whether or not the arg is empty.

-
I was going to suggest the same, +1. Another possibility is default arguments. – Szabolcs Mar 16 '12 at 18:17
@Szabolcs Thanks. I thought about default args as well, but did not include them, since that would make things a bit more complex and can possibly create some corner cases which one has to keep in mind. – Leonid Shifrin Mar 16 '12 at 18:18
@Szabolcs: it won't work with default arguments, just change my code to: f[first_, arg___ : Automatic] := (arg === "ArgValue"), which fails the same way at f[1]. – István Zachar Mar 16 '12 at 18:23
@István It will, but you must use arg__ : Automatic, not arg___ : Automatic – Szabolcs Mar 16 '12 at 18:26
@Istvan When no argument is at all given, the optional part of the pattern comes into play, and effectively binds arg to Automatic, so in such case you effectively test Automatic==="ArgValue", which returns False. – Leonid Shifrin Mar 19 '12 at 10:45

This question and Leonid's interpretation of it don't make sense to me.

This definition:

f[first_, arg___] := (arg === "ArgValue")


Will give True for f[1, "ArgValue", "ArgValue"] while Leonid's method will not.

Perhaps you want:

ClearAll[f]
f[first_, arg : "ArgValue" ...] := {} =!= {arg}

{f[1], f[1, "ArgValue", "ArgValue"]}

{False, True}


Without seeing your application I can only guess what you are trying to accomplish. Why are you trying to avoid creating a second definition? If you want f[1] to return False isn't

f[_] = False


the cleanest way?

-
Yes, it is a good question why @István used arg___ and not arg_. If the aim is to allow either one or none at all, an optional argument with a default value is better. @István, can you clarify? – Szabolcs Mar 17 '12 at 14:38
@Szabolcs and if you don't like Default you could use something like: arg : RepeatedNull["ArgValue", 1] – Mr.Wizard Mar 17 '12 at 14:42
@Szabolcs, Mr.Wizard: I will try to make it more clear tomorrow, no time today. – István Zachar Mar 17 '12 at 19:27
@Mr.Wizard: I have added some clarifications to my question, hope it helps. The problem that Leonid's answer solves is that specific case (all other cases are handled in proper ways) when arg does not exist inside f but I still want to test its existence (but not its exact value, thus SameQ is somewhat unnecessary for the case). – István Zachar Mar 19 '12 at 10:46