Live data from Hacker News

C++ Patterns: The Badge

awesomekling.github.io

111–120 of 160 posts

Re: C++ Patterns: The Badge

#111
post #95

Earlier quoted context omitted.

Everything public versions poorly when you can't update all clients of your code after you change your implementation. It increases coupling in ways you can't control. It also doesn't work very well with code completion - implementation methods get mixed up with surface API - and usability by third parties suffers. If you're on a team of one, and you own the project for its whole lifetime, then you're fine.

The implicit contract is that anybody who uses m_ "intended to be private" members is responsible for fixing breakage.

I’d rather have no breakages over a breakage that’s somebody else’s fault

Re: C++ Patterns: The Badge

#112

Earlier quoted context omitted.

> I started doing everything all-public ala python (struct instead of class by default) with occasionally an m_ prefix for "intended to be private", and I've never looked back. This is the sort of accidental complexity that access specifiers eliminated, but somehow you managed to reintroduce by trying to reinvent the wheel. The 'm_' prefix only means "private member variable, don'access it" to you and you alone, and…

Python has a well-established convention of _underscore for intended-to-be-private members, with no enforcement, and it works fine. Just document your conventions. The horrors of some other programmer using it wrong seem overblown to me. In my IDE in c++ I can quickly refactor m_ to non-m to make it "semantically public" without having to edit header files, change struct packing order / ABI, etc. And most of the time…

> Python has a well-established convention of _underscore for intended-to-be-private members, with no enforcement, and it works fine.

Python does not have access modifiers. C++ does. It makes absolutely no sense to write Python code in C++ while entirely oblivious to basic, age-old C++ features just because your background lies somewhere else and you failed or refused to learn even the basics.

And you know what actually works instead of just "working fine"? Having the compiler throw an error if a careless programmer tries to access private variables.

> In my IDE in c++ I can quickly refactor m_ to non-m to make it "semantically public" without having to edit header files, change struct packing order / ABI, etc.

Don't you understand that's completely irrelevant? Just set the private member as private and it does not matter at all which naming convention you follow. Don't you understand that having to do nothing is better than expecting team members to be prescient about your convoluted and absurd naming convention used to avoid best practices?

> Besides, in c++ people can always cast your intricately-protected object to a void pointer and start manipulating it nefarioisly anyway.

Don't you understand that't entirely irrelevant? You're trying to argue that it's ok to ignore best practices such as using member access specifyers, which actually get the compiler to validate the code, if you stick with naming conventions, but arguing that it's technically possible to circumvent compiler checks under some specific circumstances is an absurd statement. Think about it: if you feel that enforcing a coding style is enough to enforce private member access then don't you agree that the same code review that is supposed to enforce your personal style can quite easily catch your hypothetical casts?

Re: C++ Patterns: The Badge

#113

Earlier quoted context omitted.

> I also would guess that the compiler elides the Badge argument since it is never used. It's also zero width, so no temporaries, etc.

Problem is, nothing elides the presence of these obtrusive badge parameters in the source code . A few bytes of stack is the least of my concerns on some file system device registration function that is called five times when the system boots. If we imagine a software organization "going to town" with this badge approach so that there are badges all over the code base, it's not hard to imagine how it would be a nuisa…

Depending on how you approach it (eg if you don’t instantiate it as {} but instead something like access::device, which is a type alias for Badge) then I find being explicit about access rights is quite helpful sometimes. In this case, I probably would avoid it too in favour of private headers, but then, I prefer freestanding namespaces functions over objects when possible anyway (too much functional programming maybe), so I’d partition my API that way instead.

Re: C++ Patterns: The Badge

#114

I used to carefully design my C++ code with public / private / protected / friend (and the pointer-to-impl pattern for "compile time private") but a few years ago I started doing everything all-public ala python (struct instead of class by default) with occasionally an m_ prefix for "intended to be private", and I've never looked back. It's been great, made my programming life much easier. This badge thing is clever,…

> OOP also; I've seen so many crazy class architectures that could just be a handful of plain-old-functions, also, tons of "generic" numerical code with templates everywhere, where the only two possible instantiations are "float" and "double". Some people do really like to add useless complexity everywhere.

Not only is it needlessly complex, but untested generic code is a minefield of subtle future bugs ... "oh, the function is there and tested, so it should work" ... well, not in this particular combination of the completely unrestricted generic parameter set.

Re: C++ Patterns: The Badge

#115
post #76
post #47

While this is a clever little pattern, I'd argue that if you have a method of class X that can only be called from class Y, that is a code smell.

Sometimes, clever little patterns like that are useful to get stuff done in time. However, it that case it definitely smells a lot. Also, the global singleton stinks. To me this is a violation of the Interface Segregation Principle. I think the author went the right way to fix it, but not far enough. He added a parameter to segregate the device registration operations from other operations. It works, but the segregat…

Is an object really a god object if lots of people use it? I thought it was the opposite way around: a large object that contains too much functionality, but this device could be a tiny single purpose object for all we know, that a lot of clients need to use.

Re: C++ Patterns: The Badge

#116

Earlier quoted context omitted.

And you can add yourself a public interface even if all you have is a compiled library, and header files. Flipping a "private:" to "public:" has no effect on the binary compatibility.

> Flipping a "private:" to "public:" has no effect on the binary compatibility. That's not the case on Windows. The access qualifier is part of the mangled name. https://en.wikiversity.org/wiki/Visual_C%2B%2B_name_mangling...

It's still an honor system. There's a way to generate code that will call the "private" or "protected" data/function even if it violates what's specified in the headers.

Re: C++ Patterns: The Badge

#117
post #92
post #60

Earlier quoted context omitted.

yeah, python LOC > 5000 try to debugging it while some dude just modified your type instance's guts.

OP's approach works if all dudes involved read the code before chaning it and stay off private parts even if they aren't guarded by the language constructs.

That's not how software development works in e.g. companies where multiple people use the software (framework, libraries, API's) at different levels/roles.

For example, if we develop some framework to be used at multiple sites in the company, we can be 100% sure that at some point someone will assume that anything marked 'public' in the API is fair game to use (which IMO is a reasonable perspective). If they start using internal API's or depend on class internals that are only public just because the language did not provide us with a reasonable way to hide them, at some point we will change them and working systems could break elsewhere. In a similar fashion, misuse of private API's by violating preconditions that are completely opaque to users of your (intended) public API can lead to the worst kinds of bugs and unpredictable runtime failures.

Software development always seems so simple and pragmatic if you don't need to care about other people you have no control over.

Re: C++ Patterns: The Badge

#118
post #92
post #60

Earlier quoted context omitted.

yeah, python LOC > 5000 try to debugging it while some dude just modified your type instance's guts.

OP's approach works if all dudes involved read the code before chaning it and stay off private parts even if they aren't guarded by the language constructs.

>if all dudes involved read the code before chaning it

And that's only ever possible if you're the only "dude", and your codebase is like <10k loc

Re: C++ Patterns: The Badge

#119
post #45

This is a typical example of a solution to an artificial, self-imposed problem created by C++'s assumptions. As a programmer, I would feel frustrated to have to figure this out instead of spending time on something a user would actually care about.

I’m sure you’re very familiar with the patterns used in the codebase(s) you spend your time in.

In this case, once you know what a Badge is, it’s obvious what it communicates about a function that takes one.

Re: C++ Patterns: The Badge

#120

Earlier quoted context omitted.

Doesn't subvert Device badges for me. Complete sample: template class Badge { friend T; Badge() {} }; template Badge FakeBadge() { struct Stub {}; return reinterpret_cast >(Stub()); }; class Device { public: static Badge getBadge() { return Badge (); } }; void needDeviceBadge(Badge badge) { } int main() { needDeviceBadge(Device::getBadge()); // no error needDeviceBadge(FakeBadge ()); // error! return 0; } g++ errors:…

It does, however, work fine if you use a proper "* (Badge * )&stub" cast.

Isn't casting unrelated types undefined behavior?
Post reply on HN