Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
OO languages spend most effort addressing a minority use case (250bpm.com)
58 points by film42 on Aug 15, 2015 | hide | past | favorite | 66 comments


The issue is that there are so many ways to do one thing with OOP. Programmers tend to add complexity when they can do OOP, so it's not the fault of OOP, but it's hard to teach good practices. In a way the problem is that OOP is too permissive. When you use a language, a nice feature is readability, but it's because the language encourages some practices.

In that regard, C++ is fine. Java is not.

Also a bothersome issue is people arguing that OOP is reusable, so that they invent all sorts of things that will be extendable, and then you see their code never being used ever again.

My opinion: don't teach OOP, teach software design. PLEASE.


I never create a class hierarchy or implementation layer as a reuse concern, even though this accusation comes up often (from naive FP people). It is totally just a way of isolating and modularizing complexity. If you want reuse, look elsewhere, like in libraries or components. Designing nice abstractions is hard in any paradigm: the last time I was in a room with the Haskell folks (like SPJ), they spent a lot of time talking about building elegant abstractions for solving problem X in Haskell, where coming up with those abstractions didn't seem easy at all.

I don't think one can really teach reusable abstraction design like one can teach algorithms. There is no science behind it, there is no way to "measure" it. You can't create exam questions about it.


> In that regard, C++ is fine. Java is not.

You realize C++ is much more permissive than Java?


java encourages OOP. C++ only allows it.


What a straw man. Saying that OO is all about inheritance is like saying that a Tesla cars are all about having a big touch screen dashboard.


The best definition of object orientation I've come across recently is this one:

http://wcook.blogspot.co.uk/2012/07/proposal-for-simplified-...

Which identifies two defining attributes of objects as a particular kind of value: they are collections of behaviours, and invocations of their behaviours are dynamically dispatched. Inheritance isn't required; it's polymorphism that's important, and inheritance is just one way to approach polymorphism.


In what way would that be different from the use of simple closures. Given that they predated them by a couple of decades am interested in what new or different idea (or even practice) that OOP brings to the table. My question is sincere and genuine.


Well, Guy Steele suggested [0] that

> A closure is an object that supports exactly one method: "apply".

In which understanding, what objects add is the ability to have multiple methods associated with one bit of closed-over state.

Now, you can do that without objects by creating several closures in one context and putting them all in a record to give them names. But at that point, you've just implemented objects. Hence the famous aphorism quoted in Steele's email: objects are a poor man's closures; closures are a poor man's objects.

[0] http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/m...


I prefer the second idiom: Create a tuple of different functions that are closed over a common state. You get privacy and data abstraction for free. This is nothing new or ground breaking, neither in theory nor in practice. This idiom will be familiar to everyone taking a 101. So I am yet to find what is it that OOP brings to the table. Some OOP fans seem to have a large chip on their shoulder, as if they saved the world. Want to understand what's all that about.


When you create a tuple of different functions closed over a common state, that is object oriented programming. If that's something you find useful, then you already understand what object oriented programming brings to the table.


But that's my point, this has been a common practice decades before OOP fanboyism came to town telling everyone they have this new solution for all software problems of the world. And all they were selling as this new paradigm was not only old hat but a special case among the many in which closures can be useful. One uses it when it matches the problem domain. The overblown fuss around it and raising it to the grand position as _the_ solution to everything, and the assertion that you are doing it wrong if your code is not OOP, keeps me permanently mystified.


That never happened though, not in the 80s/90s when OO was considered new (everyone had experience with objects before they were called objects). It is something people imagine a lot, probably so they can feel more smug hating on OOP. But really, any new technology will attract clueless fanboys who think they are working with something brand new (again, to support their smugness in pretending to be a pioneer). And let's not get started with the FP fanboys, who think they are "doing functional programming" when it's obvious from looking at their actual code that they are thinking in terms of objects and don't really get FP at all.


Agreed in full about FP fanboyism, and exactly as you said, some write Java code in their shiny new language.


I was waiting for the one true Scotsman argument to show up in the discussion. I had to wait less than I expected. OOP fans seem to need resort to it more often than others, I wonder why. If you take away inheritance there is nothing that the conventional OOP languages facilitate over and above what languages with closures provide (happy to be educated otherwise). Those have been around some 30 years before. Anyone likes it or not inheritance is firmly a part of the baggage now inspire of Kay being quite clear about its utility or necessity


They resort to it, because programmers who dislike OO have very bizarre views of what OO is, what it's all about, and how it's used.


Little unsolicited wordly advice: If holding on to a belief requires you to rationalize that everybody else is stupid and wrong may be it is time to re-evaluate your belief. If OOP were that good how come nobody made a killing with an implementation that would make these 'true Scotsman' folks happy. What I am pointing out is that other paradigms don't seem to need such pervasive apologism.


> If holding on to a belief requires you to rationalize that everybody else is stupid and wrong may be it is time to re-evaluate your belief.

Hardly. There's plenty of valid criticisms of OO out there. However, that does not mean every criticism of OO is valid. Take this one, for instance: the author is complaining that OO is optimized for class inheritance, when it's not the normal case. However, plenty of OO languages don't have classes, or inheritance, and so it falls on its face as a criticism of OO.

> If OOP were that good how come nobody made a killing with an implementation that would make these 'true Scotsman' folks happy.

Because no OO implementation will make them happy. A little unsolicited worldly advice: programmers think themselves paragons of rationality, but they're susceptible to the same flow of fashion, and the same desire to believe ill of something they don't like, as everyone else.

> other paradigms don't seem to need such pervasive apologism.

They do—take a look at the comments when articles come out critical of functional programming, most of which are as good as the one under discussion here. Or when OO supplanted structural programming the first place.


When I started using python I wondered why classes were not so prevalent. I was just coming out of several years of C# (I had scaled the MVVM WPF mountain. Interfaces everywhere). Since then I realize that I rarely use classes except to store a basic model. And then, unless there's logic around how to convert a value from one thing to another (full name by combining first name and last name as a simple example) I've started moving things like validation and non basic business logic into their own modules. This makes using it across systems easier and allows me to scale the complexities better. Almost no OOP used basically. This has been pretty liberating as far as development and testing goes.

(Of course in 2 years I'll understand the cons of this approach and will think back on these times and wonder how I could have been so naive. :D )


Just because a language supports OO doesn't mean that you are somehow trapped using only the OO paradigm. OO is a feature that gives you, amongst others, the possibility of expressing an inheritance relationship.

Most code I write in C# is OO in that it leverages encapsulation, but is generally written in a functional style (thanks LINQ) and uses inheritance for maybe two out of a hundred classes.

Most popular languages now are multiparadigm, so there's little point in criticising particular paradigms as if we're somehow stuck working with them and them only.


You’re trapped when coworkers use (and demand) OOP, not to mention libraries which require it.

Like when your coworkers become religious about the ORM ("How DARE you write SQL!") when the database people actually have the superior model (relational) to the programmers (OOP).

Also, many languages have an explicit critique of OOP. Take Rich Hickey's discussion of how OOP complects a bunch of features which can be available a la carte.


Link?


Sure. I've recently finished writing 18,000 programming language statements in Visual Basic .NET on 80,000 lines of typing, including comments and blank lines, and so far I have never even once used inheritance, either single or multiple. I don't even know how they would handle naming conflicts with multiple inheritance. Maybe Microsoft's many classes in .NET are making heavy use of inheritance, but I don't.

So, inheritance is okay, but I don't use it directly. It just isn't a tool I use; it stays in the bottom of my toolbox.

I use classes much like structs in C or structures in PL/I. Yes, classes are a little more general, and I do make use of some of that generality.

But, PL/I structures are quite a bit more general than structs in C and, really, nearly as useful as classes. And, for "addressing" as in the OP, the array addressing in PL/I structures is much more efficient than addressing in classes.

The OP is correct: I don't think of classes and inheritance as representing a is-a relationship. Sorry, I just don't do that. Don't need it. Or, I'm big on collection classes (hopefully based on AVL or red-black trees) and did write my own key-value store for session state storage for my Web site, and that usage can be regarded as using is-a, but, again, I don't get is-a from class inheritance -- just don't need that.

And the OP is correct: A lot that is in my code has its meaning clear only in the comments. The code is like the displayed equations in a calculus or physics book, and the text between the displayed equations is like the comments. Both the text in those books and the comments in the code are crucial.

Yes, the meaning of the code is crucial, but for meaning I want to use a natural language, e.g., English, in the comments.


But why not use assembly with a lot of comments then?

Higher level languages aspire to take at least some of the "meaning" stuff that would otherwise be in comments and represent it using in-language constructs.


Good observation.

Likely the answer is, again, similar to what is done in a calculus or physics book: E.g., in a calculus book, there's a lot behind the Riemann integral, and in physics, behind the electric field, so in those books we don't express everything as just simple arithmetic with comments.

And, yes, in my code, when I write a function or subroutine, I give it a mnemonic name and have it do some work that has meaning that is described in the comments.

But here is for me a telling point: In grad school, my best math prof just stated that math is written in complete sentences. So, the mathematical symbols do not replace the natural language, e.g., English in the sentences, paragraphs, sections, chapters, etc. Usually good mathematical notation has some mnemonic hints of the meaning, but, still, the meaning is in the text, not the symbols. So, net, there is limited utility and future in trying to have programming language syntax replace the English language for communicating the meaning.


I've always wondered why (implementation) inheritance is a first class construct while delegation has to be painstakingly implemented manually.


I guess you could do this in a higher-level language like Ruby, though you either have to use a mixin or monkey-patch a core class, which isn't as clean cut as a first-class construct. With Lisp, you could just create the construct if it isn't there already.

No such luck in Java et al.


Yes, I miss it in languages like Java and C# as well.

But this is easy in prototype-based languages.


>>OO folks are wasting their time discussing minutiae of their little peculiar use case, such as, say, single vs. multiple inheritance, while at the same time nobody is paying attention to what is needed in majority of cases.

Maybe they were fifteen years ago, I don't think that is the case now, the two most popular OO languages (Java and C#) don't even support multiple inheritance.


Well, they do, kind of. Just that multiple inheritance is only allowed with the use of interfaces. In C++ multiple inheritance is supported, and interfaces are actually pure virtual abstract base classes. And that's what interfaces in Java (and C#, I think) are, just with the addition of some compiler checks for interfaces. Please correct me if I'm wrong, though.

I seldomly use mutiple inheritance in any language, and instead prefer composition.


True. We use composition to attach things to an object rather than develop a deep taxonomy through inheritance.


well, with default implementation in interfaces, now java support (something resembling) multiple inheritance


I think you and tonyedgecombe have different definitions of support. In my understanding, default implementation was included to allow adding methods to interfaces without updating the classes that implement them. You can use this feature to do something like multiple inheritance, but I haven't heard anyone recommend it.


Well, I hardly know anyone recommend multiple inheritance, whatever the language is :D


Held me up until a C++ rant. Among multiple ways of using C++, an OOP way is the least important. It is not an OO language, so most of the legitimate anti-OOP criticism simply does not apply to C++.


> It is not an OO language

That seems really outlandish and obviously flat-out wrong. I assume, then, that you have good reasons to have this contrarian position, and I am really curious to hear what they are :).

When I think of C++ I think of "C with classes." In other words... C with objects. And... a bunch of other stuff tacked on over the years. Which is not to discount that stuff---maybe that is what your argument rests on; if so, that's fine.


C++ can be OO, but isn't always OO. If OO is defined as having polymorphic runtime function invocation, then C++ allows you to opt-in to this behavior with 'virtual' and heap allocation, vs. Java which requires you to opt-out with 'final' and all objects are always heap allocated.

My biggest thing in support of OO is that it encourages DRY more affectively than other paradigms, IMO. But I am finding Rust's balancing of functional w/ OO allows for you to pick the best method to DRY (don't repeat yourself).

Anyone who doesn't practice DRY programming doesn't understand the cost of maintaining production code and technical debt.


Tell this to A. Stepanov (creator of STL). He maintains that C++ is not an OOP language and OOP has a very little place in it, if any at all.

C++ is not a C with classes. It is a C with namespaces, templates and RAII.


His articles about C vs C++ are also interesting

http://250bpm.com/blog:4

http://250bpm.com/blog:8


He seems to be throwing the baby out with the bath water here a bit. Exceptions are a failure and a bit of a mine field in C++; I have no arguments there but you also don't need to use them.

The list example is a bit contrived too. A simple templated class for the list node could give both encapsulation and the exact same speed and allocation characteristics as the C code.


Yeah, I should have mentioned to read the comments, lots of good points raised there to balance things.


This is one side of the Expression Problem.

http://c2.com/cgi/wiki?ExpressionProblem


Most OO languages are incorporating features from functional languages and generic programming, so the author's rant is kind of misdirected. Maybe he's talking about Smalltalk or Java 1.0?

Besides, in OO languages, people are coming around to the idea of favoring composition over inheritance anyway.

So this person is basically arguing against a strawman.


multiple inheritance is often misguided. Back in the day that was the major selling point of OO. These days decent languages have composition via roles or traits.


So basically the "progress" of OOP wrt. multiple inheritance looked like this: first we throw it away because it's too dangerous, then we realize it's actually needed for good architecture, so we slowly try to smuggle it in under different names ("traits", "roles", "mixins") hoping nobody will notice.


I know you're being sarcastic, but here's some contrived MI that shows common behaviour that can in independent taxanomic branches not polluting the inheritance tree [Edit, added a Bird class]:

    #!/usr/bin/env perl
    
    package Flying;
    use Moo::Role;
    sub flap {
        # do stuff;
    }
    1;
    
    package Bat;
    use Moo;
    with 'Flying';
    
    has wings => (
        is => 'ro',
        default => 2,
    );
    1;
    
    package FruitBat;
    use Moo;
    extends 'Bat';
    1;

    package Bird;
    use Moo;
    with 'Flying';
    # Implementation left to the reader.
    1;
    
    use warnings;
    use strict;
    use mro;
    use Bat;
    use FruitBat;
    use Data::Dumper;
    
    print Dumper mro::get_linear_isa('Bat');
    print Dumper mro::get_linear_isa('FruitBat');
    print Dumper mro::get_linear_isa('Bird'); 
    __END__
    
    $ perl /tmp/demo.pl
    $VAR1 = [
              'Bat',
              'Moo::Object'
            ];
    $VAR1 = [
              'FruitBat',
              'Bat',
              'Moo::Object'
            ];
    $VAR1 = [
              'Bird',
              'Moo::Object'
            ];


It was refined so that the more common use cases were promoted over and above the problematic ones. Its progressing such that its more useful and more capable of doing what we need.


Too much sarcasm. MI was too general, to the point of being more harm than good, so it had to be toned down to find the sweetspot.


I'm being sarcastic not because I don't understand the rationale, but because of the dogmatic approach of the loudest proponents of those changes.


I think the argument mostly still stands. These are still a matter of "taxonomy".


I can't make myself read something which has such an evidently wrong title. Must we ignore reality to push our alternative paradigm nowadays?


You should try to be open to it, OP tries to make a point and not just rant. Typical OO structures don't fit the way some (small majority?) of programmers think. Is becoming proficient at OOP an exercise in brain rewiring? Or should we reject it, since it doesn't come naturally? Worthy of discussion and not just outright dismissal IMO.


The problem is that he really doesn't have a point - only a straw man. He doesn't like inheritance, but he likes message passing. Well, guess what - Alan Kay, the founder of the OO paradigm, also consider message passing to be the most important part.

This is at most a rant against the misguided implementation in certain mainstream languages. Not against OO in general.


True. But in reality, when you hear term "OO" people mean Java and C++, not the orginal Alan Kay's concept. Sad but true.


When you look at books that introduce OO, and languages that incorporate it, it's usually presented as is-a and extends and inheritance.

The fact that Alan Kay meant something different is irrelevant.

While you can build messaging and composition into most languages, they're usually considered application models in their own right, not core features. (Objective C is an exception, among a handful of others.)

So I think it's a valid question - why do mainstream languages still present this model as a core feature when other models are less rigid, more expressive, easier to work with, and better candidates for language fundamentals?


That's irrelevant for all practical purposes till the one true Scotsman shows up. I have noticed that none of the other programming paradigms need as much of a defense via the true scotsman falacy, inspite of those languages being far from their theoretic ideal.


He says that the majority of problems, not the minority of programmers, are unfit for OO.

On the contrary, we see OOP being used in the majority of programming projects.

I have been waiting for a proof that functional programming is easier for a very long time now. It doesn't seem to be the case, and I'm getting sick of fanboyism that insists that it is.


No way. Majority of a so-called OOP code is nowhere close to an adequate representation of the problems it is supposed to solve. Most of the code out there is either not very OOP, breaking the purity for the sake of common sense, or a pile of convoluted overbloated crap.


Speaking of inheritance and adequate representation of reality, it's extremely hard to come up with something real that looks like a class hierarchy. The two things I was able to come up with are the tree of life and some military or bureaucratic hierarchies.


More unsubstantiated claims. But even if you could prove all of them to be true, the superiority of alternatives is a different matter entirely.


Superiority is obvious. An alternative is to represent the real world problem domains as is, without hammering them into any stupid, inadequate "models" like OO, functional, whatever else.


I've been open to it. I went on a journey of SICP, Common Lisp, Haskell and F# over three years.

I went back to my OO roots and c#/c++ and carried on mostly as I did before. Why?

Simply that its easier to rationalise a large system in terms of objects and actions. Even atypical OO languages like Go use this model.

What I did take away was limited mutability (not total immutability) and some functional paradigms such as map/filter and a well founded opinion that one shouldn't listen to programming religious wars and use what works for you.


> Simply that its easier to rationalise a large system in terms of objects and actions.

I'm currently of the opinion that OO is basically a form of module system: useful for carving up large problems into more manageable ones, but not necessarily a good model for writing algorithms.


Good points. I, personally, would say that the most of the wiring is defined by natural languages we use. If programming language cuts against the grain of those, it is bound be hard to learn and use.


OO does not fit most of the real world problems, not just a particular way of thinking.


Eh? Holding a reference is the arrow


The point here (pun intended) is that reference is not an OOP specified feature. Polymorphism is.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: