Skip to main content
GameDev.net gamedev.net
🔒 Locked

OOP design question

Started by Imprecision Jul 10, 2012 at 2:07 PM 14 replies 2.9k views
Original Post
Imprecision
Imprecision
Hi there,

I asking myself for a while how to design correctly.
Let me get an example: (C#)
[source lang="csharp"]class SimpleClass
{
private int a = 0;
private int b = 0;
private int c = 0;

public SimpleClass(int a, int b)
{
this.a = a;
this.b = b;

CalcC(); // CALL DESIGN A
this.c = CalcC(this.a, this.b); // CALL DESIGN B
}

//METHOD DESIGN A
private void CalcC()
{
c = a + b;
}

//METHOD DESIGN B
private int CalcC(int first, int second)
{
return first + second;
}
}[/source]

I always used variant A when working with private methods. But then I realised that I can't put my methods in unit tests, because they are working with the class properties and don't return any values.

I working like variant A since years, and it would be nice if somebody can tell me something about this and the dos and don'ts of this.

Thanks.
Krypt0n
Krypt0n
it depends on your use case. if your function always just works on the a and b member, then it's enough to have only CalcC(), if you can reuse CalcC for other values, then it might be better to have Design B. If you use it on members as well as on 'other' parameters, then implement CalcC with parameters and overload it also with a parameter free version, that calls the version using the members as parameters. (In no case you shall implement it twice ;) ).
I think your unit testing would then still work.
I'm not sure about c#, but in c++ I'd implement the parameter version as static function, so it could be called as an utility from outside. if you have a bunch of those CalcC functions, I'd even consider to create a separate class, holding the static parameter-versions of all those CalcC functions.
Mussi
Mussi
I think the answer has something to do with semantics. I for one expect a function with the word calculate in it's name to return something and not hide the result somewhere in the background. Design A is also not very explicit in what it does, the function name informs us it assigns a value to c, but I don't think it's the right place for that. The function name should specify what it calculates(what is c?) and the variable you assign it to then speaks for itself.

I always try to write code that doesn't require documentation to understand what's going on, it's easier to maintain and share that way.
alnite
alnite
My guidelines is if it's a private method and always works on the same variables, then it's method A. Otherwise, it's method B.

In most cases, I initially used method A, and as the code grows, I would refactor that to method B when the need arises. So don't think that you are stuck with one, you can always refactor them.
M6dEEp
M6dEEp
The primary difference between the two is that design A is coupled to the class's variables, uses message coupling and is more stateful whereas design B is more functional and reusable. If you desire to clean up the constructor to make it more readable or possibly delay construction of an object until later then design A may be suitable and out in the wild this would be seen as a typical Initialize() method. Design B would be more preferable if you want to lower the amount duplicate code because of its use all around the class or you could even make it protected for child classes to utilize. Like Mussi pointed out methods provide metaphor for the code they contain, it is just as important (if not more so) to give correct and meaningful metaphor to code as anything else. So my answer is it depends on the method's use, which may change over the project's development cycle.

I would also like to point out that design A makes the class more procedurally coupled, since you cannot determine the value of c until you have the values a and b. This is something you want to typically avoid if possible but I understand it is a contrived example.
ProfL
ProfL

In general, you should prefer methods that do not cause side effects.

do you imply that a function that is supposed to calc something based on members, is having side effects although it's on purpose?
otherwise I'm confused what you could possibly mean, could you make your reply more detailed?
Telastyn
Telastyn
So the first CalcC has a side effect. That is, it modifies the program state by mutating c.

The second CalcC has no side effects. It takes input and returns an output. The second form has a number of advantages in design, testing, and concurrency.
SimonForsman
SimonForsman

In general, you should prefer methods that do not cause side effects.


i think that a method that has no sideffects and is unaffected by the current state(a pure function) most likely doesn't belong in the class. in my opinion a non static class really should only have methods causing or relying on sideeffects.

i think Method B should be a public static method in a static support class (in C++ it should be a free function imo).
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
Telastyn
Telastyn

[quote name='Telastyn' timestamp='1341972634' post='4957857']
In general, you should prefer methods that do not cause side effects.


i think that a method that has no sideffects and is unaffected by the current state(a pure function) most likely doesn't belong in the class. in my opinion a non static class really should only have methods causing or relying on sideeffects.

i think Method B should be a public static method in a static support class (in C++ it should be a free function imo).
[/quote]

I agree, but that's a different discussion.
rip-off
rip-off
You can design your classes to be easily testable. Some would argue that classes that aren't easy to test are badly designed in general. It would be interesting to see a real example class that you are talking about.
Krypt0n
Krypt0n

So the first CalcC has a side effect. That is, it modifies the program state by mutating c.
that's not a side effect, that's the purpose of this function, if every modification of a member in a member function would be a side effect, the whole Object Oriented Design would be a side effect design, as the so called 'proper way' to access member variables is via accessor functions (setter/getter), so when you call
Init()
SetC(..)
Clear()
Reset()
CalcC()
you'd also have a 'side effect' by your definition.

from http://en.wikipedia.org/wiki/Side_effect_(computer_science)
In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world....[/quote]

Design A is perfectly fine.
SimonForsman
SimonForsman

[quote name='Telastyn' timestamp='1342009482' post='4958000']
So the first CalcC has a side effect. That is, it modifies the program state by mutating c.
that's not a side effect, that's the purpose of this function, if every modification of a member in a member function would be a side effect, the whole Object Oriented Design would be a side effect design, as the so called 'proper way' to access member variables is via accessor functions (setter/getter), so when you call
Init()
SetC(..)
Clear()
Reset()
CalcC()
you'd also have a 'side effect' by your definition.

from http://en.wikipedia....omputer_science)
In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world....[/quote]

Design A is perfectly fine.
[/quote]

The 2nd quote contradicts your first post, Design A most definitly has a side effect, and yes, OOP pretty much relies on side effects (This is why, in computer science we talk about methods rather than functions when we deal with OOP and also why C is considered a procedural language rather than a functional one)
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
Krypt0n
Krypt0n

[quote name='Krypt0n' timestamp='1342082985' post='4958312']
[quote name='Telastyn' timestamp='1342009482' post='4958000']
So the first CalcC has a side effect. That is, it modifies the program state by mutating c.
that's not a side effect, that's the purpose of this function, if every modification of a member in a member function would be a side effect, the whole Object Oriented Design would be a side effect design, as the so called 'proper way' to access member variables is via accessor functions (setter/getter), so when you call
Init()
SetC(..)
Clear()
Reset()
CalcC()
you'd also have a 'side effect' by your definition.

from http://en.wikipedia....omputer_science)
In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world....[/quote]

Design A is perfectly fine.
[/quote]

The 2nd quote contradicts your first post, [/quote]I don't see what could make you think that.

Design A most definitly has a side effect, and yes, OOP pretty much relies on side effects
side effects are unexpected/unwanted effects. if you try to drive to work with your car, and you arrive, it's not a side effect. if you hit a bike while driving, that's a side effect. if the purpose of a member function is to calculate C for the object and this is the only think it does, it's not a side effect. Otherwise, what is the main effect, next to the side effect of this member function in Design A?


(This is why, in computer science we talk about methods rather than functions when we deal with OOP and also why C is considered a procedural language rather than a functional one)
[/quote]that's why we software engineers and architects love you scientist ;)
SimonForsman
SimonForsman

side effects are unexpected/unwanted effects. if you try to drive to work with your car, and you arrive, it's not a side effect. if you hit a bike while driving, that's a side effect. if the purpose of a member function is to calculate C for the object and this is the only think it does, it's not a side effect. Otherwise, what is the main effect, next to the side effect of this member function in Design A?


In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world....[/quote] (2nd quote from your post)

side effects (in programming) have nothing to do with unexpected/unwanted behavior, (unexpected/unwanted behavior are called bugs, not side effects). Normally this is covered in software engineering degrees as part of the functional programming courses.
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
Telastyn
Telastyn

if you try to drive to work with your car, and you arrive, it's not a side effect.


No, but the fuel you burn is.
The position of your car changing is.

And yes, pretty much all of OO is side effects. Which means yes... member methods should be avoided. This is well known best practice (almost always phrased 'prefer free functions') for more than a decade now.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.