5 ms·
Inheritance is the first thing I learned when I started learning object oriented programming.
by marblar 11y ago
Inheritance is the first thing I learned when I started learning object oriented programming.
- pjmlp 11y agoAnd correctly so, but the teachers should have also teached that there isn't a single way of doing OOP and what are the cons of certain design approaches.
- manyxcxi 11y agoAs well it should've been! If you're doing OO, you're kind of missing the reason for it if you aren't aware of inheritance, isolation of concerns, and polymorphism. Granted, you could have a lot of copy/paste code and NOT use inheritance, but then why use OO in the first place? EDIT: I mentioned in another comment, and a commenter to this correctly noted- it's probably because it's easier to understand, and a fundamental piece of OO. It's actual usefulness in the real world varies, but it is also how one would step into understanding interfaces, composition, and other aspects of OO that get used heavily in OO in the real world.
- sotojuan 11y agoI think what he means is that in school we are taught inheritance and nothing else, so many programmers only know it's "pros" and not why other techniques like composition can be beneficial.
- lbarrow 11y agoInheritance isn't necessarily part of OO. Go has radically weaker inheritance mechanisms than classic OO languages, for example.
- parenthephobia 11y agoI'm not sure that's true. I think that Go has much stronger inheritance mechanisms than, say, C# or Java, albeit also more foot-gun friendly. type Doer interface { DoIt() } type Foo struct {} type Bar struct { Foo } func (*Foo) DoIt () { fmt.Println("Just do it!") } func Incite (d Doer) { d.DoIt() } func main () { b := &Bar{} Incite(b) } One can transparently invoke Foo's DoIt on instances of Bar or, if Bar had its own DoIt defined, it would override that. Foot-gun wise, of course, if you convert a Bar to a Foo and pass it to something, you no longer get Bar's version of DoIt. However, anywhere that accepts a Doer accepts a Bar without decomposing it into a Foo, so Incite will invoke Bar's DoIt and, if Bar didn't define a DoIt method, it would still implement Doer via composition of Foo. One might argue that this is composition not inheritance, but although it's implemented as composition internally, from the outside it appears that Bar isa Doer, even though it doesn't implement DoIt. Usually, composition would require either forwarding methods which disguise the fact that composition is happening, or for external code to actually access the components directly. Go allows something that looks very much like inheritance. (I'd also note that, in reality, inheritance is internally implemented as composition. What Go makes explicit is what implicitly happens in C++ or Java anyway.)
- lbarrow 11y agoWeaker might have been the wrong word; it's more just different than anything else. Go struct embedding doesn't do much more than forward a method call to an inner struct: >There's an important way in which embedding differs from subclassing. When we embed a type, the methods of that type become methods of the outer type, but when they are invoked the receiver of the method is the inner type, not the outer one. In our example, when the Read method of a bufio.ReadWriter is invoked, it has exactly the same effect as the forwarding method written out above; the receiver is the reader field of the ReadWriter, not the ReadWriter itself. https://golang.org/doc/effective_go.html#embedding https://golang.org/doc/effective_go.html#embedding
- parenthephobia 11y agoI think the important thing isn't what happens internally, but what it looks like from the outside. Fundamentally, invoking a (non-virtual) superclass's method in C++ doesn't do much more than forward that method to an inner struct. struct Reader { int fd; } struct Writer { int fd; void Write (int) { // *this* points to the Writer, not the ReadWriter } } int writeForMe (Writer *w) { // *w* points to the Writer, not the ReadWriter } struct ReadWriter: Reader, Writer { } The only real difference, aside from the syntax, is that in C++ one can dynamically convert a pointer to a Writer that is part of a ReadWriter into a pointer to that ReadWriter, something Go doesn't support.