Passing an argument to a function

Is it a bad programming principle to pass arg to a function that is not an “exact match” but has a trivial or user-defined conversion to this type? For instance:

void f(bool option); 

and then basically (this is very hypothetical, so please do not report this code):

 int a = getSomeValue(); f(a);//here instead of bool I'm passing int - is it a bad programming practice or not? 
+4
source share
6 answers

It all depends on the context.

In this very specific situation, when you host a site in your question. I prefer an explicit test rather than an implicit conversion of 0 to false (But this is also because variable names and functions are so meaningless if they were named differently than I can not mind).

But there are other situations: an implicit conversion is in order:

 std::ifstream f("File"); if (f) { // Testing f is relatively standard. } 

Whenever there is a loss of information. I would expect an explicit cast with a comment explaining why the loss of information is in order.

 long theDistanceToLodond = getDistance("ToLondon"); InsideM25Action(static_cast<short>(theDistanceToLondon)); // All distances inside the M25 fit in a short therefore no information loss. 

But castings in which no information is lost should not have an explicit cast (it overflows the code without providing any advantages). I would not expect explicit casts of pointers to a base class, etc.

+1
source

I think most people will consider this bad practice. The spelling f(a !=0) much clearer and succinct.

+6
source

Converting to bool is a special case, because it does not behave like whole conversions, so many people like to see it explicitly and can be done using != 0 rather than cast.

If you pass an int function that accepts long , then of course I don't want to see this cluttered by any explicit conversion. Similarly, I would not want to see char* cast to const char* to pass it to strlen . These transformations "actually do nothing": they always save the value of the input, and in the case of a pointer, it does not allow you to do anything with a link that you could not do using the original pointer.

If you pass an unsigned long function that accepts an unsigned int , then on some implementations (but by no means on all common ones), this is a "narrowing of the conversion", which, depending on the values, can discard information by taking a module. It is often a good idea to make the conversion explicit in such cases, so the casual reader does not need to check the signature of the function to understand that this is happening. These transformations do something, which may be surprising.

The same thing happens when converting integer and floating types: although int -> double is harmless for almost any implementation you have ever seen, double -> int has undefined behavior for some values, so you don't want the reader to skip his.

Sometimes, however, fairly complex custom conversions are provided so that you can call the function and take advantage of the implicit conversion. Thus, for them, you should probably follow the usage examples in any API that defines the transformation.

For example, if Foo has an implicit constructor that accepts std::string , and some bar function accepts Foo , which is not much different from the caller’s POV bar than if the API provided only an explicit conversion, but two bar overloads, one took Foo and one , which takes std::string , but converts it directly to Foo and calls another. Therefore, relying on conversion in this case is no worse than function overloading. The latter is not considered a crime of the century. Except for Python programs.

+6
source

Yes, I think this is a bad programming practice.

Using implicit conversions can lead to very strange errors. I once had the following problem. It all started with this function:

 void doSomething (ClassX x, ClassY y, bool b); 

This function is called with code like this:

 ClassX x; ClassY y; doSomething (x, y, true); 

Someone later decided that the arguments to doSomething should be changed, since doSomething now also required an instance of ClassZ. In addition, in many cases the boolean argument was true, so it was changed to the default argument, for example:

 void doSomething (ClassX x, ClassY y, ClassZ z, bool b=true); 

Although most of the code was changed, the call shown earlier was not changed. Oddly enough, ClassZ had an implicit constructor that takes bool as an argument:

 class ClassZ { public: ClassZ(bool b); }; 

The following happened. This call:

 ClassX x; ClassY y; doSomething (x, y, true); 

Suddenly transformed into a compiler:

 ClassX x; ClassY y; doSomething (x, y, ClassZ(true), true); 

With the 4th argument being the default.

Over the years, we found out that something did not work correctly, and after a lot of debugging, we found out that the reason for this was the reason for this call.

In this way:

  • never rely on implicit conversions
  • label constructors with 1 argument as explicit
  • try to avoid using default arguments
+2
source

If you pass the short variable to f(int) then this will be fine. But the opposite is dangerous (from int to short - possible overflow! ), And most compilers would not be happy, and that would give you warnings.

As for f(bool) , yes, the intention is more clear when you write f(a!=0) when calling f . Here we do it for readability, and not just to pass a like f(a) .

+1
source

Since you are using C ++, you should have done:

  int a = getSomeValue(); f(static_cast<bool>(a)); 

This undoubtedly expresses what you intend, so we have many types of explicit throws.

0
source

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


All Articles