Tuesday, August 13, 2013

FeedaMail: Comments for Sutter’s Mill

Comments for Sutter's Mill
feedamail.com Comments for Sutter's Mill

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by Nemanja Trifunovic

There is one major problem with your reasoning, and it can be nicely summed up in this sentence:

“Zilch. Not a single specific type appears anywhere in this code, and the lack of exact types makes it much more powerful and doesn't significantly harm its readability.”

The code sample you gave is very non-typical. That is generic, template-based code usually written by library implementers. I write code like that in my open-source project, but never at work. Code I write at work is full of types and except in a few corner cases such as declarations of iterators explicit types do improve reliability and robustness of code.

In short, I think I agree with your advice to use “auto” as much as possible, but only for template libraries. For all other code, “auto” should be used only in very few cases.

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by ned

Another downside of using auto is search-ability – it makes it very hard to search a code base to find all the places that an object is used. This can be an issue re-factoring an interface – they don’t always get written perfectly the 1st time. In a smaller project, a good IDE can help here, but when a code base spreads across 10′s or 100′s of projects its hard to beat find-in-files.

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by mttpd

A few extra thoughts and a question ;-)

* “Compile-time duck typing” is generally referred to as “structural typing” (or “property-based typing”):
https://en.wikipedia.org/wiki/Structural_type_system

* In the “What exact type is Container?” paragraph, perhaps it’s also worth mentioning on how it helps with satisfying the open/closed principle?

* I would still advise against using auto for the loops’ counting/indexing variables:
- I happen to very much care about expressing the non-negativity intent via the type system (so sloppy and wrong “auto i = 0″ is absolutely out),
- I also care about automatically matching the right data model (register size) without having to worry about such low-level details as whether I’m compiling for the LLP64 data model or the LP64 data model or anything else (so contortions such as platform-dependent macros choosing between the suffix UL and the suffix ULL are most definitely out),
- I also want zero-overhead portability (this is C++, after all), so committing to ULL (other than not being future-proof and generally violating the previous constraint), is out as well,
- “for (auto i = std::size_t{0};”, …, really? :-)

This could have been solved if we only had the suffix for std::size_t (ZU anyone? ;]), but as of today I don’t really see any alternative.

* How does decltype(auto) fit into the big picture? :-)

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by avjewe

What if you want to use the default constructor?
Would you still advocate
auto x = type{}
rather than
type x;
?

Read More »

Comment on GotW #7a: Minimizing Compile-Time Dependencies, Part 1 by Gennaro

Hi Herb, a little note just in case there’s an unintended limitation:

> You may not make any changes other than removing or rewriting #include directives

Is the prohibition to forward declare intentional or was the wording just changed at the latest moment resulting too strict?

Read More »

Comment on GotW #7a: Minimizing Compile-Time Dependencies, Part 1 by helloworld922

2. With only modifying the #include statements the only obvious inclusion I can get rid of is iostream (alt. can get rid of ostream, but I like including ostream instead of iostream because it’s more specific, and this doesn’t rely on iostream including ostream internally).

With forward declarations of class C and class E, c.h and e.h can be safely moved to x.cpp.

Also, shouldn’t the operator<< overload be extern with the actual implementation defined in x.cpp (alt.: declare it inline)?

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by Jeffrey Bosboom

Two points about auto and expression templates:

–If you use ‘auto a = x * 5someliteral’ where * returns an expression template, that template has a reference to a temporary object that will be destroyed at the end of the expression. So you can use auto to hold an expression template object, but you can’t safely do much with it (in particular, evaluate it). This feels like a trap, especially when combined with the next point.

–If you change an operator that used to return a Foo to return an expression template convertible to a Foo, any code that used to use auto can break as above because it gets an expression template. Despite using auto, if you want the flexibility to introduce expression templates after-the-fact (say, after profiling shows you need them), you need to use the ‘auto a = Foo{expr}’ form everywhere. And because there’s no types, it’ll be hard to find the locations whose meaning changed, unless you have an IDE that can find all usages of e.g., operator*. You might not even know about breakage if it’s in some template (and similarly the template author has to decide between ‘auto a =x*y’ and ‘auto a = T{x*y}’).

I recall there being some consideration of an ‘operator auto()’ to instruct the compiler what type to infer, and I’m not yet convinced it isn’t necessary.

Read More »

Comment on GotW #7a: Minimizing Compile-Time Dependencies, Part 1 by Alf P. Steinbach

In C++03 the <ostream> header could not be formally removed if one used e.g. std::endl, or the << operator. However, in practice one could use just <iostream> (as all examples in the C++03 standard erroneously did), and with C++11 that’s also formally supported. In the above code it’s not an issue, so <ostream> can just be removed. I would also replace full <iostream> with <iosfwd>.

Class E is only used result and argument type, and so its header can be removed. The situation for class C is more complicated. The C++03 standard (I’m not 100% sure of C++11 and don’t have the time to check now, sorry) required the item type of a standard library container such as the std::list in this code, to be a complete type. However, this formal requirement was regularly sinned against with e.g. std::auto_ptr, by ensuring that the code conformed to the actual requirements of the particular C++ implementation. The most infamous case of this lets-be-practical-about-it approach was one of your own PIMPL GOTWs.. :-) But anyway, at least for the formal class C’s header is needed, since C is used as a container item type, so, only the header for E can be omitted.

I would put a de facto standard #pragma once at the of that header.

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by zadecn

the codes and comments below have a little bug:

auto b1 = my_vector_bool.back(); // to capture the proxy
b1 = true; // write into my_vector

I think the right is :
auto b1 = my_vector_bool.back(); // to capture the proxy
b1 = true; // write into my_vector_bool

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by noniussenior

“Quick quiz: How many specific types are mentioned in that function? Name as many as you can.

void some_function( Container& c, const Value& v )
…”

Why is void not a specific type?

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by tr3w

Because of what Jeffrey Bosboom said, I think the my_vector_bool is a really bad example, since the following two code does something really different (and because the vector specialization already considered as a mistake).

  auto b1 = my_vector_bool.back(); // to capture the proxy  b1 = true; // write into my_vector_bool    auto i1 = my_vector_int.back(); // No proxy  i1 = true; // NOT write into my_vector_int  

Read More »

Comment on GotW #7a: Minimizing Compile-Time Dependencies, Part 1 by Victor

JQ #1: For a function or a class, what is the difference between a forward declaration and a definition?

For function:

Forward declaration specifies function’s return type and signature (parameters, cv-qualifiers if memeber, template parameters if any). It tells compiler about how to call this function, so parameters sizes should be known. Parameter size if known for any pointers, references or for complete types.
Function definition may be treated as declaration, but additionally should contain function body: zero or more statements which will be executed during function call.

For class:

Class forward declaration provides incomplete type, including class name and template parameters (if any). Note, it doesn’t provide information about inheritance from base classes.
Class definition provides complete type, including instance size (so, data member sizes and definition of base class are needed), declaration of all class methods and template parameters. So, definition provides all necessary information to compiler about what class is and how to use it, with or without function definitions.

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by Petter

See e.g. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=505 for bugs/misunderstandings involving expression templates and auto.

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by Marcel Wid

I personally prefer to use auto to declare local variables. But unfortunately there are some problems with auto and uniform initialization. Perhaps it is a good idea to shed some more light on these pitfalls:
Always use copy-initialization for variables declared with auto, i.e. auto x = expr; where expr is an expression. The point is, that a braced-init-list is NOT an expression. A corollary of this guidline is: Never write something like

  auto x = {1};  

The type of x will most likely not what you expect: Here x will have type std::initializer_list!

For another example consider the following code:

  class X  {  public:      X() : x_{0} {}  private:      int x_;  };    double f() { return 4.2; }  double d{f()};  

We teach people to use uniform initialization (in this case direct-list-initialization) for class members like: x_{0}; or variables like: double d{f()}; This avoids the “most vexing parse”:

  double d(f());  

But if we write

auto d{4.2};
{/code]
then we get a variable d of type std::initializer_list, which again is most likely not what we want. There is a proposal (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3681.html) which will solve many problems mentioned above.

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by gnzlbg

Do you have a reference to as_signed/as_unsigned ?

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by Petter

I must say that the following is very error-prone:

   auto b1 = my_vector_bool.back();  // ...  b1 = true;  // Oops! my_vector_bool changed!   

compared to

   bool b1 = my_vector_bool.back();  // ...  b1 = true;  // vector not changed.   

In almost all cases, auto will give you a copy. vector is error-prone combined with auto.

Read More »

Comment on GotW #7a: Minimizing Compile-Time Dependencies, Part 1 by Anubhav

In accordance with $3.2/4 –
-’A’ and ‘B’ need to be complete types.
-Classes C and E need not be complete, because X does not define (as opposed to declaring) any of it’s member functions,
-D needs to be complete because class ‘X’ has a member object of type ‘D’.
-iostream can also be removed as we already include ostream

Read More »

Comment on GotW #94 Solution: AAA Style (Almost Always Auto) by Norbert Riedlin

I really like one more in C++14 upcoming application of auto:
Consider:

  class C {  private:      // real internal things:      // C++11:      class Internal;      Internal doSomething();            // C++14:      //auto doSomething();  };  

In C++11 and before I have to name the return type of “doSomething()”. Although that can be done by forward declaring a local class, it feels even nicer not to have to mention that class in C++14. (At least that is how I understand N3638)

Read More »

Comment on GotW #7a: Minimizing Compile-Time Dependencies, Part 1 by Victor

Guru Question: In the following header file, what #include directives could be immediately removed without ill effect? You may not make any changes other than removing or rewriting #include directives. Note that the comments are important.

About std headers:

1. Including automatically includes also , , , and . So, we don’t need both and , simple is enouth. However, there is references only for ostream classes in function declarations – so we don’t need complete ostream type here. (Remember about function declarations). Just use forward declaration from instead of and .

2. Including is needed – we use std::list as data member, so compiler needs complete type information here.

About custom headers:

1. class X is derived from A and B. So, compiler heeds complete type information here, leave “a.h” and “b.h” as is.

2. Class C is a great candidate for further removal, but it’s used in function declaration as parameter with passing by-value. It’s sad, but compiler needs to know about what class C is right here, so complete type is needed, and we leave #include “c.h” in code. Additionally, it is strange that class C has virtual functions, but is passed by-value. Schedule a meet with this code author :)

3. Class D is a data member. So, we need to leave “d.h”

4. Class E is used as return type in function declarations only. It’s strange, but compiler doesn’t need complete type here. AFAIR, it was side effect of C calling convention on x86 compilers. Maybe I’m wrong about why it’s not not needed (please correct me?) but I think, we could change #include “e.h” to forward declaration on class E;
The only thing preventing us from this simple optimization is this exercise statement: We may not make any changes other than removing or rewriting #include directives. So, leave as is.

So, there is result:

  // #include <iostream> - removed  // #include <ostream> - changed to iosfwd  #include <iosfwd>  // placed instead of <ostream>  #include <list>    // None of A, B, C, D or E are templates.  // Only A and C have virtual functions.  #include "a.h"  // class A  #include "b.h"  // class B  #include "c.h"  // class C - candidate for further removal by rewriting 'C  f( int, C );' signature and adding forward declaration  #include "d.h"  // class D   #include "e.h"  // class E - candidate for removal by changing to forward declaration right here and right now.    class X : public A, private B {  public:         X( const C& );      B  f( int, char* );      C  f( int, C );      C& g( B );      E  h( E );      virtual std::ostream& print( std::ostream& ) const;      private:      std::list<C> clist;      D            d_;    };    std::ostream& operator<<( std::ostream& os, const X& x ) {      return x.print(os);  }  

I think, another optimization will result in redesign, so we can’t omit more headers right now.

Read More »

Comment on GotW #7a: Minimizing Compile-Time Dependencies, Part 1 by Victor

Guru Question #2. Many programmers habitually #include many more headers than necessary. Unfortunately, doing so can seriously degrade build times, especially when a popular header file includes too many other headers.

1. Including automatically includes also , , , and .
So, is not needed. However, don’t fool ourself – is excess. Actually, is enough, don’t include .

2. Next step about io streams usage: there is references to streams only. Compiler initially knows reference size for any class, so forward declaration is enough here. Replace streams implementation header with forward declaration: .

That’s all about std headers – unfortunately, we use std::list as member, so full std::list class definition is needed. Lease as is.

Class X is derived from A and B, so we need to know what A and B is – leave “a.h” and “b.h”.

Class C is candidate for further header removal, unfortunatelly, it’s passed into function declarations by value, so compiler need to know what is C, what constructors it have, etc. So, draw a sigh and leave “c.h”.

Class D is a data membe – compiler needs D declaration. Leave “d.h”

Class E is used in return type only – that’s good news. Return type might be incomplete type. This may be surprise, AFAIR, it’s good side effect of C calling conversions. I may be wrong in describing why it may be omitted (please correct me?) but I think we can remove “e.h”.

So, we have:

  #include <iosfwd>  #include <list>    // None of A, B, C, D or E are templates.  // Only A and C have virtual functions.  #include "a.h"  // class A  #include "b.h"  // class B  #include "c.h"  // class C - it's sad to see it here  #include "d.h"  // class D    class X : public A, private B {  public:         X( const C& );      B  f( int, char* );      C  f( int, C );      C& g( B );      E  h( E );      virtual std::ostream& print( std::ostream& ) const;      private:      std::list<C> clist;      D            d_;    };    std::ostream& operator<<( std::ostream& os, const X& x ) {      return x.print(os);  }  

Read More »

Comment on GotW #7a: Minimizing Compile-Time Dependencies, Part 1 by abrarov

  //  x.h: original header  //    #ifndef X_H  #define X_H  

No comments:

Post a Comment