[racket] contracts on liberal function inputs: avoiding duplicate effort

From: Matthew Butterick (mb at mbtype.com)
Date: Mon Nov 18 12:03:19 EST 2013

In a function that permits liberal inputs, I often find that the input processing I do in a contract is duplicated at the beginning of the body of the function. Is this avoidable?

Certain functions want to be liberal with input because there are multiple common ways to represent the data. For instance, I have a function that operates on CSS RGB colors. This function should be prepared to accept these forms of input & understand that they're all the same:

"#c00"
"#cc0000"
'("204" "0" "0")
#xcc0000
'(0.8 0 0)

Let's say that my internal representation of an RGB color is described by the contract rgb-color/c:

(define rgb-color/c (list/c (real-in 0 1) (real-in 0 1) (real-in 0 1)))

But I can't use rgb-color/c as the input contract for the function because it's too narrow. So I make a second contract that tests for things that can be converted to an rgb-color:

(define (rgb-colorish? x) (or/c rgb-color/c [tests for the other input formats ...] )

To determine if the input is rgb-colorish?, this contract usually just ends up trying to convert the input to rgb-color. If it works, then the contract returns true.

But after the contract returns, I have to convert the input to an rgb-color anyhow. So I'm doing exactly the same work that the contract just finished. If the conversion is expensive, I'm doing it twice.





Posted on the users mailing list.