Because the macro language is not typed (i.e. all values are text strings, rather than being defined as numeric or character) both %Eval and %SysEvalF must do some "guessing" to determine whether to treat text string as a character value or a numeric value. I would propose to add %EvalC which would always to character evaluation (even if the argument looked like a number) and %EvalN which would always do numeric evaluation (and if the argument could not be interpreted as a number, would return an error).
For example,
1.
%put >>%eval(5.0>15)<<;
Returns true, because %eval does not know about decimals. When it sees the decimal, it decides the argument is a character string and does a character (alphabetical) comparison. This is probably not then result intended by the person who wrote the SAS code.
2.
%put >>%sysevalf(5.0>15)<<;
Returns false. %SYSEVALF knows that decimals are numbers and therefore does a numeric comparison as intended. %SYEVALF also knows about SAS date literalals, and lots of other numbers, which is good.
3.
%put >>%sysevalf(793221D360=)<<;
Fails (on linux 9.3) with an overflow error. Here, the user intended a character comparison to check for null, which should return false. But %SYSVALF saw a number written in exponential notation (D is interpretted same as E) which caused the overflow.
I think these examples all result from the flexibility designed into %EVAL and %SYSEVALF to handle both character values and numeric values. I would prefer an additional pair of functions which did NOT have this flexibity. So %EvalN(5.0>15) would return true, because it would know that decimals are numeric (and dates and exponential notation and everything else %sysevalf knows). But %EvalN(b>a) would return an ERROR, because the values could not be intrepreted as numeric. Similarly %EvalN(1e2=100) would return true, but %EvalC(1e2=100) would return false, because %EvalC would do a character comparison despite the fact that the argument looks like a number.
Without these functions, if I want to force %EVAL to do a character comparison, a hack workaround is to add a text character so that it cannot look like a number, e.g. %EVAL(Q&a=Q&b). But that's ugly. And I don't think there's a good way to force %EVAL to do a numeric comparison or error on a character value (without inserting my own logic to catch character values).
As a developer, if I write a %IF statement (with implied %eval) or explicit %EVAL / %SYSEVALF, in my design mind I know whether I am intending a numeric comparison or a character comparison. It would be useful to be able to communicate this intent in my code, rather than let %EVAL / %SYSEVALF guess as to my intent.
Would welcome thoughts/comments from others.
... View more