Is there a better way to comment on the direction of the parameters in the code?

I want to improve code readability. Therefore, I commented on the direction of the parameter in the code as follows:

#define IN #define OUT void Add(IN int Para1, IN int Para2, OUT int& Result); 

But I think that the compiler will replace each instance of IN and OUT with an empty one, and this can be quite a problem several times.

So is there a better way? Thanks.

(I am using C ++.)

+4
source share
8 answers

Yes: Forget about these things and use them. This will work until you have the "in" and "out" parameters, which are rarely used and should be used.

 void foo(int i, const std::string& s, std::vector<char>& out_buf); // i and s are obviously "in" variables, while out_buf could be both, // but you can easily show that by giving the parameter a proper name. 

Edit: And constant correctness does not mean that the parameter values ​​are const! This does not give the caller any additional information, since you cannot change your variables in any way.

+6
source

You can try to put it in the comments. It is much better and readable.

 void Add(/*IN*/ int Para1, /*IN*/ int Para2, /*OUT*/ int& Result); 
+8
source

I can come up with two simple ways to do this.

one.

  /*Description : Function for adding the two variables. * Returns : Nothing * Parameters : Para1 and Para2 are **IN** parameter and * Result is an **OUT** parameter * @author : <put ur name here> */ void Add(IN int Para1, IN int Para2, OUT int& Result); 

In addition to this basic information, you can also store information such as version number, creation date, etc.

2. You can also insert parameter type information with the variable name ie inPara1, inPara2 and outResult. eg

  void Add(int inPara1,int inPara2,int& outResult); 

one more thing that I would recommend using the letters of the camel body for the variable name and function ie Parameter 1 may be like para1, etc., this will help you in the future.

+3
source

You can make the variables "IN" const , implying that they will never be changed, therefore they should be variables for input only. A link without const can also mean that it will be modified, so there must be a variable called "OUT". But in fact, just after a good agreement on variable names should be enough. Calling the "Result" parameter means that it will be the variable "OUT" itself.

EDIT: As others have rightly said, passing ints as const vars is probably not a good idea. However, you should be able to conclude whether the variable is output or not by the fact that they should always be references (or pointers). By making links that are const const values, this means that all links that are not const must be output values.

+1
source

I'm using something like this

 void Add( /* input parameters */ int Para1, int Para2, /* output parameters */ int& Result ); 

This makes it easy to add new parameters to the function, since you do not need to mark each of them with input or output , they can just skip to the corresponding section.

+1
source

Given that this is a stylistic question, it will provoke some subjective answers, including mine .:-)

There are procedural languages ​​that require that function parameters be defined as input or output. In C ++, this is largely undesirable.

The general thinking that a modern C ++ developer should have is one that focuses more on mutable vs. immutable, as well as on interfaces over raw types and data.

When we look at such a function:

 void f(int x); 

... a C ++ developer can immediately tell you that "x" is used for input. What for? This is passed by value. It is not possible to change the "x" so that it affects the caller, and therefore, any argument passed to this function will not be changed.

This also applies to any constant reference:

 void f(const Foo& read_only_foo); 

The above is certainly a strict input parameter. When we look at such a function:

 void f(int& x); 

We can generally assume that f is going to change x (it is not guaranteed, but knowing that f should eliminate any doubts).

With custom types, it gets a little more foggy.

 ostream& operator<<(ostream& os, const Foo& foo); 

Here we know for sure that "foo" is an input parameter since it is immutable. But what about os? Is this an output parameter, input, both? In strict procedural languages, the output parameter usually implies that the parameter will be changed, but we also read it here, so it will be both. Although we will call methods in "os" that affect its state, this is not quite the way we think of the output parameter in procedural languages ​​that support in / out parameters initially.

The fact is that this strict way of input / output of thinking about parameters can be completely confused with these types of high-level interfaces and object-oriented design. A more useful way to look at things here, as a rule, is whether the object that implements the interface is mutable or immutable. Here "os" is mutable. A function usually says that it will call some functions that change its state.

How about this?

 // fills the specified list with stuff void some_list(list<int>& out_list); 

Here he tends to go, perhaps more naturally, with the semantics that we expect from the output parameter. Something like filling a list, we tend to think of it more intuitively, as a function that displays the result through a list. I even prefixed the name 'out' to emphasize this. But in reality, and especially with C ++ 11, we should not write such things as Straustup emphasizes:

 // returns a new list filled with stuff list<int> some_list(); 

This actually leaves very few places left where the in / out difference can probably be very useful at all (and not redundant with the means already provided for specifying the parameters as mutable / unchanged by value, reference, pointer, or r-value).

Combined with clear documentation of what the function does, there is generally no ambiguity about how it works with its parameters, so the inclusion / withdrawal agreements tend to do very little, but add a lot of extra code and can help more oriented thinking about data from which you should try to get away.

In general, I suggest trying to avoid this agreement. Even if there are good arguments in favor of this, it’s just not what people tend to do in C ++. And if you want people to enjoy working with your code and not get upset, you need to learn to go against what the general public usually understands. Everything that is too exotic scares people.

If you are absolutely, fanatically attached to designating everything as inbound or outbound, I recommend a minimally intrusive solution, such as a documentation style or naming convention. Definitely avoid macros that do nothing. This will require your readers to check every time these macros really do nothing. A naming convention or style of documentation does not require such verification.

Finally, a small quote from the creator of C ++ itself:

First rule about macros: Do not use them unless you need to. Almost every macro demonstrates a flaw in a programming language, program, or programmer. - Bjarne Straustrup

+1
source

There are two sides: function signature and call site. You are focused on signatures, so I will address this first. Notes:

  • const ness binds and provides potential changes to a function
  • Having consistent API conventions for the library can help programmers of the library and client code, for example:
    • Returning output (which may mean the need to use a tuple, container, or custom structure) while maintaining the functional parameters for the inputs.
    • Denotes something about a function through identifiers and parameter order; personally, if I write a function that can change a parameter, I tend to call this function loadXXX () and output the result first. Other libraries I've seen output output sequentially. This is an arbitrary choice, but consistency helps. Similarly, you can name the output parameters differently ....
  • Comments / Documentation

On the client’s call site, when passing a non-constant argument, it is not clear what might happen to him.

  • Again, the loadXXX conventions mentioned above, group outputs first / last and prefer-to- return -output (s) - getXXX also help the client.
  • Passing output parameters by pointer is a time-tested but controversial practice that IMO is not particularly popular with modern professional C ++ programmers, but can read and add real value well. C ++ FAQs address most issues, but come to different conclusions than I do.
  • You can distinguish const parameters to const for communication on the call site so that they are not changed, but it is verbose and tedious, and practice cannot be enforced by the compiler (the compiler will prevent the function called that changes these parameters, but will not force the caller to provide the parameter which the function accepts as const to explicitly pass it to const ).

Some of these things can be “forced” with proxy objects, but it will make your code almost unreadable and heavy.

0
source

Use the correct language constructs, not artifacts.

Using IN and OUT does not guarantee that they are truly IN and OUT. This is similar to the Hungarian notation, which calls WPARAM something that was word , and today it is long .

  • pass by value ( int ) is an IN that you can change
  • pass by const ref ( const int& ) is an IN that behaves like a constant in a function
  • pass by reference ( int& ) - this is OUT, which should be there
  • pass pointer const ( const int* ) - this is IN, which also cannot be specified (null pointer)
  • pass pointer ( int* ) - this is OUT, which may also not be specified (null pointer)

The advantage of using the correct language construct is that improper use will lead to a compilation error (so you have to fix the problem), while IN and OUT will never cause any errors in the code, and you risk submitting a formal agreement on that after a certain number of service releases can even be on its own.

0
source

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


All Articles