From: una@phy.duke.edu (Una Smith)
Newsgroups: bit.listserv.sas-l
Subject: Re: Automatic char/num conversions
Summary: Digits NE numbers, digits EQ symbols
Date: 11 Apr 92 14:58:52 GMT
Article-I.D.: news.2336
Organization: Duke University Physics Dept.; Durham, N.C.

todd pukanecz <CCCS@VTVM1.BITNET> writes:

>  As I recall, SAS used to do alot of conversions between numeric characters
>and actual numbers fairly easily and automatcially.  This appears to no
>longer be the case, as the LOG below indicates.  The variable BREED is
>character in the permanent datasets that are used to make the temporary
>dataset, VIRGINIA.
>  I corrected the program by enclosing the digits in quotes, and now it
>runs fine.  My gripe is that this is an older program, there are probably
>others like this, and whatever happened to backward compatability?
>Do others have this problem, or am I all wet in my assumptions and
>recollections?

[stuff deleted]

>9          DATA SPNGH; SET VIRGINIA;
>10           IF YEAR>88 THEN WEIGHT=WEIGHT/NUMBER;
>11           IF BREED=1 THEN BRD='HEREFORD';
>12           IF BREED=2 THEN BRD='ANGUS';
>13           IF BREED=5 THEN BRD='ANGUSX';
>14           IF BREED=7 THEN BRD='CHARX';
>15           IF BREED='H' THEN BRD='HEREFORD';
>16           IF BREED='A' THEN BRD='ANGUS';
>17           IF BREED='AX' THEN BRD='ANGUSX';
>18           IF BREED='C' THEN BRD='CHARX';
>19           IF BREED='CX' THEN BRD='CHARX';

[more stuff deleted]

First, SAS has not changed.  Automatic conversions between
character and numeric data types still work.  They are still
*expensive* in terms of CPU, and they are still *very dangerous*.
It may be convenient to allow SAS to perform automatic type
conversions for you as you begin to hash out new program
codes, but for efficiency, good form, and (most importantly)
correctness of the program, you must convert data types 
explicitly.

Now, as for the behavior of your program, that seems entirely
standard.  No surprises there, although I suggest you remove
the block of IF statements and use a FORMAT instead, like this:

OPTIONS ERRORS=5;  * useful for debugging programs--try it! ;

PROC FORMAT;
   VALUE $BREEDFMT
   '1','H'      = 'Hereford'
   '2','A'      = 'Angus'
   '5','AX'     = 'AngusX'
   '7','C','CX' = 'CharX'
   ;
   
DATA SPNGH;
   SET VIRGINIA;
   IF YEAR>88 THEN WEIGHT=WEIGHT/NUMBER;
   FORMAT BREED $BREEDFMT.;
   
This code replaces entirely the code you gave in your posting,
it runs a lot faster (I promise!), and it eliminates the need
for the new character variable, BRD, that you created in lieu
of applying a format to BREED.

Why did you get those annoying SAS messages about invalid data?

Answer:  By using the expression "BREED = 1" naming the variable
BREED for the first time in the data step, you tell SAS that BREED
is numeric.  But BREED already exists, and is a character variable
(as you knew).  Since you told SAS to treat BREED as a numeric
variable, SAS first converts the contents of BREED from character
to numeric, then compares the result to the right-hand term of the
expression.  You initially supplied both digits and letters, w/out
quotes around them.  Digits may be either characters or numbers,
depending on how you choose to use them.  SAS tells these two types
apart by whether or not they are imbedded in quotes.  Non-digit
symbols can only be of type character, thus you force SAS to convert
AX into a number (ie, the special missing value), then compare it
to the result of another un-necessary type conversion of BREED from
character to numeric.

Not good.  The problem here is your own confusion between the symbolic
nature of the things we call digits, and and the absolute nature of
the things we call data types.  Digits are not numbers, and neither
are strings of digits, *unless* we "declare" them to be numbers.

Now, you may not want to use a FORMAT such as I've written for you
above, but there are better ways of doing what you want than using
IF statements.  You should at least be using IF/ELSE IF (and both
digits and letter codes must be inside quotes, as ever), like this:

   IF      BREED='1' THEN BRD='HEREFORD';
   ELSE IF BREED='2' THEN BRD='ANGUS';
   ...
   
Even better, use the SELECT/WHEN statement, like this:

   SELECT(BREED);
      WHEN('1') BRD='HEREFORD';
      WHEN('2') BRD='ANGUS';
      ...
      OTHERWISE;
      END;

Hope this help.

	Una Smith
	
-- 

Una Smith   una@phy.duke.edu    School of the Environment
                                Duke University
                                Durham, NC  27706
Comments: Gated by NETNEWS@AUVM.AMERICAN.EDU