object oriented programming: there are 50 classes. they all have some overlap in their venn diagram. some of the overlap is in a third or fourth dimension that cannot be graphed with human brains. your eyes register nothing but a hideous, writhing mass when you try.
@aud The problem with OOP in general, IMHO, is that it couples subtypes and typeclasses in a very confusing way.
@aud You can kind of deal with that by being very disciplined about keeping your inheritance tree to zero or one levels of depth, and using fully abstract classes (interfaces) to do the bit that looks more typeclass-y, but it's very hard to add new functionality to an existing design that way without breaking back compat... so folks tend to just poke holes in the design instead.

@aud To be a little more precise, a function like `void foo(Bar bar)` and one like `fn foo<T: Bar>(bar: T) -> ()` are morally quite similar, if extremely different in literal meaning. They're both ways of saying "this function takes a value of any type that's Bar-like," but the former *also* adds that any individual value of a Bar-like type can be referred to by a binding of type Bar.

That's a very heavy additional assumption, and places severe constraints on how you organize code.

@xgranade

this function takes a value of any type that's Bar-like,you know what's interesting, is I haven't really had to play too many object oriented struggle games in C/C++/C-style languages, thankfully, so I wasn't actually aware of this specific distinction. Usually I just watch the compilation fail, curse loudly, cast, and move on.

@aud Yeah, basically polymorphism says that there's no difference between a type T having U-like behavior, and T being a subtype of U. So then you get that in order to do U-like things with a value of type T, you need to be able to bind it to a variable or parameter of type U, which, fine... but that leads to a lot of nonlocal confusion down the road.
@aud Consider a function like `Addable add(Addable a, Addable b)`. The clear intent is that you can add two values together of the same type together, so long as that type is addition-y. But there's a missing constraint there, namely that the two parameters are the same subtype of T.

@aud So you can solve that with `T add<T>(T a, T b)`, but now you've lost the `Addable` constraint. The most common solution I've seen is to have `T add<T: Addable>(T a, T b)`.

But there's a word for "a collection of types that can be used to satisfy a constraint on valid type parameters." It's a typeclass, or in Rust terminology, a trait. Or in C++ terminology, a concept.

@xgranade @aud

> It's a typeclass, or in Rust terminology, a trait. Or in C++ terminology, a concept.

love to have three different names for a similar thing, all of which are overloaded in other English uses (except maybe `typeclass`)

@trochee @xgranade HAD THE EXACT SAME THOUGHT

like WHY did you pick "concept". I don't love the overloading of trait, but it's better than concept ffs.
@trochee @xgranade may as well call a highly specialized type or behavior thing in the language/compiler a "feature" at this fucking rate

Or, hell, why not just keep overloading object?
object Object<object: Object>(object: Object) {}

bastards
@trochee @xgranade write a programming language that dares to refer to brackets as "objects"

or even just uses
object object, which represents the classic { } in other languages...
@aud @trochee That's JavaScript, hence the "O" in JSON.