Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Pattern matching isn't just about having a switch statement, but about what you can do in the 'case' part of the statement: match complex data and extract variables.

A good example of how pattern matching simplifies code is given in the 'Patterns and Functional Style' section of PEP 635 [1]:

    match json_pet:
        case {"type": "cat", "name": name, "pattern": pattern}:
            return Cat(name, pattern)
        case {"type": "dog", "name": name, "breed": breed}:
            return Dog(name, breed)
        case _:
            raise ValueError("Not a suitable pet")
The equivalent if statement would be kind of gross:

    if 'type' in json_pet:
        if json_pet['type'] == 'cat' and 'pattern' in json_cat:
            return Cat(json_pet['name'], json_pet['pattern'])
        elif json_pet['type'] == 'dog' and 'breed' in json_pet:
            return Dog(json_pet['name'], json_pet['breed'])
    raise ValueError("Not a suitable pet")
One can imagine extending that to parse 6 or 7 types of messages.

Another example is matching tuples or sequences: the equivalent if statement requires checking the length of the sequence, then extracting the variables, etc. The 'case' statement does all of that in one line.

In other words, as one of my university professors would put it: 'there's nothing that can't be written using plain ifs, adds and jumps, but that doesn't mean we all want to write in assembly with just 3 instructions'.

[1] https://www.python.org/dev/peps/pep-0635/#patterns-and-funct...



Thanks for the clarification though your example is unpythonic. Here's refactored to be more pythonic and I'd argue it's more readable than pattern match alternative:

    pet = json_pet.get('type')
    if pet == 'cat':
        return Cat(json_pet['name'], json_pet['pattern'])
    if pet == 'dog':
        return Dog(json_pet['name'], json_pet['breed'])
Again it goes against the pep20 which is really the philosophical foundation of the language: "There should be one-- and preferably only one --obvious way to do it."


The difference is the error handling. Suppose the json includes a dog with no breed specified.


As danohuiginn clarified, the reason I'm adding the checks is because assuming there's such a key as 'breed' in the json_pet dictionary can (and will!) lead to KeyError exceptions.


Seems like an issue of data flow then. You usually don't work with dynamic random content and sanitize/clean up your data before working with it.


Even if you were using pre-processed data, pattern matching helps to make the code easier to read. I guess I can think of clearer examples in other languages, like Rust, that supported tagged unions:

    // Given this enum
    enum NumOrStr {
        Num(i32),
        Str(string)
    }

    // That allows you to define values like this
    let x = NumOrStr::Num(10);
    let y = NumOrStr::Str("hello");

    // And some random code that produces a value z that is of type NumOrStr
    let z: NumOrStr = ...

    match z {
        Num(50) => println!("Got my favorite number: fifty!"),
        Num(n) => println!('Got {}', n),
        String("hello") => say_hello(),
        String(s) => do_something_with_string(s)
        _ => println!("Default case, x = {:?}", x),
    }




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: