re: PEP 275: Switching on Multiple Values, Rev 1.2
Hi, I'm new to the list and apologies for going off-topic a bit (this has nothing to do with performance): If Python implements switch statements it would be a shame not to have pattern-matching in switch statements too. This is a feature that has long been used in functional languages like ML. For example, here's pattern matching on a tuple: def foo(a,b): switch (f(a), g(b)): case (c,1): something(c) # if g(b)==1, assigns c = f(a) case (1,d): something(d) # if f(a)==1, assigns d = g(b) case (c,_): something(c) # any tuple: assigns c = f(a), _ is wildcard Some syntactic sugar related to this would be a way to pattern-match on arbitrary objects as is now done with tuples: def foo(pair, number): Pair(x,y) = pair # assert isinstance(pair,Pair), assigns x and y int(i) = number # assert type(x)==IntType, assign i (To implement this, classes would have a __tuple__ method that returns the tuple for matching. By convention it should return the arguments to its __init__ method.) Note how type-checking happens in a very natural way: a = int(a) # convert a int(a) = a # type-check a Combining the two: def sum(pairOrInt): switch pairOrInt: case int(a): return a case Pair(x,y): return sum(x)+sum(y) Here's some documentation on how it's done in Cyclone, a C variant from AT&T that seems to have a strong ML influence: http://www.research.att.com/projects/cyclone/online-manual/main-screen005.ht... ---------------------------------------------------------------------- Brian Slesinsky
Brian Slesinsky wrote:
Hi,
I'm new to the list and apologies for going off-topic a bit (this has nothing to do with performance):
If Python implements switch statements it would be a shame not to have pattern-matching in switch statements too. This is a feature that has long been used in functional languages like ML. For example, here's pattern matching on a tuple:
def foo(a,b): switch (f(a), g(b)): case (c,1): something(c) # if g(b)==1, assigns c = f(a) case (1,d): something(d) # if f(a)==1, assigns d = g(b) case (c,_): something(c) # any tuple: assigns c = f(a), _ is wildcard
Some syntactic sugar related to this would be a way to pattern-match on arbitrary objects as is now done with tuples:
def foo(pair, number): Pair(x,y) = pair # assert isinstance(pair,Pair), assigns x and y int(i) = number # assert type(x)==IntType, assign i
(To implement this, classes would have a __tuple__ method that returns the tuple for matching. By convention it should return the arguments to its __init__ method.)
Note how type-checking happens in a very natural way: a = int(a) # convert a int(a) = a # type-check a
Combining the two:
def sum(pairOrInt): switch pairOrInt: case int(a): return a case Pair(x,y): return sum(x)+sum(y)
Here's some documentation on how it's done in Cyclone, a C variant from AT&T that seems to have a strong ML influence:
http://www.research.att.com/projects/cyclone/online-manual/main-screen005.ht...
Note that the switch implementations proposed in the PEP both use Python dictionaries as basis for the jump location lookup. The aim is speed up switches on constants which currently are linear in number of cases. I'm not sure how your proposal fits in here, but it looks like the current if-elif-else syntax is better suited to it than some trying to use a switch-dictionary with some special objects to implement wild-card matching, e.g. if type(pairOrInt) == type(1): return pairOrInt elif type(pairOrInt) == type(()) and len(pairOrInt) == 2: x,y = pairOrInt return sum(x) + sum(y) -- Marc-Andre Lemburg CEO eGenix.com Software GmbH ______________________________________________________________________ Consulting & Company: http://www.egenix.com/ Python Software: http://www.lemburg.com/python/
I'm not sure how your proposal fits in here, but it looks like the current if-elif-else syntax is better suited to it than some trying to use a switch-dictionary with some special objects to implement wild-card matching, e.g.
The wildcard object isn't very important; the part that matters is being able to take structures apart using case clauses. Also, this is mostly about syntactical convenience - for certain problems, pattern-matched case statements read better and are less error-prone than if-then-elif syntax. But I need to come up with a better example. Anyway, my main point is just to argue in favor of switch syntax rather than looking for special cases of if-then-elif to optimize. Some languages do some very elegant things with switches that Python might want to implement someday. (I do appreciate that the dictionary optimization only works for the simple case though, so comparison to constants is the only part that's needed to start.) - Brian
Anyway, my main point is just to argue in favor of switch syntax rather than looking for special cases of if-then-elif to optimize. Some languages do some very elegant things with switches that Python might want to implement someday.
I would argue that all these beautiful properties of the other languages do not carry over to Python. E.g. in Prolog, you have only a two data types: structure, and list, and neither is opaque: since they are not objects, their state is all they have. In Python, the same can be said just about lists and tuples, perhaps dictionaries. Classes don't participate that easily in pattern matching: If you have x = httplib.HTTP() x.connect("foo.com") would you then expect that x matches httplib.HTTP(), or httplib.HTTP("foo.com")? In languages with pattern matching, you find that they use it to emulate late binding: depending on the structure of a thing, you perform different code. In Python, this is more easily done using methods of the object, which naturally dispatch based on the type of the object. Regards, Martin
In languages with pattern matching, you find that they use it to emulate late binding: depending on the structure of a thing, you perform different code. In Python, this is more easily done using methods of the object, which naturally dispatch based on the type of the object.
Method dispatch is a great technique and I was once in the "all case statements are insufficiently object-oriented" camp. But sometimes you need to work with base types or other people's classes without subclassing them, so I find myself writing long if-then-elif statements (most recently for a memory profiler), and case statements would make this code clearer. (Though not nice enough to switch languages, in particular to Prolog.) re: "Classes don't participate that easily in pattern matching" True for many classes and I'll admit my proposal was quarter-baked. Even matching on base types like tuple, list, and dictionary would be plenty interesting. (Especially since they're subclassable.) - Brian
Brian Slesinsky
But sometimes you need to work with base types or other people's classes without subclassing them
I think there are situations where it's legitimate to prefer a case-statement approach even when dealing with your own classes. I once wrote a compiler in HUGS (a Haskell dialect), and I found it very convenient to be able to write a self-contained function which took a parse tree node and did something for each possible subtype of that node. It kept all the processing related to each phase of the compiler together in one place. Using a pure OO aproach, I would have had to scatter it all among hundreds of one or two-line methods of many classes, and probably would have gone insane before finishing the project. Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg@cosc.canterbury.ac.nz +--------------------------------------+
Greg Ewing wrote:
Brian Slesinsky
: But sometimes you need to work with base types or other people's classes without subclassing them
I think there are situations where it's legitimate to prefer a case-statement approach even when dealing with your own classes.
I once wrote a compiler in HUGS (a Haskell dialect), and I found it very convenient to be able to write a self-contained function which took a parse tree node and did something for each possible subtype of that node. It kept all the processing related to each phase of the compiler together in one place.
Using a pure OO aproach, I would have had to scatter it all among hundreds of one or two-line methods of many classes, and probably would have gone insane before finishing the project.
Right. IMO, the method callback approach is nice if you need an extendable architecture, e.g. to write generic parsers frameworks. It doesn't pay off in situations where you have a set of fixed requirements. In these cases, the performance gain is more important than being able to extend by subclassing. -- Marc-Andre Lemburg CEO eGenix.com Software GmbH ______________________________________________________________________ Consulting & Company: http://www.egenix.com/ Python Software: http://www.lemburg.com/python/
participants (4)
-
Brian Slesinsky
-
Greg Ewing
-
M.-A. Lemburg
-
Martin v. Loewis