I would like to specify the following (which doesn't work) for the return values of a function:
(or/c (values t1 t2)
(values t3 t4))
In other words, I'd like to verify that either the function returns two values of types t1 & t2, respectively, or the function returns two values of types t3 & t4, respectively, but not, for example, two values of types t1 & t4.
or/c is expecting a single value. Any thoughts about how to accomplish this?
P.S. It looks like someone may have marked the previous reply solved prematurely, maybe an admin/moderator? May I humbly suggest we wait a period of time to allow the OP to mark a solution before doing so on their behalf? I was busy yesterday evening, so I was only able to test the solution today.
I took a quick look at the issue and yes, perhaps this was a bad choice on my part in the design of the syntax of the range of function contracts! The use of values there is purely syntactic; it is really a kind of "keyword" that's attached to -> and friends. This was done in the days before keywords, I belive (or maybe before I realized I should have used them). If it had been something like:
(-> integer? #:values boolean? boolean?)
(-> integer? (values boolean? boolean?))
maybe it would have been a lot cleaner. Or maybe even #:results or something to indicate where arguments end and results begin.
Yikes - when I incorrectly opened that racket-mode github issue, I had completely forgotten about this discourse thread I started, and the fact that I have an example of what I wanted to do in another project - embarrassing!
Ok, I see. I hadn’t thought of that! But that kind of optimization in this particular context is still a head-scratcher for me. Clearly you want to make some guarantees about the return value here, or you wouldn’t be using contracts. But the contracts themselves introduce a performance penalty that I would assume is far higher than that of the allocation of a single cons cell. If you’re already willing to incur that penalty, why not go a little further and do it in a way that actually makes the guarantee you want to make?
(No shade here; again I’m just curious. I’ve already learned something by asking one dumb question so I figure I’ll just keep going. I’ve never had to deal with the kind of problems where avoiding allocating cons cells made a difference.)
cpu time: 1279 real time: 1197 gc time: 406
cpu time: 2044 real time: 1991 gc time: 660
You can get an even more performant version by using multiple values within the module boundary, and switch to cons across module boundaries. But that seems cumbersome and not worthwhile doing, unless this part of the program is really performance-sensitive.
I design my functions independently of contracts. Contracts are optional, and in some cases, I'll turn them off, for performance, or other, reasons. They're more of a benefit to me during development and testing, than in production.
So, when I consider the performance of a function, I do so w/o regard to contracts i.e. "what's the right thing for this function to do if there was no contract".