34
$\begingroup$

I never used Asserts in Mathematica, but trying to see what advantage they have over just argument check and additional definitions of the function to capture unwanted input.

For example, which one of these 2 would you think is better?

ClearAll[f]
f[x_] := (Assert[x > 0]; Sqrt[x])
On[Assert];
f[2.]
f[-2.]

The last call above generated in the console a beep and a message:

Assert::asrtf: Assertion -2.>0 failed. >>

But I could also just write

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

f[2.]
f[-2.]

and the second call will return unevaluated

f[-2.]

and If I want a beep, I could always do something like

ClearAll[f];
f[x_] := Sqrt[x] /; x > 0
f[x_] := Throw["f[x] not supported for negative values"]

or something along these lines.

Since asserts seem to be used to assert that input to a function is within the ranges supported by the function, what benefit they have over the other method shown above?

Or should one look into using Asserts inside the function itself, i.e. in the middle of a computation, to check that intermediate results are within expected ranges? But also then, I would use a simple If check instead, and return an error code to the caller (which I prefer) or use Throw. An example from help shows this:

myFun[x_] :=
 Block[{y},
  y = x^2;
  Assert[y > 5];
  Sin[y]
  ]

So that the call On[Assert]; myFun[1.0] generated Assert::asrtf: Assertion y>5 failed.

But I can write instead

myFun[x_] :=
 Block[{y},
  y = x^2;
  If[y <= 5, Throw["y<=5"]];
  Sin[y]
  ]

and now the call myFun[1.0] will also generate a message and a beep as well from the same place.

I guess I am looking for when in Mathematica the use of Assert would be better and recommended over these other ways of checking.

My only guess now is that Assertion code can be disabled and enabled more easily, and this can have an effect on run time. i.e. after testing the code, I can disable Asserts from the final version, and it should run faster, since all these checks are not being done at run time any more. But with the manual checking as above, that code remains there all the time.

thanks

$\endgroup$
2
  • 1
    $\begingroup$ You're right, one of the main features of assertions, both in Mathematica and in C, is that they can be turned off. They are meant for debugging: I use them to check myself. Taking your first example, if f is an internal function, and my intention is never to call it with negative arguments, I'll put Assert[x>=0] at the beginning. I might make a mistake somewhere which causes f to be called with a negative argument anyway. This will be caught by the assertion. Once the program is debugged, I can disable assertions so there's no overhead from them. $\endgroup$
    – Szabolcs
    Apr 12, 2013 at 15:55
  • 2
    $\begingroup$ However, if f is a public function that the users of my package call, then I have no control over what they pass to it. I need a permanent check I'll never turn off and I won't use Assert. I will try to make sure that the checks I include are not too slow because they won't be turned off. With Assert performance is not really an issue because it'll be turned off eventually anyway, so, at least when writing C, I'll sprinkle the code with plenty of assertions. They are merely means to catch and find my own mistakes more easily. $\endgroup$
    – Szabolcs
    Apr 12, 2013 at 15:57

1 Answer 1

31
$\begingroup$

Like in other programming languages, such as C or Java, assertions are used to catch errors in the logic of your code. With discipline, you can also use exceptions for a similar purpose (see e.g. this discussion for an example).

Using patterns and returning a function unevaluated is useful in different types of situations. The linked above answer also discusses when which is more appropriate. Very roughly, there are 3 different situations:

  1. You want to pre-emptively catch certain errors in your logic, since you know that certain things definitely can not normally happen. At the same time, these checks can not be easily reduced to input argument checks. And, finally, the error, if occurs, is purely in your logic, and otherwise things are within your control. Then, use assertions. I would not use assertions to filter out unwanted input - this is what pattern-checks in function definitions are for. Using asserts in their place would typically make code clumsier, more fragile and less readable.

  2. Your function can not move further with its computations, since either wrong arguments were supplied or something beyond your control happened (file not found on disk say). Then, return $Failed or use exceptions (but be sure to use tagged exceptions and catch them in the outer - public- functions).

  3. The function does not know what to do with the input, but there is a chance that the input may evaluate to something meaningful at some later point. Then, returning unevaluated may make more sense.

Generally, functions which do not return anything and whose results are some performed actions, tend to be candidates for 1. or 2., while functions returning expressions are more often candidates for 3. But these are just general guidelines, and one has to develop the intuition to know when to follow these rules and when to break them.

$\endgroup$
2
  • 2
    $\begingroup$ @Nasser In complicated program, you can use Asserts to assert for example that a variable must have specific value e.g. Assert[x>0]. If the change you program at some other part an violate this assert you will see a message. The good thing is that the Assert is only on in a "Debug" phase. $\endgroup$
    – user21
    Jan 18, 2012 at 10:16
  • $\begingroup$ @ruebenko Thanks for the note on a debug phase - I wanted to include that but forgot. This is indeed another important argument in favor of asserts, in cases when they fit. $\endgroup$ Jan 18, 2012 at 10:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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