Code Style Request: More public members, pls

I am repeating stuff now that was already said:

  • those jasserts might be added in the future
  • there is no way to make public members private without creating an uproar and the discussions about it are a massive time sink
  • the readability suffers IMHO

But anyway

1 Like

ofc such discussions are a time sink. but you know, i’d much rather discuss this once and for all and then spend the rest of my life enjoying shorter lines of code, than getting into the same stupid situation where i have to write lines like the ones far above every other minute just because some people think setWidth() will ever have a life-changing jassert

here’s an easy fix for you:

#define private public
#include <JuceHeader.h>
2 Likes

ok… hm… yeah i can see how that would solve it. but it seems overkill to me. afterall i do see your arguments FOR getters and setters. i just want it to be more chill for the super simple types that are often used, not that intellisense now shows me every little bit of information that exists

Don’t do that, that’s UB!

A translation unit that uses any part of the standard library may not #define or #undef names lexically identical to keywords. Otherwise, the behavior is undefined.

https://en.cppreference.com/w/cpp/preprocessor/replace

3 Likes

oh obviously, I thought that suggestion was so obviously terrible that it would read as a joke

2 Likes

i know that you meant that as a joke. but i would rather consider such a macro (if it wasn’t UB) than accepting that i have to write “get” all the time when that word really doesn’t do anything for me. just look at juce::Point and juce::ColourGradient if you want to see perfectly fine examples of classes that expose their members and no one ever complains about it. why? because it’s just nice to use these classes. maintainability is not everything in a framework. workflow should be considered too. so rather than thinking “uh, this functionality could have a jassert one day, even though it’s super unlikely” i’d rather think “damn, i’m writing this line 300 times a day. it needs to get shorter, even if just a little bit.”

that’s my last statement for today. going to sleep now. 1am in here

1 Like

:joy:

Had to laugh out loud reading this.

Although I‘m not sure if additional arguments will change anyones mind here, one additional point I‘d like to mention here is debugging. If members are public, the only way to catch the moment where an unexpected value is set is to use a memory breakpoint, which again requires you to break in the debugger after the creation of the instance. On the other hand, if there is s setter I can easially stick a breakpoint there or add a custom jassert to catch a certain unexpected value. The real world experience that this can save you hours tracking down tricky bugs lead to a strong team internal code style decision towards setters and getters nearly everywhere here.

2 Likes

i’m not arguing against that. i know how useful it is to put a breakpoint or assert into a getter. but say i’ve written out getWidth() now for the 100th time without a bug related to it, which is likely for such an easy to understand method, that’s 500 characters too much and that scales even more if you do that everyday. now let’s compare that with my approach. i’d write 100 lines with just “width” and then run into an issue where it would’ve been useful to use the getter instead. well, i can literally just replace that single line of code with the getter for debugging. if i feel like it i can rewrite it back to no-getter later but i still saved 100th of characters in total.

i’m just saying if you keep using getters extensively everyday at some point you’ll have lost full hours of your life to it without a gain, not even in performance like with other annoying keywords like const and noexcept

If typing is such annoying for you, why not just write a custom wrapper?

const auto bounds = SUPERWRAPPER (getLocalBounds().toFloat());
const auto width = bounds.w;
const auto height = bounds.h;
1 Like

is this a joke again? that literally adds another whole object type and its name to it. this whole post is about having to write less for the reasons of making things more easy to use and more readable. your wrapper argument would definitely make me have to write slightly less letters, but at what cost? should i write a wrapper for almost every type now? could other people still read my code then or even want to do that? even if the wrapper had a nice name it would mess with readability.

i mean, fine. if the juce community would rather hold on to some oldschool coding standards in an attempt to prevent any future need to ever look at Rectangle and Line again and have people rewrite their code slightly for 2min in the absolute worst case that is very unlikely, than just making things 100000x faster to write and with even more straight-forward readability from now on and probably forever, ok. it was just an idea.

Maybe the main question to ask here is why you consider shorter code lines better? This is a serious question.

Do I get you right that your point is about working faster because you need to type less? If so, which IDE are you using? In modern code editors with auto completion, this should be absolutely no issue, in fact, just typing width on a juce::Rectangle completes itself to getWidth() in CLion which is what I use, but I also experienced similar behaviour in other modern code editors.

Screen-Recording-2022-03-29-at-09.58.34

In case I missed your point and it’s not about that, then what benefit do you actually see in the few less characters?

2 Likes

thx for asking. autocomplete can only get you so far. sometimes it suggests the right things but often times also not. then you have to take your mouse and select the one you want… or idk, there are probably hotkeys for the keyboard as well but when i try what works i often just end up moving into another line or something like that. visual studio btw. so intellisense is cool and all, but if it can be avoided to need it that’s even better. sometimes the autocompletes don’t even open up at all, for example when you have a bunch of macros and templates in the same file. i suppose my computer is getting a little old. but that shouldn’t stop one from programming, right? so yeah, definitely don’t trust autocomplete to always complete your words and better prepare to type stuff out.

my 2nd argument is readability. when all these “gets” and “()” are gone we can much more clearly see what’s going on.

auto w = bounds.getWidth();

this looks like you are not only getting bounds’ width but also doing some background stuff that requires a full function call.

auto w = bounds.width;

this makes it obvious that all we do is getting the width. more straight-forward, shorter and even less blackboxy. you know what happens or doesn’t happen without having to inspect a function call.

that however enables you to stack more of these things together nicely, like:

Point centre(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);

i wouldn’t ever write this into 1 single line the way it works right now, but like this it’s just beautiful and reasonable.


so recap: my 2 arguments are readability and time it takes to write. i’m not suggesting something like bounds.w, even though i’d personally make it like that if it was my personal framework, but bounds.width is a good trade-off between making it as short as possible and still conveying the full information about what it is

1 Like

It was not a joke. Just a vague idea that, with a properly done template class + a bit of structured binding + a bit of implicit conversion, you cloud make something neat for your use. Doesn’t matter.

2 Likes

thanks for clarifying. i hate when some forum posts get to a point where i can’t be sure anymore if people try to mess with me or still argue about the actual topic! i aknowledge that it would make some things slightly shorter, even if i wouldn’t find it optimal

1 Like

IMHO, make the juce::Rectangle class usable with structured binding could be something good for everybody (encapsulation and typing).

TBH I’m stick for now with C++14 thus i didn’t think a lot about how to. :grin:

feel free to expand your concept in this post. i think we have talked about my ideas a lot already and are repeating ourselves a lot

Just throwing in a third alternative, that I feel is the best of both the public member and getter methods… Use a free function, width() that takes a rectangle and returns its width…

const auto w = width (bounds);
const auto h = height (bounds);

Which reads as “width of bounds”. Better, IMO, than “bounds’s width” or “bounds, get width”.

This has the added bonus of being overloadable, so you could also use it for other objects like components, or paths:

width (bounds);
width (component);
width (path);

//vs...

bounds.getWidth();
component.getWidth();
path.getBounds().getWidth();

And another added bonus that you can then control the return type, meaning you can be consistent with using floats for your geometry. In the last example there, the path’s width would be a float, while the other two are ints. Using the width() function you can make them all consistent.

This approach means you can also ‘add’ functionality to objects that don’t have it built in. For example, I often want to find the centre of a component, but it has no getCentre() method, so I’m forced to write

component.getBounds().toFloat().getCentre();

Whereas I could simply write

centre (component);
3 Likes

ok i like this a lot! only problem is your class can’t have a member called “height” anymore the moment a free func like that starts to exist. idk if that would mess with existing functionality of components.

right! i’d call it widthF then or something. that’s cool!

another concern i have about this new idea: say i input bounds into it only to get the width out… would the compiler be smart enough to realize it doesn’t need to copy x, y, and height for that function call? because i definitely don’t want it to lose performance just for readability and code length