Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

I strongly disagree that "code reuse" is a reason to use inheritance in C++/Java. Composition nicely solves that problem. In fact, I would argue that someone who believes code reuse is an appropriate reason to use inheritance does not understand OO programming as well as they believe.


view as:

This. In fact, a friend of mine swears by writing C++ in a style called "snippets" --- meaning, whenever it makes sense to do so, he writes new functionality as a single header and cpp file that has no dependencies whatsoever on other headers, etc, then open-sources it so that anyone can add the same functionality to their own C++ projects by just dropping in the code. A math lib, for example.

Aren't those also just called "functions"? In this case one function per file?

No. As soon as your function has a dependency on anything else whatsoever, it can no longer be copy-and-pasted into another project

A snippet consists of functions which accomplish a specific task. The important part is that the entire snippet is a single cpp and a single header. No dependencies.


That's a function with no dependencies. Still a function.

.... Something is obviously being lost in translation here.

There are certain programming problems which can be solved once and used forever. The problem wouldn't necessarily be considered a single function. However, it isn't a massive problem either.

My friend solves these problems by creating a single .cpp and a single .h file. The .cpp is the implementation; the .h file defines the interface. He calls this a "snippet".

Now, the power of the snippet is that you can simply copy the .cpp and .h into any C++ project anywhere and it's good to go. There is no tweaking, include'ing, anything. It just works.

This code can then serve you for the rest of your life, regardless of what project you are currently working on. You can say "I've solved that problem before", and be able to spend literally 30 seconds implementing it into your current project, because all you have to do is drag'n'drop two files.


I get the distinction, and its a fair one. Although, I don't get how snippets could be useful. Especially in C++. It seems like for almost anything interesting I'm going to want a dependency on the standard library or Boost or the CRT.

I could imagine some snippets that don't take any dependencies, but they are pretty few and far between. Do you have pointers to some of the more interesting snippets he's posted?


Yeah, check 'em out: http://www.amillionpixels.us/sourcecode.htm

There are surprisingly many useful snippets. For example, a single header and source file for an entire, complete A* pathfinding implementation! That's a massive timesaver.


In a lot of the ones titled snippets, I do see dependencies. Some to Windows DLLs and some to the CRT. But they're relatively self-contained.

Cool stuff. Thanks for the link. Although I'd still call them functions. :-)


And they're all functions (or function groups), apart from the one or two that are command-line utilities.

At the end of the day, they're libraries. Small libraries? Sure, but still libraries.


Composition solves that problem, but I don't know about "nicely". You end up having to litter each class with a bunch of boilerplate methods which simply call the same method on an instance field. This avoids inheritance problems but you can end up with a lot of extra code.

What I would like to see — at least in Java — is a keyword or annotation for instance fields to mark them as pseudo-superclasses. Then the compiler would generate all of those call-through methods automatically, unless overridden in the current class.


It's called the strategy pattern. Look it up.

If you find yourself writing a lot of boilerplate code, you're doing something wrong, whether you're using inheritance or not.


Yes, I've read that book too. For many of the cases I deal with the strategy pattern is not appropriate, or creates additional complications. Try again.

Should we raise this discussion to the level of concrete examples? Pastebin perhaps?

Here's a pretty good comparison of the two techniques: http://www.artima.com/designtechniques/compoinhP.html

Having worked with a lot of C++ code recently that employs both methods, I personally prefer inheritance for the majority of cases. One of my primary goals while writing code is to write as little code as possible. If I have to write wrapper methods to expose the interface of the back-end class I've composed, then I'm not achieving that goal.


So I should never use the AbstractList, AbstractSet, AbstractMap, or AbstractCollection Java classes for implementing their relative data structures? Instead of reusing the code these classes provide through inheritance, I should instead be using composition?

Code reuse is the only good reason to use concrete inheritance and there are many situations where concrete inheritance is much cleaner than composition. Honestly, this whole conversation feels a little silly to me.


Implementing an abstract class when the concrete implementation conforms to the Liskov Substitution Principle is exactly when inheritance does make sense. You would do this so that calling code wouldn't need to care that the function required a MySpecialMapClass rather then something that conforms to the AbstractMap interface.

However, if you just think that some of the functions in AbstractMap are useful but plan on creating a totally different class that doesn't conform to the interface, then inheritance is inappropriate.

Code reuse is not a reason to use inheritance; it is a byproduct of it.


I think you need to distinguish between interface inheritance and implementation inheritance.

The reason to use interface inheritance is to allow polymorphism in a statically typed language.

The only reason to use implementation inheritance is code reuse. And yes, you should only do that if the classes conform to the LSP.


(From the OP): jknupp, I agree about that. I think that code reuse is one of the two reasons why people use inheritance in Java, but I don't think it's a very valid reason in general. Upcasting, on the other hand, definitely is. My point in the original post is that because Ruby doesn't have upcasting, then inheritance in Ruby becomes pretty marginal.

Legal | privacy