# Checking the argument of user-defined function with side-effect method

Now I would like to add the argument checking in this function. Then I used a method that Mr.Wizard answered

### Requirement for the arguments of Bernstein[n,i,u]

• n must be a integer like $1,2,3,...$;
• i must be a integer like $1,2,3,...$;
• i should between 0 and n-1.

For instance, the built-in BernsteinBasis gives the warning information as below:

BernsteinBasis[1.2, 2, 3]


BernsteinBasis::intnm: Non-negative machine-sized integer expected at position 1 in BernsteinBasis[1.2,2,3]. >>

BernsteinBasis[1.2, 2.1, 3]


BernsteinBasis::intnm: Non-negative machine-sized integer expected at position 1 in BernsteinBasis[1.2,2.1,3]. >>

BernsteinBasis::intnm: Non-negative machine-sized integer expected at position 2 in BernsteinBasis[1.2,2.1,3]. >>

BernsteinBasis[4, 5, u]


BernsteinBasis::invidx2:Index 5 should be a machine-sized integer between 0 and 4. >>

### checkArgs

Attributes[checkArgs] = {HoldAll};
(*check the number of arguments*)
checkArgs [func_[args___]] /; Length@{args} != 3 :=
Message[func::argrx, func, Length@{args}, 3]

(*check the type of the first arguments*)
checkArgs [func_[a_, b_, c_]] /; ! MatchQ[a, _Integer?NonNegative] :=
Message[func::intnm, func[a, b, c], 1]

(*check the type of second arguments*)
checkArgs [func_[a_, b_, c_]] /; ! MatchQ[b, _Integer?NonNegative] :=
Message[func::intnm, func[a, b, c], 2]

checkArgs[func_[a_, b_, c_]] /; ! (0 <= b <= a - 1) :=
Message[func::invidx, b, 0, a - 1]

(*other valid cases*)
checkArgs[other_] := True


### Main implementation

Bernstein::invidx =
"The index 1 should be a non-negative machine-sized integer betwwen 2 and 3.";

SetAttributes[Bernstein, {Listable, NHoldAll, NumericFunction}]
(*special cases*)

Bernstein[n_, i_, u_]?checkArgs /; i < 0 || i > n := 0

Bernstein[0, 0, u_]?checkArgs := 1

Bernstein[n_, i_, u_?NumericQ]?checkArgs :=
Binomial[n, i] u^i (1 - u)^(n - i)

(*expansion of the basis of Bernstein*)
Bernstein /: PiecewiseExpand[Bernstein[n_, i_, u_]] :=
Piecewise[
{{Binomial[n, i] u^i (1 - u)^(n - i), 0 <= u <= 1},
{0, u > 1 || u < 0}}]

(*the derivatives of the basis of Bernstein*)
Bernstein /: Derivative[0, 0, k_Integer?Positive][Bernstein] :=
Function[{n, i, u},
D[
n (Bernstein[n - 1, i - 1, u] - Bernstein[n - 1, i, u]),
{u, k - 1}]
]


However, it gives the following information.

$RecursionLimit::reclim: Recursion depth of 256 exceeded. >>$RecursionLimit::reclim: Recursion depth of 256 exceeded. >>

$RecursionLimit::reclim: Recursion depth of 256 exceeded. >> General::stop: Further output of$RecursionLimit::reclim will be suppressed during this calculation. >>

Bernstein::intnm: Non-negative machine-sized integer expected at position >Bernstein[n_,i_,u_] in 1. >>

### Update

Thanks for Mr.Wizard's revision that adding HoldForm in checkArgs to remove the recursion.

In addition, Mr.Wizard given me a hint that ultilizing the Message as a side-effect in the comment

Now I have a reference here

SyntaxInformation[f] = {"ArgumentsPattern" -> {_}};
f[1] := True
f[_] := False
f[x___] /; Message[f::argx, "f", Length@{x}] := Null


I just remembered why I don't use this in my packages... if you have different messages being thrown based on the form of the input (as I often have), then throwing messages as a side-effect of not matching the form will result in all messages being thrown

However, this demo just for one argument, and when the number of argument greater than $1$, I have any idea to deal with Message with side-effect.

• @SjoerdC.deVries, I know the built-in BernsteinBasis applied the UpValues method. For instance, D[BernsteinBasis[5, 3, u], {u, 2}]. In addition, BernsteinBasis[3., 1., u] gives the warning information normally.
– xyz
Jul 22, 2015 at 15:13
• @Mr.Wizard, In this case, I used your "Fall-through method " , however, it failed. Could you help me if you have time?
– xyz
Jul 23, 2015 at 0:59
• @ShutaoTang @name notifications only work of a user has already commented on the post therefore I did not see your notice. However I saw this now due to the recent edit. If I have time today I shall attempt to answer this. Jul 23, 2015 at 12:15
• @Mr.Wizard, Thanks a lot.:-) Now I am trying to apply your methods that hand error-message in my functions. However, this time I failed and I didn't why.
– xyz
Jul 23, 2015 at 12:21

I have given your code only a cursory read but I think I spotted a (the?) problem: your Message code uses an unheld equivalent of the test expression itself. This cannot work. If the expression would generate a Message the first time it would even within Message and you will get infinite recursion. Use HoldForm to prevent this:

(*check the type of the first arguments*)
checkArgs[self : func_[a_, b_, c_]] /; ! MatchQ[a, _Integer?NonNegative] :=
Message[func::intnm, HoldForm[self], 1]

(*check the type of second arguments*)
checkArgs[self : func_[a_, b_, c_]] /; ! MatchQ[b, _Integer?NonNegative] :=
Message[func::intnm, HoldForm[self], 2]


With this correction your code no longer produces a recursion error on definition, however I get:

Bernstein::intnm: Non-negative machine-sized integer expected at position 1 in Bernstein[n_,i_,u_]. >>

I believe this comes from the limited evaluation that takes place during function definition and I think the definition will still be made correctly, but I'll have to check that later.

Separately I think you can and probably should be including checkArgs in the TagSet definition:

Bernstein /: PiecewiseExpand[Bernstein[n_, i_, u_]?checkArgs] := . . .


However again I haven't made an attempt to test this definition itself. If you have additional problems please note them in the question and I shall try to help when I return to this.

• +1,THX, Now I utilize the followng cases: Bernstein[3.2, 1, u] ,Bernstein[3, 1.2, u] and Bernstein[5, 6, u] to test the funtion Bernstein and then they give the desired error informtion respectively. However, I would like to how inplement the checkArg to make the Bernstein[3.2, 1.2, u] return two error-message like BernsteinBasis[3.2, 1.2, u]
– xyz
Jul 23, 2015 at 13:45
• @Shutao If you want more than one error message you can issue the Message as a side-effect rather than a match on checkArgs. The evaluator would then try all of the checks rather that stopping after the first Message. However if you want all messages to fire I think it is actually better or at least easier to make the definition upon the primary function (Bernstein). The methods I described were posted in response to the implied desire not to issue multiple messages. Jul 23, 2015 at 14:15
• The Toad's comment: throwing messages as a side-effect of not matching the form will result in all messages being thrown. But , for me, I don't know how to implement this(throwing messages as a side-effect). So could you give me a demo by this Bernstein case? ThX!
– xyz
Jul 23, 2015 at 14:35
• @Shutao FYI I am not ignoring you; I've just got other things to work on too. Jul 24, 2015 at 11:58