Next: , Previous: , Up: syntaxes   [Contents][Index]


5.5 Validating signatures

The following syntactic bindings are exported by the library (vicare).

Syntax: assert-signature ?signature ?expr
Syntax: assert-signature-and-return ?signature ?expr
Syntax: cast-signature ?signature ?expr

Validate the type signature of the values returned by ?expr, either at expand–time or run–time. ?expr can be any Scheme expression. ?signature must be a proper or improper list of type annotations representing the type signature.

The syntax assert-signature returns a single unspecified value. The syntax assert-signature-and-return returns the return values of ?expr with the original type signature of ?expr. The syntax cast-signature returns the return values of ?expr with the type signature ?signature.

(type-of 123)
⇒ #[signature (<positive-fixnum>)]

(type-of (assert-signature-and-return (<top>) 123))
⇒ #[signature (<positive-fixnum>)]

(type-of (cast-signature (<top>) 123))
⇒ #[signature (<top>)]

If it is possible to validate the signature at expand–time: when successful, the syntax use just expands to the evaluation of ?expr; when a type mismatch is detected, an expand–time exception is raised. Otherwise the syntax use expands to an expression that validates the values at run–time.

As special cases, when ?signature is ‘()’, a proper or improper list of <top> and <list> types like:

<list>
(<top>)
(<top> <top> <top>)
(<top> <top> . <list>)

no validation is performed at run–time, only at expand–time.

Here are some validation examples:

(assert-signature () (values))
(assert-signature-and-return (<fixnum>) 123)    ⇒ 123
(assert-signature-and-return (<string>) "ciao") ⇒ "ciao"

(assert-signature-and-return (<fixnum> <flonum>) (values 1 2.0))
⇒ 1 2.0

(expansion-of
  (assert-signature (<fixnum>) 123))
⇒ (begin (quote 123) (quote #!void))

(expansion-of
  (assert-signature-and-return (<fixnum>) 123))
⇒ (quote 123)

(expansion-of
  (assert-signature-and-return (<fixnum>)
    (unsafe-cast-signature <fixnum> (read))))
⇒ ((primitive read))

There are some interesting special cases:

Expansion examples for run–time validation

Let’s say we have a function ‘fun’ such that:

(type-of (fun))
⇒ #[signature <list>]

there is nothing the expander can do to infer the type signature of the function application.

Example 1: multiple values and return values

The following syntax use:

(assert-signature-and-return
    (<fixnum> <flonum> <string>)
  (fun))

is expanded to:

(call-with-values
    (lambda () (fun))
  (lambda (arg1 arg2 arg3)
    (values ((lambda (obj value-index caller-who)
               (if (fixnum? obj)
                   obj
                 (expression-return-value-violation
                     caller-who
                   '"return value of invalid type"
                   value-index '(is-a? _ <fixnum>) obj)))
             arg1 '1 'assert-signature-and-return)
            ((lambda (obj value-index caller-who)
               (if (flonum? obj)
                   obj
                 (expression-return-value-violation
                     caller-who
                   '"return value of invalid type"
                   value-index '(is-a? _ <flonum>) obj)))
             arg2 '2 'assert-signature-and-return)
            ((lambda (obj value-index caller-who)
               (if (string? obj)
                   obj
                 (expression-return-value-violation
                     caller-who
                   '"return value of invalid type"
                   value-index '(is-a? _ <string>) obj)))
             arg3 '3 'assert-signature-and-return))))

Example 2: multiple values and no return values

The following syntax use:

(assert-signature
    (<fixnum> <flonum> <string>)
  (fun))

is expanded to:

(call-with-values
    (lambda () (fun))
  (lambda (arg1 arg2 arg3)
    ((lambda (obj value-index caller-who)
       (if (not (fixnum? obj))
           (expression-return-value-violation
               caller-who '"return value of invalid type"
               value-index '(is-a? _ <fixnum>) obj)
         '#!void))
     arg1 '1 'assert-signature)
    ((lambda (obj value-index caller-who)
       (if (not (flonum? obj))
           (expression-return-value-violation
               caller-who '"return value of invalid type"
               value-index '(is-a? _ <flonum>) obj)
         '#!void))
     arg2 '2 'assert-signature)
    ((lambda (obj value-index caller-who)
       (if (not (string? obj))
           (expression-return-value-violation
               caller-who '"return value of invalid type"
               value-index '(is-a? _ <string>) obj)
         '#!void))
     arg3 '3 'assert-signature)
    (void)))

Example 3: list of values and return values

The following syntax use:

(assert-signature-and-return
    (list-of <fixnum>)
  (fun))

is expanded to:

((lambda arg1
   (lambda (list-value first-value-index caller-who)
     (fold-left
         (lambda (item-index item-value)
           ((lambda (obj value-index caller-who)
              (if (not ((letrec
                            ((pred (lambda (obj)
                                     (if (pair? obj)
                                         (if (fixnum? (car obj))
                                             (pred (cdr obj))
                                           '#f)
                                       (null? obj)))))
                          pred)
                        obj))
                  (expression-return-value-violation caller-who
                    '"return value of invalid type"
                    value-index '(is-a? _ (list-of <fixnum>))
                    obj)
                '#!void))
            item-value item-index caller-who)
           (fxadd1 item-index))
       first-value-index list-value)
     list-value))
 (fun))

Example 5: multiple values and return values

The following syntax use:

(assert-signature-and-return
    (<fixnum> <flonum> . (list-of <fixnum>))
  (fun))

is expanded to:

(call-with-values
    (lambda () (fun))
  (lambda (arg1 arg2 . arg3)
    (apply values
           ((lambda (obj value-index caller-who)
              (if (fixnum? obj)
                  obj
                (expression-return-value-violation
                    caller-who
                  '"return value of invalid type"
                  value-index '(is-a? _ <fixnum>) obj)))
            arg1 '1 'assert-signature-and-return)
           ((lambda (obj value-index caller-who)
              (if (flonum? obj)
                  obj
                (expression-return-value-violation
                    caller-who
                  '"return value of invalid type"
                  value-index '(is-a? _ <flonum>) obj)))
            arg2 '2 'assert-signature-and-return)
           (lambda (list-value first-value-index caller-who)
             (fold-left
                 (lambda (item-index item-value)
                   ((lambda (obj value-index caller-who)
                      (if (not ((letrec
                                    ((pred (lambda (obj)
                                             (if (pair? obj)
                                                 (if (fixnum? (car obj))
                                                     (pred (cdr obj))
                                                   '#f)
                                               (null? obj)))))
                                  pred) obj))
                          (expression-return-value-violation
                              caller-who
                            '"return value of invalid type"
                            value-index
                            '(is-a? _ (list-of <fixnum>)) obj)
                        '#!void))
                    item-value item-index caller-who)
                   (fxadd1 item-index))
               first-value-index list-value)
             list-value)
           arg3 '3 'assert-signature-and-return)))

Example 5: single value and return values

The following syntax use:

(assert-signature-and-return
    (<fixnum>)
  (fun))

is expanded to:

((lambda (arg1)
   ((lambda (obj value-index caller-who)
      (if (fixnum? obj)
          obj
        (expression-return-value-violation caller-who
          '"return value of invalid type"
          value-index '(is-a? _ <fixnum>) obj)))
    arg1 '1 'assert-signature-and-return))
 (fun))

Example 6: no validation and single return value

The following syntax use:

(assert-signature-and-return
    (<top>)
  (fun))

is expanded to:

(fun)

there is no need to insert a validation form because a single value of any type matches the type signature.

Example 7: no validation and return values

The following syntax use:

(assert-signature-and-return
    <list>
  (fun))

is expanded to:

(fun)

there is no need to insert a validation form because any number of return values of any type matches the type signature.


Next: , Previous: , Up: syntaxes   [Contents][Index]