Live data from Hacker News

C++ Patterns: The Badge

awesomekling.github.io

21–30 of 160 posts

Re: C++ Patterns: The Badge

#21
post #7

I like it but is access restriction really a problem? In my years of C++ programming it always seemed to be a theoretical problem more than something that leads to crashes.

This pattern is defensive by nature so people who use your library in the future will be less prone to making mistakes. Also, it shows intent to protect that asset clearly which generally leads to easier maintainability. If someone sees this guys code, they will definitely ask questions about why he is doing it, and if they are competent, they can draw the same conclusions that his blog leads you to without having to read the blog.

Re: C++ Patterns: The Badge

#22
I like it! The self-documentation of where the call is coming-from is quite nice (though a more descriptive name like CallFrom would make that even clearer, were it the principle intent). I can't help myself, though:

    template
    Badge FakeBadge() {
      struct Stub {}
      return reinterpret_cast>(Stub());
    }

Re: C++ Patterns: The Badge

#23

I do C++ for almost 20 years but never came across this simple technique before, so I'm quite surprised that I actually like it. I usually avoid 'friend' in these situations and just write //private: before the method declaration. But it actually happened that co-workers used these private methods because they use code-completion instead of reading the header... But I might would call the class Friend or something.

> But it actually happened that co-workers used these private methods because they use code-completion instead of reading the header...

A nice feature I've noticed in Elixir is that giving a function a "@doc false" annotation will actually prevent IDE/REPL autocomplete from completing the function. (It's still there to call if you type it yourself.) Maybe that's something C++ tooling could copy.

Re: C++ Patterns: The Badge

#24
post #7

I like it but is access restriction really a problem? In my years of C++ programming it always seemed to be a theoretical problem more than something that leads to crashes.

This solves a chronic architectural maintenance problem in complex C++ code bases, which I've also run into countless times. Any visible interface, public or private (via friend), will eventually be used by other programmers for other than its intended use case simply because it is there and accessible. For the maintainer of an interface with a single intended purpose, what should be a clean, tidy modification within…

There's a name for this phenomena: Hyrum's Law.

> With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.

http://www.hyrumslaw.com/

Re: C++ Patterns: The Badge

#25

I like it! The self-documentation of where the call is coming-from is quite nice (though a more descriptive name like CallFrom would make that even clearer, were it the principle intent). I can't help myself, though: template Badge FakeBadge() { struct Stub {} return reinterpret_cast >(Stub()); }

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:

  badge.cc: In instantiation of ‘Badge FakeBadge() [with T = Device]’:
  badge.cc:25:38:   required from here
  badge.cc:10:10: error: invalid cast from type ‘FakeBadge() [with T = Device]::Stub’ to type ‘Badge’
     return reinterpret_cast>(Stub());
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A reinterpret_cast won't turn an instance of the Stub local class into a Badge.

That doesn't even have to do with friendship/protection. If we move that line into the Device class, the reinterpret_cast still doesn't compile.

Re: C++ Patterns: The Badge

#26
post #7

I like it but is access restriction really a problem? In my years of C++ programming it always seemed to be a theoretical problem more than something that leads to crashes.

This solves a chronic architectural maintenance problem in complex C++ code bases, which I've also run into countless times. Any visible interface, public or private (via friend), will eventually be used by other programmers for other than its intended use case simply because it is there and accessible. For the maintainer of an interface with a single intended purpose, what should be a clean, tidy modification within…

> 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.

Re: C++ Patterns: The Badge

#27

I like it! The self-documentation of where the call is coming-from is quite nice (though a more descriptive name like CallFrom would make that even clearer, were it the principle intent). I can't help myself, though: template Badge FakeBadge() { struct Stub {} return reinterpret_cast >(Stub()); }

That's not a legal C++ cast, but it's conceivable that it could be made to work by casting to a reference type instead.

Re: C++ Patterns: The Badge

#30

Could you make the badge the last argument and give it a default value, so you don't need the initialization at the function call? It looks a bit strange and would need an explanation for why the empty initialization list is there IMO. I'm not sure if it would work, cppreference has this to say about default arguments: > The names used in the default arguments are looked up, checked for accessibility, and bound at th…

It's an empty struct so the compiler will elide any storage either way, but agreed having it be the first arg is a bit odd. Perhaps it's for regularity in the cases where you want to make variadic functions 'badged' in this way.
Post reply on HN