BookmarkSubscribeRSS Feed

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.

12 Comments
Quentin
Super User
Agree, adding quote marks can force a character comparison. It's similar to my example %eval(Q&a=Q&b). If you add quotes, you need to be careful that leading or trailing blanks don't cause surprises. That is, "X " is not equal to "X" in the macro language.

I don't think there is a good way to force a numeric comparison.
Peter_C
Rhodochrosite | Level 12

@Quentin wrote:

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...

.......

I want to force %EVAL to do a character comparison, 

 


Would that not be the point where we can use macro quoting....

To obtain a string compare, instead of 

%put >>%sysevalf(5.0>15)<<;

use

%put >>%sysevalf(%str(5.0)>%str(15))<<;

 although it appears "laboured" for such a simple example, it indicates a way to clarify the intention  

needing no new functions...

 

PIty it doesn't achieve the string compare!

here is the SASlog

 58         %put >>%sysevalf(%str(5.0)>%str(15))<<;
 >>0<<
 59         
 60         %put >>%sysevalf(5.0>15)<<;
 >>0<<
 61