Hacker News new | ask | show | jobs
by oivey 1452 days ago
OO schemas are very strict and in many situations difficult to extend. For example, let's say you have a class named Name that contains firstName and lastName. Let's say that you have a function that consumes lists of Names. Let's say you have yet another class called OtherName that contains firstName and lastName. That class will not be compatible with the function. Usual OOP suggests you solve this via inheritance, but if you don't own Name or OtherName that won't help you. OOP's tools for polymorphism are very limited, especially if you don't own all the code you're trying to use (third party libraries). If the "schema" enforced by the type system didn't include the name of the object that opens up a lot of possibilities.
2 comments

> OO schemas are very strict

I mean, it's the whole point. You want to have something that will give you compile errors whenever you change anything to make sure that you go all over the cases where the change has an impact

The goal of OOP or any programming system is to help you enforce invariants to improve correctness of a program. “has String members ‘firstName’ and ‘lastName’” is a perfectly reasonable invariant that isn’t all that well served by traditional OOP. You can’t strictly enforce the invariant I just stated via OOP. You can only define tangentially related concepts via inheritance.
> You can’t strictly enforce the invariant I just stated via OOP.

but you can strictly enforce it in pretty much every relevant OOP language - Java, C#, C++, C, Rust, D, ... by defining a class / struct / record with these two members, which is the only thing that matters. No one programs in abstract design principles, only in actual programming languages.

Ok, show me in C++. You have these three structs, which you cannot alter the signature of (maybe from an external library, maybe you don't want to introduce a type hierarchy in someone else's code, etc).

  struct Name {
    std::string firstName
    std::string lastName
  }
  struct AnotherName {
    std::string lastName
    std::string firstName
  }
  struct YetAnotherName {
    std::string middleName
    std::string lastName
    std::string firstName
  }
Write a single function that returns firstName and lastName concatenated. Bonus: write it for any struct containing firstName and lastName. The only way I can think to do it is via templates, which aren't traditional OOP and have their own downsides. Concepts in C++20 look like they make this much easier, but, again, not expressed via traditional object orientation and still infects your code with templates.

This isn't theoretical. I often don't want and often cannot use inheritance-based polymorphism. If I'm using a language where that is the only option, I'm struck writing tons of redundant, error prone, pointless, and brittle glue code. The amount of glue explodes combinatorially. That glue code can contain errors that the type checker won't find.

The inverse of this problem is also interesting. Someone wrote a function to concatenate the strings in Name. I can't put AnotherName into it unless the original author had the forethought to make their function templated. I guess the future of C++ is that all code ever lives in headers.

> The goal of OOP or any programming system is to help you enforce invariants to improve correctness of a program.

enforcing invariants means reducing the number of types that satisfy the invariant. I wouldn't call doing what you ask for "enforcing" any invariant.

> Bonus: write it for any struct containing firstName and lastName.

well,

    auto concatenate(auto t) { return t.firstName + " " + t.lastName; }
satisfies your condition - here's one that'll also handle middle names: https://gcc.godbolt.org/z/YfTYs6MMn ; again I don't think anyone wants this when they say "enforcing invariants", this does exactly the opposite of what is actually wanted.

> I guess the future of C++ is that all code ever lives in headers.

or in modules, which makes it very similar than other languages with generics instantiation

Ahh you’re, right, I forgot about fully auto’d functions. I think want more structure than just auto everything, although the compilers should find mistakes with that. Concepts will be nice.
This is the unfortunate side effect of the Javafication of OOP. Smalltalk doesn't have that problem. Neither does TypeScript, but it has taken us this long to start undoing the Javafication process.