[plt-scheme] Best style on argument checking...

From: Paulo J. Matos (pocm at soton.ac.uk)
Date: Mon Mar 26 15:19:25 EDT 2007

Hello all,

I'd like suggestions on style about arguments checking.
This happens to me (and I'm sure to you too) regularly. Guess [to
exemplify] you want to define a function with 3 arguments, 2 of them
optional. The first obligatory argument should be a string, the second
a number and the third a symbol. You just want to append them all and
return a string.

No arguments checking is easy:
(define (append-all str . args)
  (string-append str
                 (if (>= (length args) 1) (number->string (car args)) "")
                 (if (= (length args) 2) (symbol->string (cadr args)) "")))

Problem is str might not be a string and the rest of the arguments may
not have correct type. And args can have 3 arguments [probably we
would like to warn the user about it].

So, the other chance is:
(define (append-all1 str . args)
  (if (<= (length args) 2)
      (let ([str-ok? (string? str)]
            [arg2-ok? (or (null? args)
                          (number? (car args)))]
            [arg3-ok? (or (< (length args) 2)
                          (symbol? (cadr args)))])
        (if (and str-ok? arg2-ok? arg3-ok?)
            (string-append str
                 (if (>= (length args) 1) (number->string (car args)) "")
                 (if (= (length args) 2) (symbol->string (cadr args)) ""))
            (error "args not of correct type but I cannot say which")))
      (error "usage is append-all1 string [number] [symbol], you
passed in too many arguments")))

or even this:
(define (append-all2 str . args)
  (cond [(> (length args) 2)
         (error "too many arguments")]
        [(not (string? str))
         (error "first argument needs to be a string")]
        [(not (or (null? args)
                  (number? (car args))))
         (error "second argument needs to be a number")]
        [(not (or (< (length args) 2)
                  (symbol? (cadr args))))
         (error "third argument needs to be a symbol")]
         (string-append str
                        (if (>= (length args) 1) (number->string (car args)) "")
                        (if (= (length args) 2) (symbol->string (cadr
args)) ""))]))

I tend to switch between variants of the first way (this cond'ified
check is just something that came up while thinking about the issue).
However, I might guess other options are:
- contracts, however, I'm not sure if they help you checking the types
of the optional arguments and the number of optional arguments, I
don't think they do.
- typed-scheme (?!?), not really sure about this one but that would
probably require you to type variables also within the function which
you might not want to do.

So, given that you have pure scheme, what would be the best style to
do this (hopefully portably since this is a general scheme problem)?

Paulo Jorge Matos - pocm at soton.ac.uk
PhD Student @ ECS
University of Southampton, UK

Posted on the users mailing list.