What happened to a little Johnny

Fasten your seatbelts boys and girls because we're about to tackle one of the nastiest boilerplates in C++ - the polymorphic exposure functions.

So, the story goes like that. Little Johnny decided to make a class one day.

struct MyIntCollection {
    std::vector<int> _col;

    void printMyInts() const {
        for (auto i: _col) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    }
};

And the class was simple and unspoiled. Johny was smiling and blasting away!

MyIntCollection c;
c._c.push_back(1);
c._c.push_back(7);

// and the Johnny said:
// "So little code and I'm so happy!"
c.printMyInts();

Some time later a big bad wolf came (with some managers) and said “Hey, little Johny, I heard you wrote a simple class. After all, we're dealing with C++, don't you think that having a simple class in C++ is a little too good for you?”

And Johnny said “What's wrong with my class? It's so simple and beautiful!”
And the wolf said “So, you think you can get away with publicly exposed data members? PUT A PRIVATE AROUND THAT VECTOR OR I'LL EAT YOU AND YOUR WHOLE FAMILY”

After hearing that Johnny was a little upset.

So, having no choice Johnny had to add a private qualifier above his vector.

struct MyIntCollection {
    void printMyInts() const {
        for (auto i: _col) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    }
private:
    std::vector<int> _col;
};

And little Johnny realized, he couldn't just simply add ints to the vector no more! So, little Johnny added a method that adds an int to his vector.

struct MyIntCollection {
    ...
    void addInt(int i) {
        _c.push_back(i);
    }
    ...
};

Little Johnny was in somewhat better mood now as he can still add ints to his class and call the same printMyInts method as earlier.

Some time later the big bad wolf came back and said:
“So, I see you're having fun adding ints to your class and all?”
“Yeah, it's so nice and shiny! I'm so happy today!”
“I want capability to remove ints from your class.”
“But… I just put vector under private and…”
“ADD CAPABILITY TO REMOVE THEM YOU LITTLE %$@#!#@”

And little Johnny started crying. As all the exposure of the vector he had initially was encapsulated he had to add a new method for removal of ints from the vector. And Johnny stumbled upon questions, should I remove by index? Should I remove the value that exists in the vector? Should I expose iterators of a vector? What if internal storage for ints changes?

So little Johnny added integer removal capabilities but the big bad wolf came back for more:
“I want to traverse your ints!”
“I want random access to your ints!”
“I want size of your ints!”
“I want to know if int exists in the vector!”

And little Johnny kept adding methods in his class and it grew 7 times bigger that when he started with when the vector was naked.

Little Johnny was very upset because he was adding functionality that was exposed in the initial vector anyway. So little Johnny cried out because as soon as he made the Wolf's request he came back for more.

And angel landed from the sky, he saw little Johnny crying and said:
“Why are you crying?”
“The big bad wolf comes and makes requests to expose a collection that had the initial functionality anyway! I'm doing nothing but replicating what vector does!”
and the angel said: “Don't cry, here, I have a cd with templatious headers. Take that thine is and go thy way.”

And little Johnny was a little happier. He opened his laptop and he saw an interesting function in templatious library, it was called “StaticFactory::vcollection”. Little Johnny has read some documentation. He saw that he could expose entire collection, regardless of it's type across translation units through a single generic collection interface - VCollection.

struct MyIntCollection {
    templatious::VCollection<int> exposeInts() {
        return SF::vcollection(_col);
    }

private:
    std::vector<int> _col;
};

And the returned collection also obeyed generic CollectionAdapter interface so it could be used with many generic templatious functions for easy manipulation.

MyIntCollection c;
auto handle = c.exposeInts();

SA::add(handle,1,2,3,4,5,6,7);
TEMPLATIOUS_FOREACH(auto i,handle) {
    std::cout << i << std::endl;
}
SA::erase(handle,SA::begin(handle),SA::end(handle));

And little Johnny was happy again. Now he could expose his collection for the world with a single function call!

The big bad wolf came back and saw little Johnny smiling. The big bad wolf didn't want anyone to smile.

Big bad wolf said:
“What's the deal? Aren't you supposed to be debugging all the errors you made and mutable state you introduced into your class?”
Little Johnny said:
“I just exposed my collection with a single function call. How awesome is that?”
“So, you just exposed all the state of collection for anyone to fiddle with it how they want? Don't you think it sort of defeats the objective that internals should be private? I want the collection to be addable only.”

And little Johnny started crying again. He saw only one option - satisfy the demands of the wolf by going back to what was obvious - just write the function of addition thereby repeating code just to expose some parts of collection.

And the angel saw little Johnny crying and appeared to him and said:
“Why is it that thou criest?”
“I exposed the collection and the big bad wolf came and said it was too much. Now I'll need to resort to just exposing the parts that I need. And the big bad wolf will come and ask me to expose more internals and then it might break stuff and then I'll have to fix that and then he'll ask more changes! I'm so troubled and helpless!”
And the angel said: “Oh ye of little faith… Hath ye not read the documentation?”
And the angel disappeared.

And little Johnny took the advice and he looked for more in templatious library. He found an interesting function - StaticFactory::vcollectionCustom. Turns out, it gives flexibility to expose as much collection as you want when creating VCollection!

So, little Johnny used this function to fulfil wolf's request:

struct MyIntCollection {
    templatious::VCollection<int> exposeInts() {
        return SF::vcollectionCustom<
            templatious::AP_ENABLED,
            templatious::CP_THROW,
            templatious::TP_THROW,
            templatious::ACP_THROW,
            templatious::SP_THROW
        >(_col);
    }

private:
    std::vector<int> _col;
};

Now, if someone tried to do anything besides adding to collection, it would throw an exception. However, little Johnny had a lot more flexibility. He could fake addition, user could try to add but there would be no effect. We could fake clearance of collection, user might try to clear but there would be no effect.

So, in short, little Johnny could expose 162 combinations of the same vector to suit arbitrary needs. Little Johnny could then use functions that take in VCollection and rest assured that collection is only traversable, only addable, only erasable and so on.

And the big bad wolf came back and he saw that little Johnny was smiling again like never before. And he started firing demands at little Johnny hoping he would fail at the amount of work given to him.

Wolf asked little Johhny:

  • To only allow traversals to collection
    return SF::vcollectionCustom<
        templatious::AP_THROW,
        templatious::CP_THROW,
        templatious::TP_ENABLED,
        templatious::ACP_THROW,
        templatious::SP_THROW
    >(_col);
    
  • To only allow random access of collection
    return SF::vcollectionCustom<
        templatious::AP_THROW,
        templatious::CP_THROW,
        templatious::TP_THROW,
        templatious::ACP_ENABLED,
        templatious::SP_THROW
    >(_col);
    
  • Allow addition and removal from collection
    return SF::vcollectionCustom<
        templatious::AP_ENABLED,
        templatious::CP_ENABLED,
        templatious::TP_THROW,
        templatious::ACP_THROW,
        templatious::SP_THROW
    >(_col);
    
  • Allow addition and fake removal
    return SF::vcollectionCustom<
        templatious::AP_ENABLED,
        templatious::CP_FAKE,
        templatious::TP_THROW,
        templatious::ACP_THROW,
        templatious::SP_THROW
    >(_col);
    
  • Only allow finding out about collection size by elements
    return SF::vcollectionCustom<
        templatious::AP_THROW,
        templatious::CP_THROW,
        templatious::TP_THROW,
        templatious::ACP_THROW,
        templatious::SP_ENABLED
    >(_col);
    

And little Johnny could fulfil big bad wolf's requirements in seconds after he had asked them.

Big bad wolf didn't expect little Johnny to fulfil those that easily. However, big bad wolf had the final request which he thought will bring little Johnny down his knees.

Big bad wolf said:
“Not bad… Now I want your collection to be concurrent. I want read only exposure which could be shared among multiple threads at the same time but also be able to modify it any time I want and everything has to be synchronized.”

Little Johnny was done in 5 minutes. Little Johnny used a special vcollection function which allowed him to attach code to be executed upon destruction of the handle. So he made one read only handle and one write only handle, used boost::shared_mutex and everything just worked.

struct MyIntCollection {
    // This pattern is copied from safe
    // memory model of rust.

    auto readOnlyHandle() const
     -> templatious::VCollection< const int >
    {
        // shared lock for read only access
        _l.lock_shared();
        // expose read only interface
        return SF::vcollectionCustomWDtor<
            templatious::AP_THROW,
            templatious::CP_THROW,
            templatious::TP_ENABLED,
            templatious::ACP_ENABLED,
            templatious::SP_ENABLED
        >(_c,
             [&]() {
                 // unlock shared lock in destructor
                 _l.unlock_shared();
             }
        );
    }

    auto writeHandle()
     -> templatious::VCollection< int >
    {
        // exclusive lock for write handle
        _l.lock();
        // expose everything for write handle
        return SF::vcollectionWDtor(_c,
            [&]() {
                // unlock exclusive lock in destructor
                _l.unlock();
            }
        );
    }

private:
    boost::shared_mutex _l;
    std::vector<int> _c;
};

And the big bad wolf started screaming and cursing as he was so angry that he bacame huge with red eyes, he looked at Johnny and he said:
“I will destroy you”.
But the hand from heaven appeared and took the big bad wolf (with some managers) and cast him into the lake of fire where he was tormented forever and ever.

And from that day onward little Johnny was called a John.