Live data from Hacker News

A Healthy Hatred of OOP, or the principles of my message-driven framework

bythehilt.com

71–80 of 98 posts

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#71
post #51

>> When I started learning C++ I was shocked. Instead of using objects for compartmentalizing functionality, they were just used as a holding pen for loosely related functions. Instead of communicating between themselves, objects were operated on by some bigger parent object. I found it absurd and fought it for a long time. This has nothing whatsoever to do with C++. It's like blaming a microwave oven because your ki…

The Linux kernel is written in C, not C++. C has static typing, but it is definitely not strong static typing.

Yeah I did not mean to imply that the kernel was written in C++. As to whether C is "strongly typed" or not that is a matter on which we can disagree, as there is no agreed-upon definition of what that means. In my view it certainly falls on the strongly-typed side of the line when compared to the languages most developers use today. The point of my response is that OO methods as embodied in C++ were a response to the growing complexity of compiled programs back when it was developed, and those principles definitely helped developers, including myself, get a handle on that complexity.

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#72
post #64

Earlier quoted context omitted.

how fast can that player run? Is asking about internal state. When can you get to X is not. The internal vs. external separation can often greatly simplify things. A player does not care where another players feet are they care where the best place to toss the ball is. PS: In an actual game there is a lot of communication going on. You don't want to throw a ball at someone looking in the wrong direction. So, at some…

Of course there's innate complexity, but pursuing encapsulation for its own sake adds complexity you don't need (just like using functional programming techniques for intrinsically non-functional use-cases adds complexity for no good reason). Again, "messages", "objects", etc. -- these are metaphors. They should be abandoned as soon as they stop being helpful.

Generally, if you don't want encapsulation then your not dealing with an independent object. You could write a game using 2 objects or 2,000, but building complex systems without partitioning becomes incredibly difficult. At the core Objects are a very basic abstraction. It can be as basic as Simulation Rendering, but it's hard to point to a complex system and say this really is best represented by a big ball of mud.

So, sure not everything should be an object. But, saying nothing should be is a much higher hurdle than that.

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#73
The more I read about functional programming the more I question why are things this hard in traditional oops. If so many people have been doing oops for so many years then it must have something that is easy to pick up or something that is easier to work with. But after doing some functional programming the number of lines are painfully less and the code is easier to understand. I was thinking may be I was giving too much credit to FP but I was not it's simply just the way things are. But why has FN been used only as an academic tool and not as a goto programming paradigm? Can someone shed some light on this?

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#74
post #41

Earlier quoted context omitted.

>If a class has state, you have to be able to read that state or it's useless. ... That's where getters come into play. No, having a bunch of getABC(), getXYZ(), getEtc() is a code smell . If the class has many getters()+setters() or has the equivalent of many public data members, it means that related actions requiring those variables are happening outside of the class/object instead of inside the class. The more ge…

You don't seem to realize it but your countLines() method is a getter. At the end of the day, you need to get values from your class, otherwise, they are useless (and they do side effects).

>At the end of the day, you need to get values from your class,

Yes, you eventually have to "get" values from the class but you don't literally have to mindlessly create a one-to-one set of "get()" for every private member variable.

The author's example and my response to it were talking about a literal thin wrapper of public getX() for a private int x. This practice deceptively looks like OOP (I "hid" that private member with a public method) but it's not really OOP.

Instead of gets() & sets(), the programmer should find the higher level concepts to turn into higher-level methods. This way, the gets()/sets() is kept to a bare minimum.

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#75

The more I read about functional programming the more I question why are things this hard in traditional oops. If so many people have been doing oops for so many years then it must have something that is easy to pick up or something that is easier to work with. But after doing some functional programming the number of lines are painfully less and the code is easier to understand. I was thinking may be I was giving to…

Historically, mostly performance. Outside of academia, performance becomes an important factor in most programs. In the past, both slower computers and fewer optimizations made implementing the abstractions of functional programming ridiculously costly. Once it lost out to imperative programming, it only got harder to change the tide. Performance is now adequate but functional languages lack educational material and libraries as well as industry support.

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#76
post #43

Earlier quoted context omitted.

Moreover, getters and setters can be readily modeled with messages. That messages and (at least single dispatch) methods are identical was settled decades ago. (Has someone worked out a multiple dispatch OOP based on message passing?)

The conceptual difference between messages and methods to me is that messages implies that it is the object itself that is the arbiter of whether or not it can handle a specific call, and the decision may depend on factors not knowable before the call. While "method" implies to me that it is something that may be applied to the object by an external actor. E.g. if I do "foo.bar()" in C++, the compiler will simply not…

> if I do "foo.bar()" in C++, the compiler will simply not compile the code if "bar" is not already defined on the class "foo" is declared as

In a more dynamic language, in fact "foo.bar()" may be equivalent of asking foo whether it understands how to bar, and if so, then please do it. If foo doesn't understand, there could be some mechanism for handling that, like a catch-all function that can be defined that gets invoked.

Likewise, we could also have a static language with message passing OOP in which the same check is implemented. The classes declare statically which messages they understand and the compiler checks that.

Quite simply, "late binding" != "message passing". There can be late binding of messages, and late binding of function calls.

There is no real conceptual difference between single dispatch and (synchronous) message passing.

What is Unix ioctl? Message passing or function call?

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#77
post #10

The less actual code I see in articles like this, and the more abstraction I read about, the less I take the concept seriously. In fact, all of this seems like bullshit to me. The actual code inside of the repo is, well, object-oriented. How I interpret this is that the author seems to have no idea what they're even talking about, and that they write more about code than they write code itself. Show me what you mean,…

I should have a tutorial out very soon. The documentation is not yet complete but does have a few examples. Also, of course it's object-oriented. The article is titled a "healthy" hatred for a reason.

I just have one smallish question. Is the need to bench then add an actor the only way you "allow" transfer of children between parent actors?

In similar systems that I have constructed in the past, I have used a number of methods for passing actors in different states.

Pass a fully instantiated actor via a transfer process. Nothing changes for the actor, beyond reassigning parentage.

Pass a cleaned actor via a similar process to the bench and add process. This was used to allow an actor to be reduced to a resting state as it were. In most cases you could think of it as a resurrection method that allowed discarded actors to be reinstated with only specified base properties in place.

Anyway, I don't use Lua at all, but I like these type of actor messaging models. I look forward to reading through the rest of your documentation once it's done.

O.

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#78
post #6

The downside of message passing is debugging. No call stack so you can't trace things back to their source.

That's a big down side of a framework for asynchronous message passing (object-oriented or not). E.g. "Flow based programming". Message passing OOP doesn't necessarily imply that type of message passing. That is to say, the "send" call doesn't have to return until the target object has processed the message.

In a way, message passing using the usual way, methods, means TWO messages are passed: The parameters and the return value.

I think that obscures the better parts of the OOP view quite a bit.

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#79
post #4

Your essay is arguing against a strawman of what "good" OOP is supposed to be. Your examples... >Objects just aren't supposed to be reaching into each other with 'getters' and 'setters' and messing with information. The getX() and setX() is an anti-pattern of good OOP. >Instead of using objects for compartmentalizing functionality, they were just used as a holding pen for loosely related functions. No, good OOP has c…

> The getX() and setX() is an anti-pattern of good OOP. No it isn't, it provides encapsulation, which the most important aspect of OOP. I agree with the rest.

Getters and setters are an anti-pattern that works around a specific deficit in a programming language. In Python, if you want to refactor an object so that `foo.bar = baz` does something other than blindly set foo's bar to baz, you can. In Java, you can't, which is why setting foo's bar to baz is done with `foo.setBar(baz)`.

Re: A Healthy Hatred of OOP, or the principles of my message-driven framework

#80
post #10

Earlier quoted context omitted.

I should have a tutorial out very soon. The documentation is not yet complete but does have a few examples. Also, of course it's object-oriented. The article is titled a "healthy" hatred for a reason.

I just have one smallish question. Is the need to bench then add an actor the only way you "allow" transfer of children between parent actors? In similar systems that I have constructed in the past, I have used a number of methods for passing actors in different states. Pass a fully instantiated actor via a transfer process. Nothing changes for the actor, beyond reassigning parentage. Pass a cleaned actor via a simil…

>Is the need to bench then add an actor the only way you "allow" transfer of children between parent actors?

Currently, yes. Since this is sort of an entity component system and that actors can always create more children anytime they want, I suppose I just always assumed that actors could be "spun-up" with any sort of functionality and then deleted when not used.

Benching/Joining an actor is more for handling errors at runtime or for debugging ("If I temporarily remove this actor will it solve my issue?").

Post reply on HN