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?
It appears Sorawee's solution works perfectly. The contract is for a class method; hence, the entry for this. I'm very impressed with Racket's contract system!
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?)
instead of
(-> 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!
I only saw it because I came here to ask my question about using values in contracts (occasioned by your recent issue) and it popped up on the "similar topics" list on the right while I was typing.
Further curiosity: when you want to return two values that are guaranteed to be either string and integer or#f and #f, is there a particular reason you want values rather than, say, cons/c?
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.)
Yeah, the overhead of ->i is pretty significant. The following program shows that the contracted values variant could be noticeably slower than the cons variant.
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".