Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

With case, which is the best of these methods for expressing the cases?

These all work:

(defun testcaseexpr (thecase)
  (case thecase
    ('foo (format t "matched foo"))
    (bar (format t "matched bar"))
    ((funk) (format t "matched funky"))))

Which of these three expressions is considered the idiomatic way? And perhaps as a side point, why are they all working, when clearly they are not the same syntax. In fact in other contexts they have different semantics completely. A list (funk) is certainly not the same as a quoted atom, 'foo. Yet just passing in the words foo bar and funk all work the same.

like image 548
johnbakers Avatar asked Nov 14 '13 12:11

johnbakers


People also ask

How do you use a case in order by clause?

CASE Syntax: CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 WHEN condition3 THEN result3 ELSE result END; ORDER BY: This keyword is used to sort the result-set in ascending or descending order. It sorts the records in ascending order by default.

Where do you put case statements in SQL?

The case statement in SQL returns a value on a specified condition. We can use a Case statement in select queries along with Where, Order By, and Group By clause. It can be used in the Insert statement as well.

Can we use case in SELECT statement?

CASE can be used in any statement or clause that allows a valid expression. For example, you can use CASE in statements such as SELECT, UPDATE, DELETE and SET, and in clauses such as select_list, IN, WHERE, ORDER BY, and HAVING.

Which of the following is the syntax for CASE statement?

Which of the following is correct syntax for CASE statement? Explanation: The CASE statement is started with the keyword CASE followed by any identifier or expression and the IS.


1 Answers

First, note that you've actually only got two cases here. 'foo is expanded by the reader as (quote foo), so your code is equivalent to

(defun testcaseexpr (thecase)
  (case thecase
    ((quote foo) (format t "matched foo"))
    (bar         (format t "matched bar"))
    ((funk)      (format t "matched funky"))))

wherein the first and third cases have the same structure; the keys part of the clause is a list of objects.

Perhaps this question is off-topic, since it's asking for the “best”, and that might be primarily opinion based. I agree with the points made in wvxvw's answer, but I tend to use the style you've shown in the third case almost exclusively. I've got a couple reasons for this:

It's the most general form.

It's the most general form. In the documentation for case, we read that in an normal-clause ::= (keys form*) keys is a designator for a list of keys. This means that a clause like (2 (print 'two)) is equivalent to ((2) (print 'two)). You never lose anything by using a list instead of a non-list, but if you have some clauses with multiple objects and some with single objects, you'll have consistent syntax for all of them. E.g., you can have

(case operator
  ((and or) ...)
  ((if iff) ...)
  ((not)    ...))

It's harder to mess up.

It makes it harder to mess up the special cases of t and otherwise. The documentation says about keys that (emphasis added):

keys—a designator for a list of objects. In the case of case, the symbols t and otherwise may not be used as the keys designator. To refer to these symbols by themselves as keys, the designators (t) and (otherwise), respectively, must be used instead.

In practice, some implementations will let you use t and otherwise as keys in normal-clauses, even though it seems like this shouldn't be allowed. E.g., in SBCL:

CL-USER> (macroexpand-1 '(case keyform
                          (otherwise 'a)
                          (otherwise 'b)))


(LET ((#:G962 KEYFORM))
  (DECLARE (IGNORABLE #:G962))
  (COND ((EQL #:G962 'OTHERWISE) NIL 'A)
        (T NIL 'B)))

Using explicit lists removes any ambiguity about what you're trying to do. Even though t and otherwise are called out specifically, keys is a list designator, which means that nil (an atom and a list) needs some special consideration. Will the following code produce a or b? (Can you tell without testing it or checking the spec? This case is actually highlighted in the examples.)

(case nil
  (nil 'a)
  (otherwise 'b))

It returns b. To return a, the first normal-clause would have to be ((nil) 'a).

Conclusion

If you always make sure that keys is a list, you'll:

  1. end up with more consistent looking code;
  2. avoid edge-case bugs (especially if you're writing macros that expand into case); and
  3. make your intentions clearer.
like image 163
Joshua Taylor Avatar answered Sep 29 '22 18:09

Joshua Taylor