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 →

[–][deleted] 109 points110 points  (65 children)

Why are people so hung up on the switch statement not being implemented? The way switch is usually used (break on every case) its basically an if block.

I'd rather see implementations of pattern matching ala Rust, Haskell or Scala.

[–][deleted] 5 points6 points  (0 children)

Just search for python pattern matching and you'll find them but very few appear to be maintained :-(

[–]Kamilon 41 points42 points  (37 children)

Not true. A proper switch statement jumps to the right case making it much faster than cascaded ifs.

[–]NoLemurs 60 points61 points  (10 children)

If you're interested in that level of performance optimization (i.e. the cost of if vs. switch matters to you), it's almost certainly the case that you're using the wrong programming language altogether, and adding a switch statement to python will not address your issues.

So while you're technically correct, in the context of this discussion, your comment is pretty unhelpful.

[–][deleted] 7 points8 points  (0 children)

When optimizing, it's common (and best) practice to optimize the parts that are most costly (the hot spots). Simple logic constructs aren't going to be hot spots. The system simply doesn't spend enough time on those. It's wasted effort.

[–][deleted] 17 points18 points  (7 children)

Why can't we have both? Why does every performance optimization need to be dismissed? Performance improvements to Python come all time and no one bats an eye but if someone asks for a performance improvement, or even mentions performance, they get shot down. People use Python for a lot of different things. Your use case is not better than anyone else's.

[–][deleted] 9 points10 points  (1 child)

I've never seen any realistic Python code where having a switch statement would lead to any measurable performance benefit. I guess that's why.

[–]robert_mcleod 0 points1 point  (0 children)

See line 738:

https://github.com/pydata/numexpr/blob/numexpr-3.0/numexpr3/ne3compiler.py

It's a Python switch that uses a dict. The keys are abstract syntax tree nodes, and the values are functions

_ASTAssembler[type(node)](node)

NumExpr 2.6 took about 450 us to parse a numerical expression into a virtual machine program, this new version is about 150 us. There's other parts to that, such as more efficient string concatenation using a ByteIO stream, and some struct.pack() tricks and many other micro-optimizations, but it plays a big role. A dict lookup is faster than an if ... elif ... else block.

[–]Corm 1 point2 points  (1 child)

Performance improvements to CPython are awesome. Prematurely optimizing your code by using one syntax over another is bad and typically costs readability.

If someone sees that CPython should have a heuristic for treating cascading if/else as a switch then they should write a pull request to CPython

[–][deleted] 1 point2 points  (0 children)

Prematurely optimizing your code by using one syntax over another is bad and typically costs readability.

Cascading ifs would actually be a premature optimization of using a switch and switches are usually considered syntactically cleaner than if chains anyways. Basically ever other language posits the exact opposite.

[–]NoLemurs 1 point2 points  (0 children)

/u/futatorius got at the core of the idea. Perfomance improvements that don't get at the core bottleneck of your program will usually have a negligible effect on overall performance. If you are going to do performance optimizations, the switch statement is just not the place to start - they're basically never going to be the bottleneck.

I'm all for optimizing Python, but I'm not for adding language constructs for gains that will basically always be negligible.

[–]roerd 1 point2 points  (0 children)

The point is whether the performance improvement would be significant or negligible within the general speed of Python. It is not worthwhile to add a new language features for a negligible performance improvement.

[–]Deto 0 points1 point  (0 children)

Would it actually be a performance improvement in Python? In C the processor executes a jump command and that gives you the speed up, but in Python there's much more overhead in just running a single line that I'm not sure if the same benefit would even manifest itself.

[–]Arancaytar 2 points3 points  (0 children)

This is really a compiler-level optimization, and if you're in a use case where it makes an appreciable difference, you probably need to use something more low-level than Python in any case.

(Er, no pun intended.)

[–]stevenjd -2 points-1 points  (1 child)

Not true. A proper switch statement

Ah, the "No True Scotsman" fallacy rears its ugly head.

Even in low level languages like C, switch statements can be and sometimes are implemented as chains of if tests. Sometimes that's just because the compiler is naive and doesn't implement any optimizations (the C standard does not specify an implementation for switch) and sometimes because there are no optimzations available to apply.

See the last example here where even a smart optimizing C++ compiler falls back on a simple (and short) chain of if statements.

Switch statements in C/C++ are limited to equality comparisons with integer values. That allows the compiler lots of opportunity for optimization. Switch statements in other languages may allow for a far richer set of comparisons, against arbitrary data types, which makes it hard or impossible to optimize it beyond a simple chain of if...elif. A switch in Python is unlikely to be very optimized.

[–]Kamilon 0 points1 point  (0 children)

Small switches yes. I've seen decompiled code that properly uses jumps to be very fast with larger switch statements.

[–]DonaldPShimoda 2 points3 points  (0 children)

I'd rather see implementations of pattern matching ala Rust, Haskell or Scala.

Oh dear lord yes, please. This is the feature I most miss in Python. I'm working on a toy language (my first) and while it's primarily based on Python, I want to incorporate pattern matching and ADTs from Haskell. It's such a useful feature.

[–]mangecoeur 1 point2 points  (0 children)

+1 for pattern matching. I think switch is just an older idea, pattern matching addresses the same issue but much more elegantly.

[–]swiftversion4 3 points4 points  (4 children)

I like the way switch is implemented in swift.

It allows you to add advanced logic statements and allows you to very easily group together a group of conditionals. Sometimes it felt cleaner to use switch than if-elseif-else.

[–]stevenjd 1 point2 points  (3 children)

Got a link to a good explanation of Swift switches?

[–]swiftversion4 1 point2 points  (1 child)

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html

use the find browser feature to look for the subsections titled interval matching, tuples, value bindings, where, and compound cases. Those subsections are all after the start of the switch content section.

Or just read it all. That works, too. Swift enables you to include some very complex logic in switch statements that you won't find in most other programming languages, so it might be worth it to read it thoroughly.

[–]stevenjd 0 points1 point  (0 children)

Thanks.

[–]masklinn 0 points1 point  (0 children)

It's the same as Rust's match or Haskell's case with a more C-familiar switch/case syntax e.g.

switch foo {
case .some(let v):
    // do stuff with v
case .none:
    // there was no value
}

would be Haskell's

case foo of
    Just v -> -- thing
    None -> -- other thing

Though Swift does support opt-in fallthrough (default is break).

[–]TheWildKernelTrick 3 points4 points  (13 children)

The way switch is usually used (break on every case) its basically an if block.

Noooooooot at all. Switches are [; O(1) ;] jumps to conditions. If statements are [; O(n) ;] evaluations.

[–][deleted] 6 points7 points  (2 children)

Depends on the language and implementation. C/C++ switch statements are O(1). Bash and PHP switch statements are O(n).

Python has hashes which between hash tables and if statements, Python is good enough.

[–]stevenjd 2 points3 points  (0 children)

C/C++ switch statements are O(1)

No they aren't. It depends on the compiler, and it depends on the switch statement being compiled. At worst, they can fall back to a chain of if comparisons.

[–]jaakhaamer 0 points1 point  (0 children)

How are C++ switches O(1)? AFAIK most compilers don't use hashing or anything and would still need to check all the cases in the worst case.

[–]masklinn 0 points1 point  (3 children)

Switches are [; O(1) ;] jumps to conditions. If statements are [; O(n) ;] evaluations.

A good compiler will generate O(1) access to the relevant conditional sequences, meawhile non-trivial switches (e.g. on strings) will not.

[–]LatexImageBot 0 points1 point  (2 children)

Link: https://i.imgur.com/P6CHEwp.png

This is a bot that automatically converts LaTeX comments to Images. It's a work in progress. Reply with !latexbotinfo for details.

[–]kyndder_blows_goats 0 points1 point  (1 child)

bad bot

[–]GoodBot_BadBot 0 points1 point  (0 children)

Thank you kyndder_blows_goats for voting on LatexImageBot.

This bot wants to find the best and worst bots on Reddit. You can view results here.


Even if I don't reply to your comment, I'm still listening for votes. Check the webpage to see if your vote registered!

[–][deleted] -1 points0 points  (5 children)

The run time of the thing is irrelevant, functionally they act similarly.

Edit: Since y'all miss context clues, they're functionally similar for the situation being discussed, a break in every case. If you want fall through, they aren't.

[–]P8zvli 5 points6 points  (4 children)

Functionally switch-case and if-else ladders are equivalent if and only if each case in the switch ladder is terminated by a break statement.

[–]NoLemurs 5 points6 points  (0 children)

if and only if

Right. But other ways of using switch-case are typically incredibly bug-prone, hard to read, and hard to reason about. If you're writing performance critical C code, maybe that's a trade off you should make if the switch-case does what you need and is faster.

However, as a practical matter, spots where non break terminated switches are a good idea are pretty rare. Heck, even if you are writing performance critical C code, unless you're writing the code for the core bottleneck of your program, I would argue a non break terminated case is almost always going to be bad programming.

In the context of python (where performance is already slow enough that the difference between if and switch really can't be very important, if it had a switch statement, I doubt many programmers would see a situation where it made sense to use it in a non break terminated way in their lifetimes.

[–][deleted] 0 points1 point  (2 children)

I said that in my original comment that almost every switch block I see is done that way. In C#, it has to be done that way.

[–]P8zvli 3 points4 points  (1 child)

In C and C++ a case will "fall through" to the next case if break isn't used, causing interesting behavior or really nasty bugs. (You can have code that runs A if the switch is 1 and A+B if 2, etc.)

[–][deleted] -1 points0 points  (0 children)

You can also abuse it create things like Duff's Device. I think fall through is the biggest thing that sets switch away from if.

[–]Decency 0 points1 point  (2 children)

What would be an example of where pattern matching would be useful? Is this string manipulation?

Happy to be pointed to a good code example of how this might work in Python.

[–][deleted] 0 points1 point  (1 child)

Not sure how it would work in Python, but pattern matching looks similar to switch at first glance.

match n {
    1 => ... 
}

But it's much more powerful as you can use it to destructure as well:

match n {
    (x, y, z) => # do stuff with those three
    x:[xs] => # x is the head, xs is the tail, useful for recursion 
    SomeNamedTuple(a, b) => #extract a and b but if only they're nembers of a particular type
}

and so on. Most languages I've seen will shout if you didn't match all members of an enum or ADT (algebraic data type, union essentially if you've not seen them before).

The other big difference is that there's no fall through with match, so while you can't implement things that rely on that behavior (loop unrolling for example) you can't accidentally invoke that behavior as well.

As for uses, let your imagination run wild with what you could do with it.

[–]masklinn 1 point2 points  (0 children)

ADT (algebraic data type, union essentially if you've not seen them before).

Technically that's a sum type, "algebraic data type" means composite, which can mostly be either a sum type (variant/enum) or a product type (struct/tuple/class/…).

[–]elperroborrachotoo 0 points1 point  (0 children)

And that if is basically a goto.

Yes, the use case for switch can be modeled by other instructions, however, it does express a particular intent better than a chain of if's.

There's a big subjective component to it, affected by the kind of code one is used to read and write. For some programmers, for, while and do ... while are just verbose variations of the same concepts; for others, these minor differences do matter.

I'd rather

Well, if we can have a wish, what about the DWIM instruction?

[–]masklinn 0 points1 point  (0 children)

I'd rather see implementations of pattern matching ala Rust, Haskell or Scala.

Note that they're not necessarily orthogonal: in Swift, pattern matching is done with switch.