Is encapsulation necessary in solo projects?

I am currently programming a game solo. I have an Object class that has a craftingMenu() member, in which I use public attributes (miscItems and blueprints) from another class (Character class).

However, I've been conscious that normally you would use encapsulation (use private attributes and use public getters and setters) to get the values passed to the Object class and passed back to the other class. But honestly, this is time-consuming to implement, compared to just directly using the attributes of the other class, especially when you have a larger and larger requirement for using those as more and more variables from other classes, even global variables need to be used in the class. Not to mention having to place the calls to getters and setters in the right sequence in the main loop.

So is encapsulation necessary for a project like this?

I can already see the first response to my post being: "do it, it will save you a headache down the line". But come on, having to create getters and setters, and figuring out where to place those in the main loop so they are updated with the right values at the right time, for each attribute I want to use inside the class, is very time-consuming. I can see the reply already: "not as time consuming as having to figure out where those variables were changed across the entire code". Lol.

Would you bother taking the time to implement encapsulation in this case?
Looks like you've made up your mind already.
LOL
I'm absolutely in favor of encapsulation. However, I'm NOT a fan of writing getters and setters for every variable. If you're going to do that, you might as well make all the variables public and forget the getters and setters.

Instead,, you should analyze your class and determine what ACTIONS your class should perform. Those actions become your member functions. Those same actions operate on the private variables that make up the class.
I often use this to save a bit of typing:
1
2
3
4
#define DEFINE_INLINE_GETTER(x) const decltype(x) &get_##x() const{ return this->x; } 
#define DEFINE_INLINE_NONCONST_GETTER(x) decltype(x) &get_##x(){ return this->x; } 
#define DEFINE_INLINE_SETTER(x) void set_##x(const decltype(x) &v){ this->x = v; }
#define DEFINE_INLINE_SETTER_GETTER(x) DEFINE_INLINE_GETTER(x) DEFINE_INLINE_SETTER(x) 
Using getters and setters or not using them is not about whether you're working on your project by yourself, but about giving yourself some wiggle room to redesign your class. If it later turns out that you need a property of your class to be dynamically computed rather than part of the state, or if you need to add more logic when a property is updated, updating all the usages of the property is going to be a pain. If you think you're never going to need to redesign the class' interface then go ahead and use public members. Just be aware of the trade-off you're making.

figuring out where to place those in the main loop so they are updated with the right values at the right time
How is that any different from referring to the objects directly?
I think this may very well be the first time I've heard a programmer complain about having to do things in a specific order for them to work. You do understand that you're basically complaining about having to program, right?
Last edited on
it depends. I dislike do-nothing getters and setters. I totally get you on that. My dislike is the space they take up and visual clutter.

Here are some things to consider before going rogue:
- if tampering with a variable breaks the class, it should be locked up. Consider vector<> for example, if the user can set the size by direct access, that breaks things: memory may not exist that far out if increased, and it would crash.
- common interface is good. having some stuff direct access and other stuff via a getter is more annoying than having all getters.
- modern IDE make getters a one-liner, and modern compilers optimize them away usually. They cost nothing unless they do something, the only drawback is a little visual clutter.

so, lets start with the core complaint. WHY do they take a long time to implement for you? They should just be one line in the header files, 99% of the time:

class...
...
public:
thing& getthing(){return private_thing;} //a good editor can literally make a macro to craft this from the variable declaration, making it a single keypress to craft it and a copy/paste to place it. You may want a couple of them for references, copies, constant, etc formats.
Last edited on
But come on, having to create getters and setters


Indeed, but if you try harder then encapsulation is not all about setters and getters only.

You should always write setters and getters, the question is do you really need them for all member variables? and even more importantly do you even need all those variables in the first place?

Instead of avoiding setters and getters, first step is to access restrict member variables into private\protected (and almost never public).

Because by reducing amount of variables you also reduce amount of needed getters\setters.
It's all about how you design your classes, for example, setters and getters should always be inline methods, defined in header (but outside class).
Inline setters and getters should take no more than 2 lines.

Why inline? because you want your cpp file clean, containing only functions that are not setters\getters, that way you forget of having them, main point is cleaner cpp file and secondary benefit is letting compiler inline them if possible which is small performance benefit.

Usually you need much more getters than setters, a lot of setters are sign of bad design, because that's what class function should do, not the user using setters.

----
Bottom line:

1. Limit amount of variables to only those really needed.
2. Limit your getters to minimum to only those variables you directly use in other code.
3. Limit setters to minimum, many setters are bad design.
4. Never access variables directly, ex. public access.

If you hate writing setters and getters reduce them, change design of your classes, but do not remove getters completely.
Guys, I have a reply for each and every one of your questions, critique and (wrong) assumptions on what and how I program but I am simply too exhausted to reply to you all. I am in the middle of a cutting bodybuilding diet, high load, high volume and high frequency training and on reduced sleep, so sorry. I think given the trade off, I am happy to keep using public variables where I need to for this project.
Last edited on
There are several concrete reasons to avoid get/set functions, in particular the one-liners that don't do anything except assign or return some member data. Three of the most major reasons are:

- Get/set functions are more expensive in terms of development effort. This is because a programmer can't always determine required information about a function without reading documentation or the source code.

For example, we cannot assume much about the behavior of the imaginary member function
foo.get_frobnicator()
without reading its source code or its documentation. What exception-safety guarantee does it offer? Which exceptions does it throw? Can it be called from multiple threads? Is it a constant-time operation? Does it allocate memory (e.g., some kind of cache)? Failure to account for this will introduce runtime failures and make your product worse.

- Pass-through get/set functions rarely offer a useful measure of flexibility. For example, if
foo.set_frobnicator()
is modified, the change may strengthen but not weaken the interface's guarantees. If that isn't possible, each call site must be reviewed individually, to check for cases where the weakened guarantees may cause problems.

Such changes are surprisingly rare; even if a change can be implemented in terms of the get/set function it is unusual that it can be made without reviewing the call sites. In all but those rare cases the get/set functions prove to be a useless investment.

- Pass-through get/set functions may be less performant. For example this program copies an object of type A where it would have been moved if the programmer had used the simpler option.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <cstdio>

struct A {
  A() = default;
  A(A const&) { std::puts("A::A(A const&)"); } 
  A(A&&) { std::puts("A::A(A&&)"); }
};
struct B { A a; A get_a() const { return a; } };

int main()
{
  A a1 = B{}.get_a(); // getter incurs potentially-expensive copy construction
  A a2 = B{}.a; // direct access incurs potentially-cheap move construction
}

This is not an inevitable consequence of get/set functions; one could double down and write the appropriate overloads.

Despite these disadvantages, one might write a get/set function anyway if there are class invariants to be maintained, there is meaningful work to be done in the get/set function, or if the interface is used so widely that the additional flexibility is worth it anyway. For example the get/set functions may do actual work by calling through a compilation firewall.
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#i27-for-stable-library-abi-consider-the-pimpl-idiom

In most cases it's easy to add the get/set functions later on, if and when they are actually required.
Last edited on
I would make a member variable public when a setter is required. Internally a public variable needs to be treated with special care since it can change at any time.

So: No I don't see any use for getter and setter. Just for getter.
None of these rules are necessary, they're just guides to help us on our way.

For example, you don't need skyscraper building codes if you're building a chicken coup. The catch is, in programming, you always cross that line without realising it.

In programming, especially C, but true in any language, things get complex fast. The guides are ideas folk came up with to manage this complexity. Thinks like:
* use of libraries
* typed languages
* no global variables
* structured programming
* data structures
* encapsulation
* object oriented programming
They exist because they helped someone make sense of this cruel world. You can reject all that stuff if you want, and live free of professional dogma.
Last edited on
But come on, having to create getters and setters, and figuring out where to place those in the main loop so they are updated with the right values at the right time, for each attribute I want to use inside the class, is very time-consuming.


This statement strikes me as indicating that your design could be improved. Without knowing anything about your code (because you haven't given us any examples or what you are trying to do), I envision a situation where the class should be performing an action and setting its variables.

For instance, if your class is a bouncing ball, and it has x, y and z coordinates, you don't want the main loop to calculate where the ball will be and then set the ball's member values. Then main loop should call the ball's move() function, which sets its own member values.

To me, your post sounds like you are trying to do something akin to calculating the ball's position in the main loop and then telling the ball where it is.

It is possible, however, that you have a class where you are just storing a bunch of values that are only tangentially related to each other. You might want to calculate them in one function and display them in another function. For instance: start and stop times, calculated value, result, etc. If this is the case, I would just make it a struct (a class with all public members) and don't worry about getters/setters.

A little more detail about your classes and their members would make it easier to help you.
So: No I don't see any use for getter and setter. Just for getter.


and, if you end up with that design you can mask the variables with public constant references instead of a function. So if changing it damages the object, lock it, if not, give full access, and either way, the interface is the same (object.variable) to the user. Here again a macro editor can just make the line you need with 1 click.

it gets tricky -- an example: its good practice to split interface (cin? edit control? file stream? network? ) for how you get and print things from processing. But its nice to have this stuff in the class, so you don't need to run getter/setter mess just to print a value. Then you get a choice of a skyscraper (borrowing above) where you inherit a processing class into a UI handling class, the UI class can directly set / get the items via inheritance so the processing/work class does not need a lot of get and set. Advanced designs can get rid of the need to have a get/set for everything, but now you have a more complex design to deal with.

Lets take one more simple example. There are plenty of classes that violate the rules of 3/5/numbers and work fine. They only break if you try to do something with them that triggers the problems that those rules help solve. If you do not do those things, its fine, but it will make a purist tear their hair out in frustration even so.
Last edited on
Topic archived. No new replies allowed.