Hacker News new | ask | show | jobs
by recursivedoubts 694 days ago
Agree 100%: static typing (for code completion) + method/data bundling is the major win in OO, and it rarely gets talked about for whatever reason.

It's unfortunate that inheritance became such a major focus of practical OO languages. Would love to see a composition-first OO language. Might have its own problems, but would at least be interesting.

4 comments

Go, Rust, Zig, etc all support static typing and method/data bundling without any explicit language support for implementation inheritance (interface inheritance in general and especially when structural rather than nominal is not nearly as much of an issue and doesn't create strict tree hierarchies).

Rust has support for variance and subtupint so perhaps it's not as pure of an example, but it's pretty heavily restricted.

Zig's support for method/data bundling being used for "objects" isn't even first class so I wouldn't call it OO (object-oriented) so much as object-orientation-capable with less fuss than if one wanted to build their own objects system in C.

Even in C++ the last time I thought I might need inheritance I made a simple class/struct with a few members that were `std::function` instances. Instead of needing inheritance this worked and I managed to keep type safety checks on all function return and parameter types. Once upon a time this would have been weird function pointers and `void*` with dangerous casts. Last month when I did it, there were just lambdas passed to typesafe constructors.
Go's first class support for typed return tuples and Interfaces is a lovely replacement for inheritance (E.G. an Interface of type blah supports this signature). They function as an API contract, if a given class implements the requirements of the Interface, it can be cast to and used as that anywhere which accepts that interface.
It's not unfortunate happenstance, it's by definition.

Dynamic dispatch is the defining feature of object-oriented programming. In dynamically typed languages such as Smalltalk, you can get there with duck typing. But a statically typed language needs a statically typed mechanism for dynamic dispatch, and that requires some way of saying, "Y is a particular kind of X, so all members of X are also in Y." Which is - again by definition - inheritance.

You could remove - or refuse to use - the inheritance (or, equivalently for some purposes, duck typing). But that would also prevent the use of dynamic dispatch, so what you're doing would bee be procedural programming, not OOP, even if you're using an object-oriented language to do it.

> Dynamic dispatch is the defining feature of object-oriented programming.

Message passing is the defining feature of object-oriented programming. Dynamic dispatch can be achieved using message passing, but message passing is more than dynamic dispatch.

Ultimately, static typing is incongruent with object-oriented programming. Messages are able to be invented at runtime, so it is impossible to apply types statically. At best you can have an Objective-C-like situation where you can statically type the non-OO parts of the language, while still allowing the messages to evade the type system.

Whether you'd call "composition-first" is probably asking for a big argument about what "composition first" really means, but Go is certainly a language that syntactically privileges a particular type of composition over inheritance. It doesn't even have syntax for inheritance, and frankly even manually implementing it is rather a pain (best I've ever done requires you to pass the "object" as a separate parameter to every method call... and, yes, I said that correctly, to every method call).

I'm not ready to try to stake a position on the top of some "composition first" hill because the syntactic composition it supports is not something I use all the time. It's an occasional convenience more than a fundamental primitive in the language, the way inheritance is in inheritance-based languages. Most of the composition is just done through methods that happen to use in composed-in values, but it is generally not particularly supported by syntax.

Typescript and it's structural typing my be what you're looking for.