-->

Why are Clojure's multimethods better than 

2019-04-18 16:42发布

问题:

I've spent some time, trying to understand Clojure multimethods. The main "pro" multimethod argument, as far as I understand, is their flexibility, however, I'm confused with the argumentation of why multimethods are better than a simple if or case statement. Could someone, please, explain, where is the line between polymorphism and an overglorified case statement drawn?

EDIT: I should have been clearer in the question, that I'm more interested in comparison with the 'if' statement. Thanks a lot for the answers!

回答1:

The difference between multimethods and a big if-statement is that you need to modify the function that contains the case-statement to add cases to the if-statement. You can add a new method without touching the previously existing methods.

So if you define a multimethod inside your library and you want your users to be able to extend it for their own data types, that's no problem. If you had used an if-statement instead, it would be a big problem.



回答2:

Say we have types A, B, C, D and E, and methods m1, m2, m3 taking single argument of the previous types. You can put them in a table like this:

   | A | B | C | D | E |
m1 |   |   |   |   |   |
m2 |   |   |   |   |   |
m3 |   |   |   |   |   |

The "switch" statement strategy is implementing one row of this table at a time. Suppose you add a new type F. You'll have to modify all implementations to support it.

The class-based polymorphism (C++, Java, etc.) allows you to implement a whole column instead. Adding a new type is thus easy, as you don't have to change the already defined classes. But adding a new method is hard, as you'll have to add it to all other types.

Multimethods allow you to implement single cells of the table independently of each other.

This flexibility is even greater if you have to dispatch on multiple arguments. Each new argument adds another dimension to this table, and both swich-based and class-based dispatches become very complex pretty quickly (c.f. Visitor pattern).

Note, that multimethods are actually even more generic than depicted, as you can dispatch on pretty much anything, not just on the types of the arguments.



回答3:

ivant's answer above can be expanded by taking a look at this article . It does a good job of explaining the power of protocols. Think of multimethods as protocols with many dimensions.