this post was submitted on 02 Feb 2024
51 points (89.2% liked)

Programming

17270 readers
39 users here now

Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!

Cross posting is strongly encouraged in the instance. If you feel your post or another person's post makes sense in another community cross post into it.

Hope you enjoy the instance!

Rules

Rules

  • Follow the programming.dev instance rules
  • Keep content related to programming in some way
  • If you're posting long videos try to add in some form of tldr for those who don't want to watch videos

Wormhole

Follow the wormhole through a path of communities [email protected]



founded 1 year ago
MODERATORS
 

There are so many definitions of OOP out there, varying between different books, documentation and articles.

What really defines OOP?

you are viewing a single comment's thread
view the rest of the comments
[–] [email protected] 6 points 9 months ago

keeping state (data) and behavior (functions) that operate on that state, together

Importantly, that's "together at runtime", not in terms of code organization. One of the important things about an object is that it has dynamic dispatch. Your object is a pointer both to the data itself and to the implementation that works on that data.

There's a similar idea that's a bit different that you see in Haskell, Scala, and Rust - what Haskell calls type classes. Rust gives it a veneer of OO syntax, but the semantics themselves are interestingly different.

In particular, the key of type classes is keeping data and behavior separate. The language itself is responsible for automagically passing in the behavior.

So in Scala, you could do something like

def sum[A](values: List[A])(implicit numDict: Num[A]) = values.fold(numDict.+)(numDict.zero)

Or

def sum[A: Num](values: List[A]) = values.fold(_ + _)(zero)

Given a Num typeclass that encapsulates numeric operations. There's a few important differences:

  1. All of the items of that list have to be the same type of number - they're all Ints or all Doubles or something

  2. It's a list of primitive numbers and the implementation is kept separate - no need for boxing and unboxing.

  3. Even if that list is empty, you still have access to the implementation, so you can return a type-appropriate zero value

  4. Generic types can conditionally implement a typeclass. For example, you can make an Eq instance for List[A] if A has an Eq instance. So you can compare List[Int] for equality, but not List[Int => Int].