22
class Boxer:

    def punch(self, punching_bag, strength):
        punching_bag.punch(strength)


class PunchingBag:

    def punch(self, strength):
        print "Punching bag punched with strength", strength

boxer = Boxer()
punching_bag = PunchingBag()

boxer.punch(punching_bag, 2)

No doubts that punch is a good method name in case of a boxer. But is name punch also good for the method of punching bag? In both cases I mean punch as a command (i.e. do punch).

23

A good rule of thumb is that method names should be verbs or predicates such that the object you call them on (self in standard Python convention, this in most other languages) becomes the subject.

By this rule, file.close is kind of wrong, unless you go with the mental model that the file closes itself, or that the file object doesn't represent the file itself, but rather a file handle or some sort of proxy object.

A punching bag never punches itself though, so punchingBag.punch() is wrong either way. be_punched() is technically correct, but ugly. receive_punch() might work, or handle_punch(). Another approach, quite popular in JavaScript, is to treat such method calls as events, and the convention there is to go with the event name, prefixed with 'on', so that would be on_punched() or on_hit(). Alternatively, you could adopt the convention that past participles indicate passive voice, and by that convention, the method name would be just punched().

Another aspect to consider is whether the punching bag actually knows what hit it: does it make a difference whether you punch it, beat it with a stick, or run into it with a truck? If so, what is the difference? Can you boil the difference down to an argument, or do you need different methods for different kinds of received punishment? A single method with a generic parameter is probably the most elegant solution, because it keeps the degree coupling low, and such a method shouldn't be called punched() or handle_punch(), but rather something more generic like receive_hit(). With such a method in place, you can implement all sorts of actors that can hit punching bags, without changing the punching bag itself.

  • 4
    @Artur: yes and no. Files can (conceptually speaking) close themselves when asked; arrays can sort themselves; but punching bags do not punch themselves. – tdammers May 4 '13 at 9:05
  • 2
    Okay, if our punching bag hits the wall at insane speed, is it the wall that punched it, or was it punching bag experiencing hit on itself and by actually itself? – user79302 May 4 '13 at 9:16
  • 1
    @tdammers: Your suggestion to generalize could also lead to an interface called Hitable. – Jens Piegsa May 4 '13 at 9:48
  • 2
    @Artur: I think this is where the OOP assumption that every sentence has a natural subject, and that this idea is applicable to programming, breaks down. – tdammers May 4 '13 at 9:48
  • 1
    So the main question is. If files can close themselves, arrays can sort themselves, etc., why punching bags cannot punch themselves? Is there any real difference or is it just that in the first case, we are used to it and in the second, we are not? – clime May 4 '13 at 11:02
6

I think it is a conceptual issue (how we think about the world). It's alright to say:

  • Look, the door is closing. door.close()
  • Wow, the paper is folding on its own. paper.fold()
  • What the hell?! That file on the desk has just closed, nobody being around. file.close()

It is weird to say:

  • That punching bag in the gym has just punched itself. bag.punch()

It would need to have something to punch itself with in the first place (e.g. arms). You would probably say:

  • The punching bag has started moving on its own like somebody would have punched it. punching_bag.move()

It's alright for programmatic objects to do things that normally others do to/with them (in the "real world"). But I guess it should always make at least some sense that the thing is doing it to/with itself. You should be able to imagine it easily without getting obscure (as in case of the punching_bag).

2

It is matter of taste, I think. Punching bag's punch() method is at least consistent with file.close() or frame.move() in sense of experiencing action on itself. Greater question would be, why Boxer does have punch(something) method at all?

  • I like your point about file.close(). That was something I was getting at. Maybe boxer has punch method because there is also a coach training the boxer. Well, in fact, I was just trying to give some example of an action (message) being passed through several objects with the last one being "object of an action". I have slight problem with list.append(4), account.deposit(50), file.close(), paper.fold() vs. boxer.punch(), dog.bark(), logger.log() etc. – clime May 4 '13 at 0:45
  • When passing through several objects, there are 2 cases: you use bound context (self), and you don't. If you do, your methods should be Coach.sayPunchToBoxer(), Boxer.punchNearestBag() and Bag.punch(). Otherwise you have to guess what will happen every time you call Coach.punch(). General rule is: if object that experiences action is not specified in method name, then receiver is that object. – user79302 May 4 '13 at 9:06
  • Well, i think this is also allright: coach.say_punch(boxer, punching_bag), boxer.punch(punching_bag). i.e. receiver is not in the method name but in parameters. – clime May 4 '13 at 9:29
  • 1
    Sure, I meant that action receiver should be guessable from call statement. – user79302 May 4 '13 at 9:37
2

You have two different messages: one to command an object to punch and one to inform an object that it was punched. Consider that a Boxer object is likely going to need to respond to both. Differently. That's a really good reason to give them different names.

My inclination would be to keep punch(boxer, object, strength) and rename the opposite method to punched. You could call it handle_punch or something like that but then it's still ambiguous whether it's to handle a punch command or the notification that it got punched.

  • A good point about Boxer needing both punch and something like handle_punch (would be defend in this particular case). But punching bag is never going to be bidirectional like that. And there is already this file.close()... – clime May 4 '13 at 9:36
  • defend is a command. It is one possible action that an object could take in response to punched, but you wouldn't want other objects to invoke defend directly. – user2313838 May 4 '13 at 14:52
2

Your approach will eventually lead to very coupled code.

To summarize Eric Lippert ideally here you'd want the boxer to be able to punch a great many things. Having the punching bag as the signature of the boxer function implies that the boxer is created with an immediate knowledge of All (that is punchable). Plus giving a punch and receiving a punch are two VERY different things, thus they should not share the same name.

I would rather model this as a Boxer that creates a punch (another object that contains the punch's attribute force, reach, direction etc).

Then have the punching bag with a method such as onPunch which receives this punch object can the compute the effect of the punch on itself.

Keeping this in mind the name of things matters a lot. It must fit the mental model you have of the situation. If you find yourself trying to explain how something can happen which makes no sense at first sight, or if you hare having the hardest time naming somehting then perhaps your model is wrong and needs to change.

It's hard to change a model after you started, people generally tend to bend the reality to fit the model. The problem with this is that as you bend things to fit (such as a punching bag that can punch things) the world you are creating becomes more and more complex and the interactions get to be more and more difficult to implement. You will eventually reach a point where adding even the most trivial thing becomes a nightmare of changes and bugs. This conceptual technical debt can have a very steep price even if the initial cost was perceived at the time as the cheapest thing to do.

1

This is the problem which I call "object/subject" confusion and it's quite prevalent.

Sentences generally have a subject who does the verb on their target object.

Now with regard to programming the only thing that actually does things is the computer. Or virtually a process, thread or a fiber. The objects are not animate by default. They don't have their own threads running so they can't really do anything.

This means methods operate on them, they are the target of the action not who does the action. That's why we call them "objects" not "subjects"!

When you say File.close it's not the file closes itself, it's current running thread who closes the file. If you say Array.sort, the current running thread sorts the array. If you say HttpServer.sendRequest, the current running thread sends the request to the server (not vice versa!). Similarly saying PunchingBag.punch means the current running thread punches the bag.

This means if you want the Boxer to be able to punch, then it must be a subclass of a Thread so it can do things like punching bags in its thread function.

However sometimes it also makes sense to say punching bag punches itself in the case where each object has their own thread you may want to avoid race conditions and implement method calls as message passing: you punch the bag by sending it the punch message, it's thread punches itself then sends you back the punch successful message, but that's only an implementation detail.

0

I agree that "punch" is a good method name for the Boxer class, as (with some tweaking) it could be reused against other objects. It also accurately describes that an object of a class is doing an action on another object. Though, I would rename the method to "doPunch", to more clearly demonstrate the relation.

For the PunchingBag class however, I find the method name to be either too vague or a little inaccurate of what is happening in the method. When I see "punch", I think that something is punching something else. However, in here, the PunchingBag object is reacting to a punch from an object (in this case, a Boxer object). So, I would rename the method here to "isPunched" to illustrate that the object is reacting to a punch.

Though, this is my interpretation of how I would name the methods. It's all a matter of taste and which standards you are following.

  • 3
    isPunched is really misleading (more or less, depending on framework naming scheme). – user79302 May 4 '13 at 0:17
  • It is usual that method is applied to that object, on which it is called. What's wrong with just punch()? – user79302 May 4 '13 at 0:18
  • Well, I totally understand that need to specify the action direction but I think there is something about OOP and its philosophy that makes this unnecessary. Some kind of abstraction that is connected with that famous explanation that objects "send messages" to each other. – clime May 4 '13 at 1:06
  • If it isn't obvious from the method name what the method is doing then it's a problem with the name. It's not a problem with OO or whatever paradigm is being used. That's why punch() on a punching bag is wrong in whatever context you want to use it. What does it mean when you say punch to a punching bag? It's also why you can't assume by any philosophy that something is unnecessary in situations where the assumption creates ambiguity. There are cases where rules of thumb work and situations where they don't. If rules of thumb always worked then they'd be called rules (without the "of thumb"). – Dunk Oct 24 '16 at 20:47
-2

hmmmm. i'm questioning punching bag as a class, because you dont really care about the punching bag -- you care about the impact and strength of the Boxers fist. so the methods should be about whatever is measuring and reporting the punch impact. even if this is coming from the 'punching bag', the naming should still reveal the responsibility - like punchImpactMeter etc.

-3

The boxer punches the punchingbag -> boxer.punch

The punchingbag gets punched by the boxer -> punchingbag.get_punch

  • 3
    this doesn't seem to offer anything substantial over points made and explained in prior 6 answers – gnat Mar 22 '15 at 9:45

protected by gnat Mar 22 '15 at 9:44

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.