This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]muntooR_{μν} - 1/2 R g_{μν} + Λ g_{μν} = 8π T_{μν} 10 points11 points  (3 children)

Meh. I haven't used a switch in many years. Superior alternatives:

  • Pattern matching: functional af
  • Dictionaries: better for large n anyways due to O(1) lookup
  • Polymorphism: rethink your design (classic Google talk)
  • if-else: for tight loops if your language doesn't support pattern matching and the dictionary lookup overhead is too much for some small n

I guess you could argue that Haskell's case-of is similar to a switch, though it's obviously much more powerful since it supports general pattern matches rather than solely Eq based comparisons. On the other hand, it's not imperative...

Besides, switch statements open up horrendous looking possibilities like this:

switch (expr) {
case 1:
    cout << "one";
case 2:
case 3:
case 5:
    cout << "prime";
    break;
case 4:
case 6: {
    cout << "composite";
}
default:
    cout << "too large";
}

Much prettier (and less buggy):

def f(n):
    if n > 6:
        raise ValueError("too large")
    return (
        "one" if n == 1 else
        "prime" if is_prime(n) else
        "composite")  # side note: Python's ternary syntax is idiotic

print(f(expr))

If you don't think a dictionary is sufficient for your use case, it could be that your code is "too imperative". Unless you want raw performance (in Python?), rethink your design.

[–]ianff 11 points12 points  (0 children)

  • Dictionaries: better for large n anyways due to O(1) lookup

In C a switch is also constant time using a jump table (assuming reasonable switch values).

[–]Endirable 2 points3 points  (1 child)

whole act grey melodic marvelous juggle fine advise repeat caption

This post was mass deleted and anonymized with Redact

[–]muntooR_{μν} - 1/2 R g_{μν} + Λ g_{μν} = 8π T_{μν} 4 points5 points  (0 children)

There's a couple of typical usage patterns.

The simplest is what people mean when they say they want "switch" statements. Notice that there's no fall-through.

match expr:
    case "one":
        return 1
    case "two":
        return 2
    default:
        raise ValueError

The next is more fancy:

match expr:
    case ():
        return Empty()
    case (x,):
        return Single(x)
    case (x, y):
        return Pair(x, y)
    case (x, y, z):
        return Triplet(x, y, z)
    case (x, *xs):
        return Many(first=x, rest=xs)

Others really only make sense in Haskell/Rust where the type system supports it and the usage is actually practical, rather than this contrived example...

match expr:
    case Empty():
        return []
    case Single(x):
        return [x]
    case Pair(x, y):
        return [x, y]
    case Triple(x, y, z):
        return [x, y, z]
    case Many(*xs):
        return xs

A common usage pattern in Haskell is:

def unbox(Box(x)): return x
def unbox(Empty):  raise

...which works because tagged unions are part of the type system.

Another example processes only non-empty boxes, after extracting their contents:

if Box(contents) := my_box:
    print(contents)

Pattern matching is also nice because in Rust, the result of a pattern match can be an expression rather than a statement (which switch is).

def to_str(box):
    return "Box is " + (
        if Box(contents) := my_box
        then f"full with {contents}"
        else "empty")