[racket] Why does (case ...) quote its matching value expressions?

From: Jon Zeppieri (zeppieri at gmail.com)
Date: Mon Dec 22 00:52:48 EST 2014

`case` is like C's `switch` (but unlike similar constructs in other
C-like languages) in that the case labels must be known at compile
time. This allows the compiler to generate especially efficient code.
If the label values are densely distributed, a decent C compiler will
usually generate a jump table. Racket's `case` can't do that, since
it's not implemented at a low-enough level, but it can generate, in
the best case, a vector lookup followed by an open-coded binary
search. In the worst case, it will use a hash table lookup followed by
an open-coded binary search. (If the number of constant labels is
below a set threshold, then `case` will just test them in order,
exactly as if you'd written a `cond` expression. That's what
`case/sequential-test` does.)

C's switch does, however, allow the use of constant *expressions* as
case labels, so you can have something like `case FOO % 3`, where `FOO
% 3` can be computed at compile-time. (In your example of `case x %
3`, unless the value of `x` is known at compile time, it would be
illegal in C, though legal certain languages that use a similar
syntax.) Racket's `case`, on the other hand, only allows plain-old
values.

This is limiting sometimes. For example, to get the very best
performance out of `case`, you need to use either fixnums or chars,
but if you're creating, say, a state machine, you probably want to use
symbolic names for your states. In C, you'd define an integer constant
and use the symbolic name as your case label. You can't do that with
Racket's `case`, however; if you want to use symbolic names, then
you'll actually be representing your states with symbols rather than
fixnums.

At any rate, if you actually need to do runtime computation in your
state labels, then neither C's `switch` nor Racket's `case` are
appropriate.



On Sun, Dec 21, 2014 at 11:58 PM, J Arcane <jarcane at gmail.com> wrote:
> Up with a horrible ear-ache this morning I decided to include a FizzBuzz
> example in Heresy, the Racket #lang I've been working on, and ran into an
> unexpected behavior in the (case ...) statement.
>
> In many languages with case, you can make the testing value a constant, and
> then make the matching clauses actual calculations which then match against
> that constant. So when doing FizzBuzz in C-like languages you can do
> something like "switch 0" and then "case x % 3" for the matching clauses.
>
> It turns out this doesn't work in Racket, because Racket quotes the values
> in the matching clauses so they do not evaluate. Specifically, it narrows
> down to doing this in (case/sequential-test ...): #`(equal? v 'k)
>
> I can implement an alternate version that works as I expect (and will
> probably include it in Heresy) just by removing that quote in my version,
> but I was curious as to the reasoning behind this behavior and if perhaps
> there's some explanation for it that I may've missed.
>
> Any insights appreciated,
> John Berry
>
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>

Posted on the users mailing list.