Hacker News new | ask | show | jobs
by xscott 2433 days ago
One of the things I dislike about the OO noun.verb() syntax is that frequently you have multiple nouns. For example in some graphics systems, you've got a canvas to draw on, a pen which knows styles for line thickness or dashes, a brush for how to fill, and a shape to be drawn. Who owns the verb? They kind of all do:

    canvas.draw(pen, brush, circle)
    circle.draw(canvas, pen, brush)
    ... and so on
The other issue I have is in closed object systems where you can't add new methods to classes in the library. Say I want to add a new type of shape, maybe an emoji face composed of several circles. Depending which class owns the methods, my new smiley method stands out from the other shapes which are provided by the library, and I think the lack of symmetry is ugly:

    canvas.draw(pen, circle)
    draw(canvas, pen, smiley)
For simple cases, inheritance solves this, but then you get into worse trouble when Alice builds a derived class to support smileys, and Bob builds a separate derived class to add stick figures. Which version of the canvas do I instantiate to support both? Maybe this implies the method should be on the shapes, but I can contrive other examples which break that too. (Another approach is monkey patching, which has it's own flaws, and so on.)

There aren't many languages which support multimethods, but overloading functions is sufficient for statically typed cases, and it's appealing (for me) to have the same syntax for "builtin" methods and ones you add yourself:

    draw(canvas, pen, brush, circle)
    draw(canvas, pen, brush, smiley)
Other people have mentioned languages with "uniform function call" syntax (where f(a) and a.f() are synonyms). I guess that's ok if you're in the "there's more than one way to do it" camp. I don't think that completely addresses the problem though. I could make more examples, but this post is getting long already.

For what it's worth, I really dislike it when languages implement operator overloading for binary operators as methods on the first object without a way to dispatch to the second object. This makes it very difficult to have your new types play well with the builtin or library provided types. Binary operators really are functions with two arguments.

2 comments

This whole comment section tells me that almost no one on HN really understands OOP.

OOP is not about nouns. It's about establishing protocols between subsystems. What you're describing are the typical fake "dilemmas" of someone coming from a static, class-oriented programming languages like Java.

Look up Class Responsibility Collaborator exercise.

I looked it up and while worthwhile, I would need someone to explain how it applies to this specific comment section.
> It's about establishing protocols between subsystems.

Is that what it's about? I try to establish protocols between subsystems without OOP quite often. Are you referring to message passing specifically?

> Is that what it's about?

I'm pretty sure most people who strongly like OOP are sure their particular definition is the correct one. I haven't seen many people agree about what that definition is though. I generally dislike OOP, but perhaps that's because my definition is "encourages implementation inheritance". As you're keen to note, the standard list of other things (encapsulation, message passing, dynamic dispatch, interface inheritance, and even "establishing protocols") are available in a lot of other languages which people don't generally consider OO.

Perhaps I'm ignorant, but I like my way of doing things, and a.f() is less attractive to me than f(a) for all the reasons I listed.

> This whole comment section tells me that almost no one on HN really understands OOP.

Or maybe it tells you that the benefits of OOP are different from what they're theoretically supposed to be. What I read from the thread is that there seems to be significant psychological appeal to some in the noun-verb way, and OOP (perhaps unintentionally) satisifies that need. (And that helps me understand the frequent "Julia needs a thing.do() syntax" complaint on the Julia forums, and why telling them "semantically do(thing) does the same thing" doesn't seem to work.)

One approach here might be to take a cue from Forth and other concatenative languages and use postfix notation:

    canvas pen brush circle draw