Newbie question regarding OOP
8 28 Jun 2015 12:40 by u/ThePenis
I am sorry for this stupid question, but I was unable to find a satisfying answer elsewhere. Regarding OOP, specifically class-based OOP languages like C++ and C#, the question is: should methods be sort of actions pertaining to a class, or should they strictly be behaviours of that class?
In other words, if a have a Point class, described by x and y coordinates, does it make sense for this class to have a distanceTo method, returning the distance from this Point to another Point, or would it be better to have a different static class with a distance method that took two points as parameters and returned their distance?
Distance is an action that is applied to the object, or rather to two objects in this case, and intuitively, to me, it doesn't make sense to "ask" a Point how much it's away from another point, but it would intuitively make sense to have a different object perform a calculation.
It makes sense if I think of methods as behaviour. A Point doesn't do anything, it's just a point.
In the same vein, suppose I have a Car class. Would it make sense to have a setter change its colour, or would it make more sense to have a different class do it? As before, it's counterintuitive, to me, to "tell" a car to change its colour.
Again, as a matter of behaviour, a car can accelerate, steer etc, but it cannot change its colour.
So, which of the following snippets (in a sort-of pseudocode) makes more sense?
Point p1( x1, y1 ), p2( x2, y2 );
distance = p1.distanceTo( p2 );
vs
Point p1( x1, y1 ), p2( x2, y2 );
distance = Calculator::distance( p1, p2 ); // Here distance is a static method
and
Car c( "red" );
c.setColour( "blue" );
vs
Car c( "red" );
Carshop::paintjob( c, "blue" );
Obviously the first snippets are easier to implement, need less memory and have less overhead, but they make less intuitive sense to me. What is the correct way?
Sorry if this is a stupid question, but I'm a newbie and need direction.
21 comments
9 u/Stavon 28 Jun 2015 12:57
This is not a stupid question, it's the sorrt of question people should aks.
There is no correct way, you always have to choose between several options. Unless one way needs to be taken for performance reasons I strongly recommend you use the most readable one.
4 u/nefreat 28 Jun 2015 14:39
There is not right answer but my personal preference is: Calculator::distance and Carshop::paintjob. I like Point and Car classes to be immutable data and have functions operate on the data. In fact I think Carshop should return a new Car instance. This approach translates nicely to F#
1 u/ThePenis [OP] 28 Jun 2015 14:47
Yes, I just finished playing around with Haskell for a small personal project and that's the exact same thing I thought about immutability. I learned to trust Haskell garbage collector, is C#'s comparable? In fact in the future I'll more than gladly learn F#, but I'm starting with C# because I also need to find a programming job relatively soon, and functional languages don't sell over here.
1 u/nefreat 29 Jun 2015 01:01
I would expect C#'s garbage collector to be superior to GHC's or any other platform outside of the JVM. The reason is simple, man centuries of optimization by a corporation that has the money to hire the best. Then again I haven't seen many papers talking about Haskell's GC.
2 u/el_cordoba 28 Jun 2015 13:55
Keep in mind that when you get to code in the real world you will find yourself cursing out the dev before you because they had no idea what they were doing. So while they did use "OOP" it was hardly correct. And they did it everywhere.
Anyway, I would say it total depends. If you only have one class like Car then I would say just make it a method of that class. If you had many classes with the same type of method then I would explore other options in the interest of reusability. For example maybe you might want to make a more inclusive parent class and put the method there instead.
2 u/fluffingtonthefifth 28 Jun 2015 14:33
There's a whole sub for newbies: /v/learnprogramming. You're welcome any time. :)
1 u/ThePenis [OP] 28 Jun 2015 14:42
Thank you, I will check it out
2 u/Master_Foo 28 Jun 2015 14:39
As others have said, there isn't a "correct" way to do this... skinning cats and all.
but there IS an OOP way to do this.
My opinion is that the "distance_to" method should go in the "point" class. Why? Because the point of OOP is to marry data to the methods which manipulate that data.
This way, everyone knows that if you want to measure distance between two points the methods to do that are in the "point" class. (Where else would it be? the "Calculator" class? Why the fuck is it there?)
It also keeps code DRY.
1 u/ThePenis [OP] 28 Jun 2015 14:51
That's what I meant, OOP way. Can you point me to a resource that explains and defines what the OOP way is?
As /u/nefreat suggested the second snippets cater more to immutability and a later-stage translation of the code to F#, both are things that I like but since C# is based on the OOP paradigm I'd like to learn the "correct" way to develop OOP code.
2 u/Master_Foo 28 Jun 2015 15:09
Not really, most OOP languages are actually "Multi-Paradigm" languages. In that, the language supports "OOP", but also supports "procedural", "functional", and other common paradigms. So, now we are back to skinning cats. Which is fine, you shouldn't feel pressured into purely OOP programming styles.
The main thing here, and someone already said this. Be consistent in the way you program. If you choose OOP try not to mix it up with "functional" unless there is a good case for it.
It should also be noted that OOP (in compiled languages) doesn't give you any performance gain or loss. (Exception being virtual methods (usually). This is the rule with a few exceptions)
All OOP is, is a method to organize your code to be more manageable for YOU the human reading the code. That is all.
OOP is an illusion. It doesn't exist after it's been compiled. Keep this in mind.
It could be. I'm not very familiar with C# and less so with F#. But I'm not sure he is correct if immutable works the same way in other languages. I'm assuming that if you are using the "point" object for a car, that "point" data is going to change as the car moves around the track. This would make it unsuitable for immutable data because immutable data isn't supposed to change.
But, I'll admit my ignorance, maybe C# and F# have this covered. I'm fairly sure that such a thing would not fly in C++ though.
0 u/ThePenis [OP] 28 Jun 2015 15:31
Thank you, I had oped there would exist a sort document standardizing OOP code structure, or at least discussing various styles and their advantages and disadvantages, I guess I'll just stick to my own style then.
The Point and Car examples were disjointed and just illustrative of the fact that I don't really know where to stuff the functionality in my program since C# doesn't support freestanding functions, so this prompted me to ask myself what the "best" course of action is (that is, what style represents the OOP way the most).
Also, if you have 25-30 minutes I suggest you read this article by Bartosz Milewski. I found it quite interesting.
0 u/Master_Foo 28 Jun 2015 15:41
If you are really interested, I'd look into Python and Ruby which have the somewhat ignorant philosophy of "Everything is an object". These are "opinionated" languages in that there is a "Python" way of doing things, or a "Ruby" way of doing things and they are both OOP heavy.
The problem is, they are not really "correct" in any sense. They are simply "opinionated" about the way things "should" be done and people who use these languages generally conform to the standard.
I tend to prefer Python myself. Python coders tend to understand that the "Everything is an object" philosopy is bullshit. Meanwhile, Rubyists have drank the coolaid.
0 u/Scaliwag 30 Jun 2015 21:39
If you want to go the immutable route you would not mutate the point, just return a new one. This is not exclusive to F# by any means. It's pretty common in other languages, even in C++ you can work that way if you're const correct.
1 u/112365365321 28 Jun 2015 16:35
Java: Walls and Mirrors is a good book for OOP Java, which is similar to C#. The OOP way should still carry on to most languages, there is just a difference in syntax. It also contains more of an explanation as to why you would use OOP, its purpose and also includes information on separating implementation from interface. Like others have mentioned, there isn't a "right" way, but to choose a specific answer for your question the preferred OOP way is generally the 2nd versions of what you posted.
0 u/Scaliwag 30 Jun 2015 14:31
That is the OOP way. But by no means it guarantees DRY.
What if you want to measure distances between points in a different coordinate system. Now points have to know about a bunch of coordinate systems. Oh and we want lines to do that too. Now you have to do the same code on the lines class, and then polygon, and so on.
That's why a more functional approach where a generic CordinateSystem class could manipulate all kind of objects you give it, without those objects knowing how you want to use them. A point is a point, it doesn't matter if it represents cartesian coordinates, geographic coordinates, etc.
1 u/Master_Foo 30 Jun 2015 17:09
Polymorphism and clever use of templates will solve those problems. I didn't mention it because OP's use case didn't require it.
0 u/Scaliwag 30 Jun 2015 21:16
I think polymorphism would only make it less straightforward, though. Which increases boilerplate, reduces readability and so on.
But we agree, a better solution would probably involve generic programming which can be bone using templates, for example. But that's would not be strict OOP, and purists would certainly frown upon it. Using templates would be a more functional approach, where you separate algorithms from the data they work upon, which is counter to OOP dogma. That's my point.
0 u/Master_Foo 30 Jun 2015 21:25
I've already warned OP against purists. If someone wants strict dogmatic OOP they should drag their sandy vagina over to Ruby and play with the script kiddies.
I mean, OOP is great. But it's not really a solution to a problem so much as syntax sugar.
1 u/Rhaelle 28 Jun 2015 15:05
I don't consider myself an expert but here is my take. I think it should be best if the function is static to the class. I'm not sure if this is possible or a good practice in C++ as I have coded only a little bit and some time ago in the language but it is certainly possible in C#. So you would have Point.Distance(p1,p2);
1 u/el_hombre 28 Jun 2015 15:12
I've been doing C# for over 10 years and this is usually how I have seen this type of stuff implemented. However, a recent project that I worked on has made me question the practice, mainly because of unit testing. We had one massive function that manipulated about a dozen other classes and when we came back and tried to add unit tests we found it nearly impossible (admittedly though the learning curve was a substantial factor). Unit testing static classes, while possible, is cumbersome and painful so I am almost of the opinion to not use them but in simple scenarios.
0 u/recursive 01 Jul 2015 01:20
I'd put these methods inside the associated classes. There are arguments both ways, but my primary reason is simple: They're more easy to find there.