Hacker News new | ask | show | jobs
by nine_k 1821 days ago
Polymorphism is good. You describe polymorphism.

Inheritance is bad. Inheritance is patching a class and overriding some of its methods, while leaving others intact. This brings all kinds of unexpected interplay between methods of different levels of overriding. A typical example is http://www.cse.psu.edu/~deh25/cmpsc473/jokes00/joke01.html

Ideally all "concrete classes" with method implementations should be final, and the polymorphism should be achieved via interfaces / typeclasses / traits, or purely abstract classes where these are not available. Reuse of implementation should be achieved via composition; there are several ergonomic ways to express it.

2 comments

> Simulator supervisors report that pilots from that point onward have strictly avoided kangaroos, just as they were meant to.

Won't fix; working as intended.

> Polymorphism is good. You describe polymorphism.

It also seems like they're describing the nominal typing of Java versus a structural approach.

Haskell and, IIRC, Rust allow you to declare that a certain data type conforms to some interface, and describe how, by listing / adding the functions with necessary signatures.

This allows to have the upsides of structural polymorphism without losing static checks.

Go, OTOH, goes all the way structural.

> Haskell and, IIRC, Rust allow you to declare that a certain data type conforms to some interface ...

I believe at least in the case of Haskell, you are referring to type classes[0].

0 - https://wiki.haskell.org/OOP_vs_type_classes

I'm unfamiliar with anything like that in Rust, beyond Rust's structural approach to tuples. I'd love to hear more about it, though!
I think they're just talking about how you have to declare what trait a function implementation is for, rather than having it derived from the type signature alone. The `impl Trait`[0] syntax. In Go, you don't need to declare that the function implementations are being implemented for a particular interface, you just have to match the type signatures and function names.

Rust's way can help avoid some errors. You can't accidentally implement an interface, whereas in Go you can if you happen to implement a group of functions with appropriate names and type signatures. It's unlikely to cause actual bugs (you'd have to misuse the resulting implementation) but can be conceptually somewhat confusing.

[0] https://doc.rust-lang.org/book/ch10-02-traits.html#returning...