⬆️ ⬇️

Method chaining

In this post I will talk about a simple but sometimes useful programming technique - method chaining. I will also tell you about the potential pitfall associated with its use.



Test



To make it more interesting, first a small test.



1. What is method chaining? The essence of this reception?

')

2. How is it implemented in C ++?



3. Can you think of a potentially dangerous situation associated with the use of this technique?



Theory



Sometimes, when using or writing large classes, it becomes necessary to call several methods of an object of this class in a row. Usually it looks like this:



class worker { public: void set_data(const data_t& d); void process(); void send_result(); void print_log(); ... }; void foo() { worker w; w.set_data(data_t{}); w.process(); w.send_result(); w.print_log(); ... } 




Receiving method chaining allows you to reduce this code. To do this, in each of our methods we will return a link to our object and line up calls in a chain.



 class worker { public: worker& set_data(const data_t& d){...; return *this;} worker& process(){...; return *this;} worker& send_result(){...; return *this;} worker& print_log(){...; return *this;} ... }; void foo() { worker w; w.set_data(data_t{}).process().send_result().print_log(); ... } 


As far as I know, this technique is loved in Java. In C ++, it is not particularly popular, and I do not in any way urge to use it, but I think it will not hurt to know about it.



Underwater rock



Strictly speaking, what I describe below refers not so much to method chaining, as to the order of calculating arguments and function calls, but nevertheless, using the “chain of calls”, these rules may work unexpectedly at first glance. So.



 struct worker { worker& process(int& i) { i = 185; return *this; } worker& print_result(const int& i) { std::cout <<"result: "<< i << std::endl; return *this; } }; int main() { int data = 0; worker w; w.process(data).print_result(data+2); } 


This code will compile without warning or error. But the execution results may differ on different compilers.

The fact is that although the standard guarantees that process () will be called before print_result (), it is not guaranteed that the argument of the print_result function will be evaluated after the execution of process (). Accordingly, sometimes as a result of the execution of this code, “2” can be displayed.

Source: https://habr.com/ru/post/215059/



All Articles