2

I was wondering if it is good practice to use the member operator . like this:

someVector = (segment.getFirst() - segment.getSecond()).normalize().normalCCW();

Just made that to show the two different things I was wondering, namely if using (expressions).member/function() and foo.getBar().getmoreBar() were in keeping with the spirit of readability and maintainability. In all the c++ code and books I learned from, I've never seen it used in this way, yet its intoxicatingly easy to use it as such. Don't want to develop any bad habits though.

Probably more (or less) important than that, I was also wondering if there would be any performance gains/losses by using it in this fashion, or unforeseen pitfalls that would introduce bugs into the program.

Thank you in advance!

Rod
  • 52,748
  • 3
  • 38
  • 55
Anne Quinn
  • 12,609
  • 8
  • 54
  • 101
  • `var` is an expression on its own. `var.member` doubly so. So by this logic... –  Feb 21 '11 at 19:09
  • See this related topic : [Is this code well-defined?](http://stackoverflow.com/questions/4709727/is-this-code-well-defined) – Nawaz Feb 21 '11 at 19:18

8 Answers8

4

or unforeseen pitfalls that would introduce bugs into the program

Well, the possible pitfalls would be

  1. Harder to debug. You won't be able to view the results of each function call, so if one of them is returning something unexpected you will need to break it up into smaller segments to see what is going on. Also, any call in the chain may fail completely, so again, you may have to break it up to find out which call is failing.

  2. Harder to read (sometimes). Chaining function calls can make the code harder to read. It depends on the situation, there's no hard and fast rule here. If the expression is even somewhat complex it can make things hard to follow. I don't have any problem reading your specific example.

It ultimately comes down to personal preference. I don't strive to fit as much as possible on a single line, and I have been bitten enough times by chaining where I shouldn't that I tend to break things up a bit. However, for simple expressions which are not likely to fail, chaining is fine.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • Thanks! I'll have to avoid using it with anything more complex than the example then. I sometimes forget a lot of functions return garbage if they fail, especially ones returning pointers. Luckily, my debugger enters any function calls in a statement if I tell it, so that at least may not be a big hassle. – Anne Quinn Feb 21 '11 at 19:40
3

Yes, this is perfectly acceptable and in fact would be completely unreadable in a lot of contexts if you were to NOT do this.

It's called method chaining.

There MIGHT be some performance gain in that you're not creating temporary variables. But any competent compiler will optimise it anyway.

Falmarri
  • 47,727
  • 41
  • 151
  • 191
  • 1
    As an aside, it can also make the code completely unreadable in a lot of contexts as well. And has the potential (depending on how it is implemented) to introduce some scoping bugs. Like most things, it really depends on how you use it: if it makes it more readable, go for it; if it makes it less readable, don't. – Zac Howland Feb 21 '11 at 19:21
  • I was wondering if this had a name! And I was enjoying not having to rely on temporary variables when it was only to break up the statement. (I still use them to cache results though) @Zac : From most of the answers, that seems to be the consensus. I sometimes forget coding involves judgment calls like that. I'll have to be sure to just think in terms of that last thing you said from here on in, thanks! – Anne Quinn Feb 21 '11 at 19:46
1

it is perfectly valid to use it the way you showed. It is used in the named parameter idiom described in C++ faq lite for example.

One reason it is not always used is when you have to store intermediate result for performance reasons (if normalize is costly and you have to use it more than one time, it is better to store the result in a variable) or readability.

my2c

neuro
  • 14,948
  • 3
  • 36
  • 59
  • I just finished reading that article you linked. That gives me quite a few ideas for some problem classes I have. Thanks! – Anne Quinn Feb 21 '11 at 19:54
  • @Clairvoire : You are welcome. C++ faq lite is a must to read when you have gone past the C++ basic skills. Good luck with your code :) – neuro Feb 22 '11 at 08:49
1
someVector = (segment.getFirst() - segment.getSecond()).normalize().normalCCW();

Not an answer to your question, but I should tell you that the behavior of the expression (segment.getFirst() - segment.getSecond()) is not well-defined as per the C++ Standard. The order in which each operand is evaluated is unspecified by the Standard!

Also, see this related topic : Is this code well-defined?

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Oop, I guess we can assume getFirst() and getSecond() both return a Vector, which has - overloaded, for example's sake – Anne Quinn Feb 21 '11 at 19:19
  • @Clairvoire: That makes sense. My post should be taken as precaution. After all, I was not trying to answer! – Nawaz Feb 21 '11 at 19:25
  • Okay! And thanks for that link. I am quite glad doing anything that contrived with this method chaining thing will never cross my mind. – Anne Quinn Feb 21 '11 at 19:33
  • 2
    What's not well defined exactly? Assuming getFirst() and getSecond() are const functions(which, I think, is a safe assumption), the result is perfectly well defined. If you are referring to the order in which the two functions are called, you are correct, but I think that's rather irrelevant to the calculation. – Benjamin Lindley Feb 21 '11 at 19:56
1

Using a variable to hold intermediate results can sometimes enhance readability, especially if you use good variable names. Excessive chaining can make it hard to understand what is happening. You have to use your judgement to decide if it's worthwhile to break down chains using variables. The example you present above is not excessive to me. Performance shouldn't differ much one way or the other if you enable optimization.

Emile Cormier
  • 28,391
  • 15
  • 94
  • 122
  • Thanks! Strangely, I find almost 50% of my time while coding, spent trying to think of good names for variables/classes/functions. Always fail when it comes to temporary variables though, and end up giving up and calling it 'double temp_double' or something equally lazy. I will try to avoid using excessive chains then – Anne Quinn Feb 21 '11 at 19:51
  • 1
    A thesaurus or other libraries can sometimes give you inspiration for good variable names. If you invest time coming up with concise, self-explanatory names, you'll save time later when documenting code. The code will already be self-explanatory. – Emile Cormier Feb 21 '11 at 21:45
0

I suppose what you are doing is less readable, however on the other hand, too many temporary variables can also become unreadable.

As far performance I'm sure there is a little overhead when making temporary variables but the compiler could optimize that out.

Marlon
  • 19,924
  • 12
  • 70
  • 101
0

There's no big problem with using it in this way- some APIs benefit greatly from method chaining. Plus, it's misleading to create a variable, and then only use it once. When someone reads the next line, they don't have to think about all those variables that you now didn't keep.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • Actually, now that you mention it. I am going to have to re-examine how I have been using some of the libraries I have, just to see if this would work better with them. Thanks! – Anne Quinn Feb 21 '11 at 19:22
0

It depends of what you're doing.

For readability you should try to use intermediate variables.
Assign calculation results to pointers, and then use them.

Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185
  • That's mostly how I've learned to do it. But I'm not sure I follow what the pointer is needed for... – Anne Quinn Feb 21 '11 at 19:24
  • You want to save the result... So if you wouldn't use a pointer, but a class variable, it would call the copy constructor and copy the data. Waste of time. – Yochai Timmer Feb 21 '11 at 19:27
  • Could you show an example of what you're suggesting? How do you assign a calculation result to a pointer if the function doesn't return a pointer? – Benjamin Lindley Feb 21 '11 at 19:44