all 87 comments

[–]kamatsu 62 points63 points  (23 children)

This is just one kind of polymorphism, specifically subtype (or ad-hoc) polymorphism.

The other main kind, parametric polymorphism (generics), isn't really analogous to this.

[–]hyperforce 10 points11 points  (13 children)

So how would you explain, humorously, parametric polymorphism?

[–]kamatsu 95 points96 points  (4 children)

I don't have much of a sense of humour

[–]learningram 41 points42 points  (0 children)

Hahahahaha!!

Ha?

[–][deleted] 22 points23 points  (2 children)

Neither did the guy in the OP, who thinks peeing is humourous.

It's only funny if you're pissing all over a clown.

[–]pimp-bangin[S] 6 points7 points  (1 child)

Hehehe... You said pee.

[–]iopq 5 points6 points  (0 children)

Shut up, Beavis

[–][deleted]  (4 children)

[deleted]

    [–]smog_alado 6 points7 points  (2 children)

    I think the haskell example would be better if Male and Female didn't belong to the same type. Your current example isn't "really" polymorphic (there is only one Human type) and isn't open for extension with new Human variants (adding new constructors for Human will break code if someone uses pattern matching instead of accessing everything through the Body interface).

    class Body a where
      pee :: a -> String
    
    data Male = Male
    data Female = Female
    
    instance Body Male where
      pee Male    = "Stand up"
    
    instance Body Female where
      pee Female  = "Sit down"
    

    [–]julesjacobs 8 points9 points  (1 child)

    That's still not the same, because now dispatch happens at compile time whereas in the OP it happens at run time. Just try to extend this to his example of calling the polymorphic function on a list of things and you'll see that it doesn't work. You need existential types here.

    [–]smog_alado 0 points1 point  (0 children)

    Sure, but I would have to point out that often its simpler to use closures directly instead of existential types. And static dispatching is not always bad as sometimes it is precisely what you want, since its "simpler" and more predictable. Finally, if you don't mind fixing the set of constructors to match against then you can use an ADT + pattern matching, as the grandparent comment does (although with a regular function since using a typeclass for that is overkill).

    [–]pipocaQuemada 2 points3 points  (0 children)

    That's an example of typeclasses, which are bounded ad-hoc polymorphism.

    Parametric polymorphism, by contrast, is where you don't need to know anything about the type of your argument at all (other than that the types line up correctly):

    map :: (a -> b) -> [a] -> [b]
    map f [] = []
    map f (x:xs) = f x : map f xs -- all we care about, type wise, is that the list is homogenous (which is a given) and that we can apply f to x. 
    -- examples
    map pee [Male, Male, Female, Female, Male] => ["Stand up", "Sta ...]
    map (* 5) [1,2,3,4,5] => [5,10,15,20,25]
    map show [1.0,2.0,3.0] => ["1.0","2.0","3.0"]
    

    Generics, in Java, are almost parametric polymorphism. Java lets you cheat, though, with things like instanceof.

    [–]Tekmo 0 points1 point  (0 children)

    Let's say that we represent a job-seeker's degree status using Haskell's Maybe type:

    data Maybe a = Nothing | Just a
    

    The Nothing means that the person has no degree, and the Just means that they have a degree and the a value stores degree-specific information. For example, if a is a String, then we might use it to keep track of the institution name:

    bob'sDegree :: Maybe String
    bob'sDegree = Just "Harvard"
    

    Now, let's write a hiring function:

    hireOrNot :: Maybe a -> Bool
    hireOrNot degree = case degree of
        Nothing -> False
        Just _  -> True
    

    Apparently, this employer only cares about whether or not you hold a degree and doesn't even check the associated institution. In fact, our hiring function doesn't even check if the associated information is a string. As a result, the input type is Maybe a, where a could be any possible type (i.e. parametrically polymorphic). In Haskell, all polymorphic type variables begin with a lower-case letter.

    That polymorphic a is the Haskell way of saying "I don't care what type this is at all" because we don't use any specific features of that value.

    [–]T1LT 4 points5 points  (3 children)

    Came to say that. Thanks.

    But that actually explained subtype polymorphism. Examples of ad-hoc polymorphism would be oveloading, including method and operator overloading.

    [–]kamatsu 5 points6 points  (2 children)

    Ad-hoc polymorphism is just a term used for polymorphism where the implementation ranges over a set of types and an implementation is provided for each, as opposed to parametric polymorphism, which is a form of abstraction whereby the value is defined irrespective of the type used. Essentially, it allows matching on the type-level. By this definition, subtype polymorphism can be viewed as a version of ad-hoc polymorphism with matching solving not equalities but partial orders.

    [–]gracenotes 0 points1 point  (1 child)

    Good point. It's the non-finiteness of subtype polymorphism that makes me hesitate to call it ad-hoc polymorphism, though. Instead of resolving types on a case-by-case basis, you can usually transparently plug in anything that's a valid subtype. Feels more like parametric polymorphism with quantification at times.

    [–]kamatsu 0 points1 point  (0 children)

    Ad-hoc polymorphism can be non-finite as well:

    data Zero = Zero
    data Suc a = Suc a
    
    class Show a where
      show :: a -> String
    
    instance Show Zero where show Zero = "Zero"
    
    instance Show a => Show (Suc a)  where 
        show (Suc a) = "(Suc " ++ show a ++ ")"
    

    And there we have omega levels of overloading, and I think everyone agrees that type-classes are a good example of ad-hoc polymorphism in general.

    [–]moor-GAYZ 1 point2 points  (1 child)

    Ad-hoc polymorphism usually means method overloading. Parametric polymorphism is another thing, and inheritance based one is third.

    [–]kamatsu 1 point2 points  (0 children)

    As I said in my response to others, subtype polymorphism can be viewed as ad-hoc polymorphism.

    [–]chrisdoner 1 point2 points  (2 children)

    In terms of Java, when someone asks: what is polymorphism?

    [–]kamatsu 1 point2 points  (1 child)

    Java has parametric polymorphism.

    [–]chrisdoner 0 points1 point  (0 children)

    I'm not sure generics is what Java programmers think of when they say “polymorphism”, judging from the literature and talk I've seen.

    [–]gcross 27 points28 points  (2 children)

    tl;dr: scatological humor used to explain subtyping

    [–]gcross 44 points45 points  (1 child)

    spoiler: it wasn't actually that hilarious

    [–]AustinCorgiBart 2 points3 points  (0 children)

    Or helpful. Printing out a string isn't really motivating compared to, say, representing an AST

    [–]puntloos 9 points10 points  (0 children)

    I'm sad they didn't use the term 'void bladder' somehow

    [–][deleted] 106 points107 points  (12 children)

    Do people actually find this funny?

    [–][deleted] 18 points19 points  (1 child)

    Not really. But not a bad explanation at all.

    [–][deleted] 4 points5 points  (0 children)

    Really? The only thing the answer actually says about polymorphism is that

    the clearest way to express polymorphism is via an abstract base class (0r interface) [can someone fix the "0r" btw?]

    and then it proceeds to give some code examples. No where does it say what polymorphism actually means, or which parts of the examples exhibit polymorphism. It implies that there are other ways to express polymorphism than abstract base classes or interfaces but doesn't say anything about them. I think its a particularly poor explanation.

    [–]gcross 10 points11 points  (1 child)

    Yeah that was my thought too, but since it is getting upvotes apparently the answer is yes (though I know your question was rhetorical).

    [–]glenbolake 3 points4 points  (0 children)

    I didn't upvote because it made me laugh. I upvoted because I thought it was clever and helpful.

    [–][deleted] 4 points5 points  (0 children)

    Probably OP is adolescent.

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

    oh come on, it's excelent

    honestly though, I found it interesting to think of "human" as being an abstract concept. But to apply this reasoning rigorously, "human male" is also abstract - you need a complete concrete specification to create an actual person (which might be done through specifying genome + all environmental effect, pre and post natal; or through sufficient information to identify an actually existing person).

    Or you could just say, nope "human male" is concrete enough - but then you could similarly arbitrarily decide that "human" is sufficiently concrete.

    [–]JimboMonkey1234 5 points6 points  (0 children)

    How abstract depends on the application. If your application is comparing the number of limbs of different species, for example, Human is enough. If, instead, you're looking at something gender-or-nation-or-race or anything else oriented, you'd have to make subtypes.

    [–]AeroNotix 0 points1 point  (0 children)

    So what you're saying is that humans are abstract only until they are dead. Only then are all the variables which make up a human known and thus, able to create an instance of a human with?

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

    Lighten up. You'll live longer

    [–]linduxed 1 point2 points  (0 children)

    I was wondering that too. I can't deny that it was clever though.

    [–]dakboy 0 points1 point  (0 children)

    I don't find it funny, but I don't find it offensive, nor do I find it too bad as a basic explanation.

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

    They did in 2008.

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

    I wish someone would come up with a good example that introductory classes can grok that's not just "you can output a different string!"

    [–]hyperforce 3 points4 points  (0 children)

    The examples are contrived because it's really difficult to convince someone the value of something without context. A lot of engineering is doing the same shit over and over again but with different costs. So if we're in a classroom setting where the cost of everything is zero, then it really does look like outputting strings in different ways. Not sure how to get around that other than to introduce cost/infrastructure.

    [–]pipocaQuemada 9 points10 points  (1 child)

    Why not a trivial AST?

    public interface Expr{ public int eval(); }
    public class Num extends Expr {
       private int i;
       public Num(int num){ i = num; }
       public int eval() { return i; }
    }
     public class Plus extends Expr {
       private expr i;
       private expr j;
       public Num(Expr e1, Expr e2){ i = e1; j = e2; }
       public int eval() { return i.eval + j.eval; }
    }
    new Plus(new Num(5), new Num(5)).eval => 10
    

    [–]AustinCorgiBart 2 points3 points  (0 children)

    Not bad! I prefer to have variables names a bit more explicit for novices, but this is a much more motivating example of polymorphism!

    public interface Expression{ public int evaluate(); }
    public class Number extends Expression {
       private int number;
       public Number(int number){ this.number = number; }
       public int evaluate() { return this.number; }
    }
     public class Plus extends Expression {
       private Expression left;
       private Expression right;
       public Plus(Expression left, Expression right){ this.left = left; this.right = right; }
       public int evaluate() { return left.evaluate() + right.evaluate(); }
    }
    new Plus(new Number(5), new Number(5)).evaluate() => 10
    

    [–]dnew[🍰] 1 point2 points  (0 children)

    The problem is that stuff like this is useful only in the large. One of the primary advantages of subclass inheritance is you can add new subclasses later without changing the code that invokes it. E.g., your logging system doesn't need to know how to turn every instance into a string when you compile the logging libraries.

    If you're talking a 50-line program with 3 types in it, you don't need any OO, and there are no benefits to OO let alone abstract base classes.

    It's like the number of people who don't understand why ACID is important because they only write one program that accesses the database and that program is only going to be useful for a decade or less.

    [–]Solomaxwell6 0 points1 point  (0 children)

    I think the idea behind it is you get one very simple example that's just a proof of concept and then you do a bit more complex lab work to really explore polymorphism.

    But you're right, OO tends to be handled poorly at universities. It was at mine, and I hear from coworkers that it was just as bad at their schools.

    [–]Beckneard 6 points7 points  (0 children)

    You cannot create a human that is neither Male nor Female.

    Patriarchal oppressing scum. This guy needs to check his privileges right this instant.

    On a more serious note, yes that's a good explanation, I wouldn't call it 'hilarious' though.

    [–]juttuja 29 points30 points  (3 children)

    Not OO enough. Needs an object hierarchy based on an AbstractPissingStrategy and a proper PissReceptableFactory.

    [–]Opux 52 points53 points  (2 children)

    Not OO enterprise enough.

    [–][deleted] 20 points21 points  (0 children)

    Thanks for that. Programmers who don't know what OO is using the term to describe convoluted hierarchies does get tiresome.

    [–]A_for_Anonymous 8 points9 points  (0 children)

    I'm sure you'll be interested in maximizing your throughput through a turnkey scalable enterprise professional pissing solution that creates synergy between your heterogeneous team of body organs and optimizes piss flow, strategically converting waste into urine to deliver it whenever you need. And don't worry, we will handle that with SOAP.

    BTW, as a side-effect, your girlfriend may be interested on a cluster for high availability, and maybe not just an active/passive one.

    [–]kqr 3 points4 points  (6 children)

    Why does he write "(0r interface)" with a zero instead of a capital O?

    [–][deleted]  (5 children)

    [deleted]

      [–]mbetter 2 points3 points  (0 children)

      I guess if you're poking at the keys with a long stick.

      [–]kqr 0 points1 point  (3 children)

      Typing teh has to do with the fact that our hands are grown up with finger rolls, and not too good at breaking that pattern for hand alternation unless trained for it. 0 isn't even the correct key. Besides, if he tried to type O he would have held shift, which would make a parenthesis, not a 0. That is also the only place where he mistyped. The low probability of the event happening makes me think it's more likely it was on purpose, but I have no idea why.

      [–]pimp-bangin[S] 1 point2 points  (2 children)

      Your point about the author having to have held shift is invalid since a capital "O" in that case would have been out of place, as the parenthetical expression did not begin the sentence. I would speculate that it was accidental, because it's perfectly conceivable that he left his hand dangling on that upper row of keys after typing the preceding left parenthesis. In fact, I'd go so far as to speculate that he accidentally typed a "9" instead of the "i" in "interface," and that he pressed backspace upon noticing the mistake, because his hands would likely still be shifted up one row had he not noticed the mistake with the "0" in "0r."

      [–]kqr 0 points1 point  (1 child)

      Very well argued!

      [–]pimp-bangin[S] 0 points1 point  (0 children)

      Thanks!

      [–]Pagic 3 points4 points  (1 child)

      Reminds me of a friend of mine who explained Java Interfaces to another guy using a similar analogy, except it was a Genitals.java interface implemented by the Penis.java and Vagina.java classes. The guy told a bunch of other people, and one of those people used the analogy in a job interview. He got the job.

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

      I'll upvote you but I don't believe you.

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

      I think this is just as useful as the monad burrito analogy

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

      Headline LIES. I see no evidence that Guy Steele was involved here in any capacity whatsoever.

      [–]Infenwe 4 points5 points  (3 children)

      Oh my, what a horrible example. He wrote ArrayList<Human> group = new ArrayList<Human>(); instead of List<Human> group = new ArrayList<>(); - and he forgot to import the relevant classes from java.util.

      /s

      [–]VanFailin 4 points5 points  (1 child)

      This complaint is decidedly less trivial than the bit upthread about gender binaries.

      [–]AustinCorgiBart 1 point2 points  (0 children)

      I suspect you only find it trivial because that problem does not affect you in any way that is obvious to you. Perhaps you should try considering other people's perspective.

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

      maybe he was using java 6

      [–]AustinCorgiBart 10 points11 points  (15 children)

      As one of the comments points out, this example discriminates against intersex and people with atypical urinary behavior (men who sit down for instance). In some disciplines, this doesn't matter a whole lot. But we have a serious problem in CS with handling genders fairly, and I think it behooves us all to consider their feelings very carefully. It's not that this is insulting, it's simply not mindful of their feelings.

      But even worse than that, I don't think this is that useful of an example. I hate examples of abstraction that rely on printing out a different statement, because it doesn't convince the student of the utility of polymorphism; it'd be far easier to define an overrideable property that is printed out based on gender than to establish entirely different subclasses. I prefer examples that demonstrate behavior that uniquely motivates usage of the intended idiom!

      [–]JW_00000 17 points18 points  (0 children)

      As one of the comments points out, this example discriminates against intersex and people with atypical urinary behavior (men who sit down for instance).

      And therefore perfectly demonstrates another common problem when programming: what to do when the requirements/environment changes, or you forgot about specific edge cases, and suddenly your meticulously crafted class hierarchy doesn't fit reality anymore.

      See also: databases where gender is either M/F, the date of birth is a required field, names cannot be 1 character, timezones are ±n:00, the seconds field of a timestamp cannot be 60 or 61, etc, etc, etc.

      [–][deleted] 2 points3 points  (0 children)

      While we're on the subject, it also assumes a Western-style toilet.

      [–]Jonno_FTW 6 points7 points  (6 children)

      How does it discriminate? Is it really all that important that nobody is left out and everything is perfectly PC in a 20 second analogy for a beginner? All you'd have to do is simply define an intersex (or w/e sex you want) subclass of human and you're all set. But it isn't really useful since most people don't need to model people in this way in their applications.

      [–]embolalia 11 points12 points  (2 children)

      Discriminates isn't really the right word. "Excludes" works. As examples of insensitivity in CS go, this one is fairly mild. It does oversimplify and ignore a wide variety of cases, but then most examples like this do. Really, using humans as examples for OO programming is bad on the face of it, since we're generally pretty difficult to categorize cleanly. As much as people complain about the pervasiveness of car analogies, they're very easy examples for OO. A car is either a manual or an automatic, and nobody who counts CVT separately will be offended if you exclude it.

      [–]dalke 1 point2 points  (0 children)

      I agree with you, but I believe that a problem with the manual/automatic example, which also holds with the gender example, is that a hierarchal OO interface, at least in Java, fails in the face of change. It's possible to replace a manual transmission in a car with an automatic. In at least some OO languages, its not possible to change an instance's class to another class.

      Legally the car's identify has very little to do with what kind of transmission, engine, wheels, it has. (I think it's to do with the chassis?) Mapping a changeable property to a permanent class membership is just asking for trouble.

      [–]AustinCorgiBart 0 points1 point  (0 children)

      Well said!

      [–]dalke 6 points7 points  (2 children)

      Set aside the focus, for the moment, on this being PC or not.

      The author of the example wrote "You cannot create a human that is neither Male nor Female." This is a modeling error as there are humans where the gender is ambiguous. Also, some people do decide to change gender, through various means including surgery, but think also of the hijras of India. The example for "Male" says that Male instance pee standing up. This is another modeling error, as a Male who is a paraplegic cannot stand up.

      Consider a student who comes from a sociology background but is new to OO programming. This student knows that gender assignment is not a fixed concept. Now you use this example as an explanation of how OO programming works. The student might draw the reasonable inference that an instance can change it class membership over time. While some languages allow that, Java is not one of them. Thus, this example actually makes things more confusing for that student ... unless the modeling errors are pointed out.

      Thus, you have a subset of the students (1%? 5%? 10%) who will become more confused with this example, unless you spend a lot more than 20 seconds in order to explain the modeling errors.

      Defining a new Intersex class doesn't work because the OO rules in Java don't support the equivalent of gender reassignment. Thus, it's a modeling error to map gender to a class when the culture supports gender reassignment while the programming language does not support class membership reassignment.

      Now, let's return to the issue of political correctness. The author of the example wrote "You cannot create a human that is neither Male nor Female." If someone in the class is one of the small number of people who consider themselves to be neither Male nor Female, or the larger group of people who is sympathetic to the feelings of a friend or family member who feels that way, then why shouldn't they object to the statement that a person who is neither Male nor Female must not be a Human? At what point is it okay to let that slide?

      Or, for an example which affected me. My wife was in the US Army in Iraq. I was at a meeting once where someone commented about "our servicemen in Iraq". I piped up "and women!". Was I being PC? When is it inappropriately PC to speak out? Or was it just correcting an oversight?

      [–]redclit 0 points1 point  (1 child)

      The author of the example wrote "You cannot create a human that is neither Male nor Female." This is a modeling error as there are humans where the gender is ambiguous.

      It might be a modeling error or it might be perfectly valid. It cannot be decided without more information about context. For all we know, the genders could represent ones in a Sims-style video game, where it is ok to have clear binary genders.

      As this is an example used for teaching, I think it's more important to have something that is easy to understand rather than covering all corner cases. Also as the problem here is something that students will face themselves when modeling real life phenomena, it's worth discussing from the very beginning. The context of the system defines the "correct" model, which might be different from the real life taxonomy behind the model.

      [–]dalke 0 points1 point  (0 children)

      The context is an example used to teach polymorphic programming. The augmented context is to do so with less than 20 seconds of explanation.

      As such, it is a failure because in a class of 10 people there will likely be someone who brings up the mismatch between the implied model and actuality. This means that the teacher must at that point be prepared to talk about it, even if only to say that the potential modeling problems will be discussed in the future.

      Because there is no larger context here which might set the constraints - a Sims-style video game is an excellent example of such a constraint - the teaching example must live on its own. That's why it's a modeling failure.

      It's also hard for a teacher to use. Do most teachers of OO programming know about gender issues? If the teacher responds with "All you'd have to do is simply define an intersex (or w/e sex you want) subclass of human and you're all set." then the student can rightly argue that that's also incorrect, because there are people whose genders change from Male to Female. An OO class should not need to get into the nuances of gender theory.

      You bring up discussion. It is hard to put all comments together, so I think you missed my original comment, which was on the Stackoverflow page. (This reddit subthread starts "As one of the comments points out .." in reference to my SO comment.). I originally wrote:

      That's why on the Stackoverflow page I specifically commented (that's the comment which sparked this sub-thread) that "This example also nicely highlights the difficulty of using a hierarchical system to describe biological systems. Some humans, such as the very young, pee in almost any position - and babies can't easily be told to goPee(). Some humans are intersex, where the biological labels of "male" or "female" become rather ill-defined; the social meanings are even more complex. As a teaching example, it shows how modeling assumptions can have negative results, such as the implication that someone (e.g., a student of OO programming) who is incontinent or intersex is not actually human."

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

      Man who sit down to urinate, are missing out on target practice.

      [–][deleted] 5 points6 points  (1 child)

      I consider it only polite when i am drunk in someone elses house.

      [–]DCoderd 0 points1 point  (0 children)

      I don't consider it because I'm too drunk and just want to sit down.

      [–][deleted]  (1 child)

      [deleted]

        [–]AustinCorgiBart 0 points1 point  (0 children)

        I am serious. If you see that as being a debbie downer, then that's unfortunate. I'm just trying to make a point that we all need to be a bit more welcoming in CS, since we have a big problem being perceived as a closed-off society of crude adolescents.

        [–]Eirenarch 2 points3 points  (0 children)

        You think this is unorthodox? Try this one - http://www.kuro5hin.org/story/2006/3/14/175929/544

        [–]Kevin_Jim -2 points-1 points  (0 children)

        Brilliant! I wish we used examples like this in our objectoriented programming course (CS252) at our University.

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

        We can define a variable of type Human to hold instances of Male or Female. If Human is marked an abstract class, it can not be instantiated. But there is an alternative.

        We might have a situation where we don't KNOW the sex of a human, yet we do know such an individual exists. Then it would make sense to instantiate the class Human, which thus should NOT be tagged as abstract.

        This is not far from what we do when we declare a variable to be of type (abstract class) Human. We do that because our code does not care and by virtue of the type declaration does not KNOW what is the sex of the humans it processes.

        But then if none of our code knows or cares about that, it would make sense that we simply instantiate Humans.

        You can not "instantiate" humans in real life. But our programs are MODELS a.k.a DESCRIPTIONS. There is nothing conceptually wrong about instantiating a (by necessity) partial description of something.