# Disclaimer

I'm afraid there is no "right" or "wrong" here. There are just a bunch of opinions, and either way you will be able to find a sizeable group of people supporting the idea. As such, my answer here is not a "this is correct", but rather a "this works for me".

# A direct answer to your question(s)

> why wouldn't I then just write a pure, static, stateless function in a class called NotesHelper? Creating a manager class to just have one function double calculate(), and using its instance instead of a static function feels to me like making it look like OOP while it isn't really.

I agree and disagree at the same time.

It is correct that there is no difference concerning functionality. In this situation, a method or a static function will do the same thing, and apart from having to instantiate the class, there is no difference in usage either.

**On the other hand,** the OOP concept of _encapsulation_ means caring about the interface and not about the implementation. All that we care about is that we call `gpaCalculator.Calculate(...)` to get the GPA. What `GpaCalculator` does internally - or if there even _is_ an "internally" - doesn't matter to us. The class `GpaCalculator` does not have any fields and it could be a static function instead? _We don't care._

# To what end though?
The benefits of using an object here is in the encapsulation. This doesn't give you any advantage _at the moment_. It's more about the future.

Imagine the calculation gets more complicated in the future and `GpaCalculator` now _does_ need a private field to do its job. You can add it with a constructor argument; now every place where it's constructed gives you an error and tells you "hey, I need that thing over here". This might only be one place.

However, every place where `Calculate()` is called will not need to change. And that makes sense, because those calling places haven't changed; they still just want to have the GPA calculated.

(Maybe GPA calculation doesn't change and it's a bad example, I don't really know the US school system. The general idea should be clear though.)

# Additional info

### Managers
Please put a lot of effort into avoiding "-manager" as a class name. It doesn't tell you anything about what it does, really. Just compare your own example; imagine how much another programmer knows if they see the class name `GpaCalculator` vs. `NotesManager`. Use [a thesaurus](https://www.thesaurus.com/), it's the most underrated programming tool.

### Inhertiance
Inheritance is _way_ over-hyped in schools. I would advise to [favour composition over inheritance](https://en.wikipedia.org/wiki/Composition_over_inheritance). So, a `Student` and a `Professor` "have" a `Person`, instead of "being" one. It doesn't make a lot of sense in English, but it will save you [some headaches](https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem). For example, a professor might take a course. You can then easily have a `Professor` and a `Student` both referring to the same `Person` object.

### The "Uncle Bob" school of OOP
In the book "Clean Code", Robert Martin elaborates on a style of OOP that has worked well for me, and which I still use:
> Objects hide their data behind abstractions and expose functions that operate on that data. Data structure[sic] expose their data and have no meaningful functions.

Well, "data structures" already has a different meaning in computer science, so I prefer to call them "data holders". Either a class holds data (in your example, `Student`, `Professor`, `Course` etc.), or it does something to data (e.g. `GpaCalculator`). When I say that this "works well for me", I mean it provides

- easier creation; it's pretty clear where new code goes, less issues with finding good names etc.
- easier change; it keeps things pretty easy to refactor (e.g. a change in `GpaCalculator` is pretty much unable to introduce errors in other objects that work with the same data)
- easier diagnosis; bugs are relatively easy to track down

Some people don't like this approach, but that seems to be restricted to people who haven't used it.