Errors resulting from number/string confusion are extremely difficult to debug due to several factors:
- TLisp doesn't have typed variables.
- The console displays strings without quotes wherever possible, making them difficult to distinguish from other data types.
- Some functions automatically convert string arguments to numbers, others return errors (which may be swallowed by their callers), and others have unpredictable behavior.
- Even with recent improvements, the function help doesn't specify the types of arguments and return values for most functions.

I think the simplest solution that would address most of the problem is for all functions that require numerical arguments to use a single helper function to convert strings if possible, and return an error if a string isn't a well-formatted number.

Here's some of the faulty code that prompted this. Why the block is never evaluated is left as an exercise for the reader:

(if (and (setq range (xmlGetAttrib theXML 'maxRadius))
		(gr range 0)
	)
	(block ...)
)
george moromisato on 7/21/2017 5:44 PM:

This is caused by overzealous argument-checking in function parameters. Most functions specify the type of arguments (integer, string, etc.) and if the caller passes the wrong type, we return an error.

(Some functions explicitly allow any type.)

Note that this check only happens when passing the arguments to the function. Inside the function itself, we automatically convert from string to integer (and vice versa). Thus fixing the arg-checker would be relatively easy.

We could do one of the following fixes:

  • Allow string, ints, and doubles to be interchangeable as far as the arg-checker is concerned. We might miss some errors, but it might be worth it. This is the easiest fix.
  • A slightly more complex fix is to check to see if a string really is a number or not. For example, if a function expects an integer and the caller passes a string, we could check to see if the string really is an int. If not, we would return an error as normal. Since this is slightly expensive, we might do such a check only in debug mode.
nms on 7/21/2017 8:18 PM:

Either would be an improvement. It seems better to return an error rather than convert an unparseable string to 0 or partially parse a string that begins with a number. But I think those mistakes are rare and easier to debug compared to passing a parseable number string to a function that doesn't accept it. So error checking is probably not necessary if it's difficult or performance impacting.

george moromisato on 9/13/2017 11:37 PM:

I added code to automatically convert strings to numbers. Currently it returns an error if we expect an integer but we cannot convert the string. [For doubles, we always return 0.0 if we cannot convert because of limitations in the library.]

Unfortunately, this does not solve your problem with (gr ...). I didn't want to convert those because it would break backwards compatibility.

To handle this I've made two additional fixes:

  1. The new relational operators (=, >, <, >=, <=) all coerce strings to numbers as appropriate (but only if the other value is a number). To use these operators you will need to wrap your code in <![CDATA[ ... ]]>
  2. More usefully, I've changed xmlGetAttribute so that it returns a number or a string, depending on what it's got. This should solve your problem without additional code.