C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Impose friendship when needed

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Sun, 17 Jul 2022 22:07:31 +0100
On Sun, Jul 17, 2022 at 7:36 PM Robert A.H. Leahy wrote:
>
> Being able to "impose friendship" would create a maintenance nightmare for everyone who writes libraries.


No, it wouldn't. A simple disclaimer:

    "The behaviour of this library is undefined if you impose friendship".

But of course: The use of imposed friendship is evidence that you're
using the 3rd party library in a way in which it wasn't intended to be
used -- so the disclaimer is implicit. Perhaps there could even be a
compiler diagnostic to the effect of:

main.cpp:27:5: warning: member object 'monkey' is marked 'private' in class,
                        but imposed friendship violates interface
27 | obj.monkey = 5;
   | ^~~~~~~~~~~~~~

If I were to write my own library -- for example a 3D graphics library
-- and release it to the public domain, I wouldn't be particularly
worried about how my library will behave when Tom, Dick or Harry edits
my header files. I'm not going to accommodate people editing my header
files, and I'm not going to accommodate imposed friendships.


> Not only would the publicly-visible surface of the library need to be maintained but the internals couldn't
> change because any consumer of the library could have "imposed friendship" and now be depending on the
> precise inner workings of the class. It's the ABI compatibility nightmare except arguably worse.


I propose that one of the requirements for compilers implementing
imposed friendship is that it doesn't change the ABI -- and so other
source files in the project _don't_ need to be recompiled.

What I'm proposing is better than editing the 3rd party header file in
order to change:

    class RS232_Link {
        int monkey;
    };

into:

    class RS232_Link {
        int monkey;
        friend class Friend_RS232_link;
    };

and then writing in your own source file:

    struct Friend_RS232_Link {
        int &monkey;
        Friend_RS232_Link(RS232_Link &arg) : monkey(arg.monkey) {}
    };

    int main(void)
    {
        RS232_Link obj;

        Friend_RS232_Link(obj).monkey = 5;
    }

Obviously we shouldn't use a 3rd party library in ways they weren't
intended to be used -- the author of the library marked a particular
method as 'private' for a good reason -- but we live in the real world
where sometimes it makes sense not to follow a rule or not to follow a
convention. In the few corner cases in which we should violate good
programming practise, it would be much cleaner to simply do this:

    friend<monkey>.obj = 5;

instead of going editing the 3rd party header files. Leaving the 3rd
party header files intact means we don't need to go editing them every
time a new version of the 3rd party library is released.

Received on 2022-07-17 21:07:42