Here's my perspective on it. It's just my opinion, so take it with a grain of salt.
Madrayken wrote:Good question. I assume that OOP involves structures holding both data & functions that act on that data, subclasses & encapsulation.
I agree with this, except for the "subclasses" part. I don't think subclassing (or even "classing") is critical for OOP. Of course, all that proves is that we have different ideas about what OOP means (or maybe different ideas about what features of OOP are the most important).
If you're encapsulating and subclassing, then yes. If you're not subclassing then the classes are really just containers of data+methods. Is this *strictly* OOP? Yes. Is this the 'full spirit' of OOP? Not really. It's just being tidy!
I see what you're getting at, but I think the benefits of subclassing are just a side effect of the fact that subclasses will
share a common interface when treated as instances of a superclass. Having objects that share a common interface is what's important to me about OOP; this is where the polymorphism benefits come from. The interface here doesn't need to formally exist, it can just design by contract.
Yes, there is the added benefit that methods of a superclass are "very close by" in a subclass, but this is really just a convenience, and not always worth it.
Advantages are (theoretically) reusable code (i.e. less repetition enabled by extension of base classes), clarity of what data your functions are designed to work on.
To me, the main advantage of OOP over procedural is polymorphism. In other words, It doesn't matter how an object does something, and we don't need to specify a particular implementation of a function when doing something with an object. We just say objectA:doSomething() and the object is responsible for knowing how to do it. This is why the concept of "structures holding both data & functions that act on that data" is important, in my opinion.
The clarity thing is nice, but not a huge deal; good naming conventions could take care of that in procedural code.
The inheritance thing can also be nice, but it's a double-edged sword.
The only real disadvantage, I think, is that sometimes you just don't want the functions coupled to any data... except that you could just have a singleton class that manages data but doesn't hold any data itself, if you were bent on all-out OOP, so that's not really a huge deal.
Considering the potential complexity of Lua's return types, FP should be fairly unrestrained. Apart from that, I haven't coded in FP since Miranda in the '90s! I'll need to do some research.
To me, it means you have the option of using patterns like mapreduce, memoize, bind, and so on. It also means you can make use of first-class functions and closures to write functions with very few assignments and no side effects. I think this can co-exist perfectly happily with OOP code. For example, nothing would stop you from giving your own data structures "each" or "map" as methods.
My understanding of design patterns is pretty sketchy. I know it's simply a formalized way of approaching common problems, but that also sounds like it would involve a choice of paradigm to me! I guess you're saying that problems are problems, and each can be solved in a number of ways. A specific OOP approach and a functional approach can co-exist in Lua.
You got it, Toyota.
Nnnnnghhhh...
Yes, it's possible! Take a look at the excellent
d3.js, my favorite example of an object-based API with a very declarative feel.
Anyway, all that aside, I don't think you need to ditch OOP, but I think you may have put inheritance on somewhat of a pedestal. I'd try to look for other ways of reuse (composition), and think about the other things you like about OOP, and also think about the bad parts of inheritance. The ECS pattern discussed earlier is a good example of how code reuse can be achieved in a more flexible way without inheritance in some cases (of course like any pattern it's only useful in certain situations).