From boris@kolpackov.net Thu Dec 18 12:06:49 2003 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1AX2Xw-0000r2-SU for notes@kolpackov.net; Thu, 18 Dec 2003 12:06:48 -0600 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id hBIIB5MM025804 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 18 Dec 2003 12:11:05 -0600 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id hBIIA1aY006703 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 18 Dec 2003 12:10:02 -0600 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id hBIIA1Ya006701 for notes@kolpackov.net; Thu, 18 Dec 2003 12:10:01 -0600 Date: Thu, 18 Dec 2003 12:10:01 -0600 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20031218181001.GA6686@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="bp/iNruPH9dso1Pn" Content-Disposition: inline X-Uptime: 2 days X-URL: http://kolpackov.net X-Accept-Language: en, ru User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Thu, 18 Dec 2003 12:07:43 -0600 Subject: dynamic_cast X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Dec 2003 18:06:50 -0000 --bp/iNruPH9dso1Pn Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Good day, In my recent project (compiler) I got exposed to some obscure=20 features of C++ dynamic_cast operator. After encountering a few=20 surprises I decided to test dynamic_cast in static (pun intended)=20 and here are some of my observations. First of all, dynamic_cast has four distinguishable outcomes: * run-time failure=20 Results in std::bad_cast exception in case of a reference and=20 0 in case of a pointer. * run-time conversion Results in an accordingly adjusted at run-time reference or=20 pointer. * compile-time failure=20 Diagnosed by a compiler as an error. * compile-time conversion Results in an accordingly adjusted at compile-time reference or=20 pointer. Note that in this case no run-time checking is performed. The latter two outcomes may be a surprise to you but here is the=20 case (and the only case, to my knowledge) in which everything is done at compile-time: struct A { virtual ~A () {} }; struct B1 : A { }; struct B2 : A { }; struct C : B1, B2 { }; void f () { C c; dynamic_cast (c); // compile-time error: ambiguous B1& b1 =3D c; dynamic_cast (b1); // compile-time conversion }; This case is described in clause 5.2.7 paragraph 5 of The C++ Standard and boils down to conversion to accessible unambiguous base. Note also=20 that, even though C doesn't have unambiguous base of type A, the=20 conversion still succeeds. Another interesting feature is dynamic_cast to void* (described in clause 5.2.7 paragraph 7). One might expect that it would be=20 equivalent to implicit conversion to void*. The following example=20 examines the difference: struct A { virtual ~A () {} =20 long a; }; struct B { virtual ~B () {} =20 long b; }; struct C : A, B { }; int main () { C c; =20 C* cp =3D &c; B* bp =3D cp; void* sv =3D bp; void* dv =3D dynamic_cast (bp); cerr << "cp =3D " << cp << endl; cerr << "bp =3D " << bp << endl; cerr << "sv =3D " << sv << endl; cerr << "dv =3D " << dv << endl; }; On my box the example prints cp =3D 0xbffffa50 bp =3D 0xbffffa58 sv =3D 0xbffffa58 dv =3D 0xbffffa50 which shows that dynamic_cast returns pointer to the most derived object pointed to by the argument. Note that the argument should be a pointer/reference to a polymorphic type. Protection violation and ambiguity are the common causes for=20 conversion failure. As surprising it may sound, in dynamic_cast they lead to run-time failures. Consider the following example (covers protection violation - ambiguity is analogous): struct A { virtual ~A () {} }; struct B { virtual ~B () {} }; struct C : A, protected B { }; void g () { C c; =20 A& a =3D c; B& b =3D (B&)(c); // subvert protection =20 dynamic_cast (a); // run-time failure dynamic_cast (b); // run-time failure } struct D : A, B { }; struct E : protected D { void f () { A& a =3D *this; dynamic_cast (a); } }; void h () { E e; A& a =3D (A&)(e); // subvert protection dynamic_cast (a); // run-time failure =20 e.f (); // run-time failure even though executed // in member function dynamic_cast (a); // ok }; The difference between the last two conversions is somewhat subtle and specified in clause 5.2.7 paragraph 5. To better understand all these cases you can view inheritance as a graph and dynamic_cast as a traverser that can navigate through edges in any direction but only if they are public and unambiguous. Plus one small condition: in order for dynamic_cast to jump to a sibling (from A to B in D-inheritance) it has to be able to traverse to the most derived object (E in our case). You may also be surprised that certain 'obvious' cases are not handled at compile-time. Consider for instance this example: struct A { virtual ~A () { } }; struct B : protected virtual A { }; void k () { C c;=09 A& a =3D (A&)(c); =20 dynamic_cast (a); // run-time failure } Since B has only protected base of type A then dynamic_cast (A&) should always fail. Apparently this is not the case: struct D : virtual A { }; struct E : D, B { }; void l () { E e; D& d =3D e; A& a =3D d; dynamic_cast (a); // ok } In this example compiler cannot take A->B path. Instead it takes longer but legal path A->D->E->B. This also shows that protection information is preserved in translated programs and not discarded after static analysis. Another relevant to dynamic_cast C++ feature is virtual base class. As you may know, we cannot use static_cast to 'up-cast' from virtual base to derived and dynamic_cast is the only option: struct A { virtual ~A () {} }; struct B : virtual A { }; void m () { B b; A& a =3D b; static_cast (a); // compile-time failure dynamic_cast (a); // ok } To understand why we can't use static_cast with virtual bases consider this example: struct C : virtual A { }; struct D : C, B { }; Here either C or B (or both) will have to 'give up' their instance of A in order to share the common copy. As a result compiler has no way to decide at compile-time whether a pointer to A is B's own copy of A (as in the former case) or it is somebody else's copy of A that B is=20 sharing (as may happen in the latter case). And finally, to show how crafty dynamic_cast can be, one practical=20 example: struct A { virtual ~A () {} }; struct B : A { }; namespace N { struct B { virtual ~B () {} }; void f (A& n) { dynamic_cast (n); } } Do you see the problem? Do you think compiler will warn you? Of=20 course, you may say, A and N::B are two unrelated types thus compiler will never be able to convert A& to N::B&! Well, this is not quite=20 correct. The following definition would establish the relationship between A and N::B which is just good enough for dynamic_cast: struct C : A, N::B { }; And since compiler cannot foresee that there is no such relationship it has no other choice than to perform run-time check. hth, -boris --bp/iNruPH9dso1Pn Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBP+HteciAKQuuCE8dAQKOSQv/Q4DUtdtjicY1aba9ns/NEn7CSgHxzKu7 MQKEjRlv4ZEV6k7RgFZJ4DIamu+T6jLBs5OCMg8t8YGfNf3fox24/tskeSYSBinD pPBTey2zPIScFTyi6KkJvC99RD3JWVfYWZCxKFKtyYssyzYNd5+WFskEI7/qdJJj KpzhbK3dkJABQLsbpjgfWn7N7s59JKYIKt345Gl2WfvpYB97SLgUYuZ7D/Ds2ykZ L3mgxRy8y9nthSjSdoX0y9vdltctVFk7I90jvsb1QfmoctqkALkZfC1jrcVdf/UJ OEKDvuPLOh42U7dsbobwVbfibbtgGcvPjzJlt+GaY9fnms0cNIHxKdwmkJGl0pnr ndGMSKQRRUtN7tD5RdrfN5qTF/ogy+JGEXqzyz/JZsJUedHjnK+O/jrOb7kc3WjX zDGzRpSI2wT5t4Jn+QpgcX5xQTKCuNIOw1/nEKuqKRgouYSMhklymkx7O5AqdMz/ ORQlTs+uwpbUgtyhZXhCP3irVuc7Gu8E =8MCP -----END PGP SIGNATURE----- --bp/iNruPH9dso1Pn-- From boris@kolpackov.net Thu Jan 22 13:17:34 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1AjkKc-0002Vj-Ln for notes@kolpackov.net; Thu, 22 Jan 2004 13:17:34 -0600 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i0MJMm16002246 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 22 Jan 2004 13:22:48 -0600 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i0MJLRoA003881 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 22 Jan 2004 13:21:27 -0600 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i0MJLR3d003879 for notes@kolpackov.net; Thu, 22 Jan 2004 13:21:27 -0600 Date: Thu, 22 Jan 2004 13:21:27 -0600 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040122192127.GA3868@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="45Z9DzgjV8m4Oswq" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Thu, 22 Jan 2004 13:19:15 -0600 Subject: GNU make: order-only prerequisites X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 22 Jan 2004 19:17:36 -0000 --45Z9DzgjV8m4Oswq Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable A new flavor of prerequisites was introduced in GNU make 3.80 called order-only prerequisites. They are essentially the same as normal ones except that an out-of-date order-only prerequisite does not render its=20 targets out-of-date. I found this especially useful in the following=20 context. Suppose I need to build 'foo.o' from 'foo.c' in $(out_dir). In the GNU make syntax such a desire can be expressed, for example,=20 like this: $(out_dir)/foo.o : foo.c g++ -c $^ -o $@ So far so good. Now, suppose the directory $(out_dir) does not always exist and I need to create it before producing 'foo.o'. The first thing=20 that comes to mind is to write something along these lines: $(out_dir) : mkdir -p $@=20 $(out_dir)/foo.o : $(out_dir) This doesn't work because now we have two prerequisites for=20 '$(out_dir)/foo.o' and when the rule's command is executed, we get=20 something like this (assuming $(out_dir) is /bar): gcc -c foo.c /bar -o /bar/foo.o Of course, we could filter out all prerequisites that don't have suffix '.c' but that wouldn't be a very elegant solution. A much cleaner approach= =20 would be to use an order-only prerequisite: =20 $(out_dir)/foo.o : | $(out_dir) This will ensure that if $(out_dir) does not exist then it will be created before '$(out_dir)/foo.o' is built. hth, -boris --45Z9DzgjV8m4Oswq Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQBAit8iAKQuuCE8dAQJ5lgwAjBe7Vyt+kujd89gpzb20S032aoT+vWRZ h4GNmoTzp2/0hrvdfn1wv/YwrTfFOprqswvZabBK2T391CjJNY2xoCCL9p7d+u3y 2l2X1o03t069HA+W/orK6+BHH3rVKUD0wULh/xE/apGTJXbw2baQzwRCG/UkJc7D ZOwXL8XvE0gp9QdaAt435kSXuwJRSRGkC5+cXmKj0nc1e5+cMGK2TXk5/iCSWeo6 tjB8Bt2iXAghXRYcXjlHscCe1WTPVWfaEfV6dd+ffob1UPHUiqn4si6qsyV/jhfO Gn3suyUyrLqhxy/3AK7xpWrDRyd+hxKIxr5Ivo4zR5Nza9vocaNIVt2nREiGwOnL TU0h8pTUNIJADZ3fJfJygPy8suMRur0EONUdsPzrA6+RowC5UEyoWai4vVJvqwO9 0irzlGp7FTWwAH8J7B3luUQJnqAZfRY5oI4ca3xVPP8lJgyJVpSlGcC1zuguZq82 WAFRkDRrVB5T3rU/AM+ygvnpYC9MjdQi =Hupi -----END PGP SIGNATURE----- --45Z9DzgjV8m4Oswq-- From boris@kolpackov.net Mon Jan 26 14:24:59 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1AlDI2-00010h-W1 for notes@kolpackov.net; Mon, 26 Jan 2004 14:24:59 -0600 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i0QKUHqf027261 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Mon, 26 Jan 2004 14:30:17 -0600 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i0QKSvoA007482 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 26 Jan 2004 14:28:57 -0600 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i0QKSvuZ007480 for notes@kolpackov.net; Mon, 26 Jan 2004 14:28:57 -0600 Date: Mon, 26 Jan 2004 14:28:57 -0600 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040126202857.GA7467@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="d6Gm4EdcadzBjdND" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Mon, 26 Jan 2004 14:25:42 -0600 Subject: c++: class-type enumeration X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 26 Jan 2004 20:24:59 -0000 --d6Gm4EdcadzBjdND Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Good day, I would like to announce two new articles which are available=20 =66rom my website: "Class-type Enumeration" describes a class-based alternative=20 to potentially dangerous and inflexible C++ enumerations.=20 http://kolpackov.net/projects/c++/enum/class.xhtml "Class-type Enumeration Synthesis" is a complementary article=20 that provides details of the synthesis process results of which=20 are presented in "Class-type Enumeration". http://kolpackov.net/projects/c++/enum/synthesis.xhtml -boris --d6Gm4EdcadzBjdND Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQBV4iciAKQuuCE8dAQKOfQwAlNySWDswilZJge4aj60o+BhdolvHEUSi zTiDnA8aYf4m6ETLV/v5l5h8SzOdDPnBuJdnbM7Z8Pqb8NYBjAVW5QVsZE/zw9Wc ri/bmRP1AdgsHpplo///gOL6mpJSsdtMKY7ttmVprp7EWMyo0/v5kNbXRqqzlWBe bxtOrnbxo5ILPgaCh6sxouGuVqymLVIqfEEkt/7DNEUNVd5hk5zLJAXyKT5iC1n+ k2k27OZ1C/DN3FrTY6vE5xotpZU1q9jD/1f2DKi3LK+B/FpsSvh1ySaPUTgs5hKc knEy76iWHwvfCYBbrCihj/eNeAVXtIdshl5KTkJKhYuR+4vxZ1SVXLUrek+Zb7CK qSCgt6l1tEMRq4nbrX/V7WuWzgpa84s+/cB3CVNL6Nys+4CVAjNYaUw2IN07rMzp 9Lar8YJODQCfUr8EO6yPPgS8tMskJ/cREO5ogEWfXuHHJbjyb6vPlMHzXUFxEjF1 YeumStC/YSAh5y0/QdHOsmYvYQpwnBGa =5hx0 -----END PGP SIGNATURE----- --d6Gm4EdcadzBjdND-- From boris@kolpackov.net Mon Feb 23 16:23:57 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1AvOUX-0000Wv-HI for notes@kolpackov.net; Mon, 23 Feb 2004 16:23:57 -0600 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i1NMU1TO018318 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Mon, 23 Feb 2004 16:30:01 -0600 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i1NMSbRX017785 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 23 Feb 2004 16:28:37 -0600 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i1NMSbOL017783 for notes@kolpackov.net; Mon, 23 Feb 2004 16:28:37 -0600 Date: Mon, 23 Feb 2004 16:28:37 -0600 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040223222837.GA17775@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="oyUTqETQ0mS9luUI" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Mon, 23 Feb 2004 16:26:11 -0600 Subject: c++: notes on namespace X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Feb 2004 22:23:59 -0000 --oyUTqETQ0mS9luUI Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Good day, Below are some notes on namespace usage in c++. DEC++ - The Design and Evolution of C++ PLC++ - The C++ Programming Language (special edition) TC++ - C++ Templates @@ A namespace should: - contain logically related set of features; the relation is=20 usually suggested by the name of the namespace - be convenient and natural to use by not imposing significant=20 notational burden @@ Two roles of namespaces: - avoid name clashes - group logically related entities @@ There are four mechanisms that allow you to access a name in=20 a namespace: - membership - qualification - using-declaration - using-directive @@ Qualify names that are used once-twice; using-declare names that are used regularly. @@ Prefer using-declaration/using-directive in a function scope to using-declaration/using-directive in an outer scope. @@ Using-directive is an efficient way to 'inherit' namespaces. @@ Using-directive allow you to 'override' some declarations=20 (see also DEC++ 17.4.3 last paragraph; PLC++ 8.2.8.2). @@ Using-declaration brings on all functions associated with=20 the name. Thus it makes sense not to name unrelated functions with the same name. Also consider argument-dependent lookup=20 (PLC++ 8.2.6; TC++ 9.2.1). @@ Namespace models: 'flat' (like std::) and 'tree' (with nested namespaces). @@ A 'tree' model can potentially be transformed into a 'flat'=20 model via using-directives. @@ In the 'tree' model the outer namespace is usually for name- clash avoidance; the inner namespaces are for the concept=20 grouping. @@ What names are good/bad for namespaces? What should namespace name signify? =20 Bad: name of interface (parser, lexer, reader, etc). You will most likely want to name one of the entities in the namespace=20 with this name. As a result you will end up with something=20 ugly like 'parser::parser'. =20 Namespace name should not correspond to a single entity but rather to a category to which names in the namespace logically belong. This makes the job of choosing the right name even=20 trickier: you have to decide based on which principal to group. Should we use plural names? @@ In DEC++ 17.4 there is a suggestion that using-directive=20 syntax is redundant and instead of writing 'using namespace A;' we could simple write 'using A;'. Note, however, that in=20 the standard C++ 'using A;' and 'using namespace A;' have=20 distinct semantics. =20 =20 @@ DEC 17.5.1 suggests an analogy between class inheritance and namespace nesting. This analogy doesn't scale to multiple=20 inheritance, however (because a namespace cannot be nested=20 into more than one namespace). A better analogy, IMO, would be using-directive in which case we get surprisingly precise matching. Consider the following example: struct A { void f (); }; struct B : A { void f (); }; struct C : A { void f (); // hides A::f }; struct D : A, B { // f is ambiguous using B::f; // choose B::f over A::f }; =20 By replacing 'struct' with 'namespace' and inheritance with=20 using-directive we get the same 'inheritance' semantic we=20 have for classes: namespace A { void f (); }; =20 namespace B { void f (); }; namespace C { using namespace A; void f (); // hides A::f }; struct D : A, B { using namespace A; using namespace B; // f is ambiguous using B::f; // choose B::f over A::f }; --oyUTqETQ0mS9luUI Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQDp+lciAKQuuCE8dAQKTVAv7BIBHCutrcsGfX1IbLcJD7+efSIPt9Zi/ NcjLQ53F4/7z62p2iF67XYow4PVzRYi694+TFN1+S0Xchfo9ODzUw5AOVrOmz2wW XQwEAIYcl6bGjkB4CoNiUGB/KbN/Fhei6Rl3X0sS0ULF4YErmhIQoMw8VWrPo1so ljKCv7fmHc0nzQEaT8SZiNhR5n1k8CHVfO7VpcKv6RDqNPlmS36K/tvqReDzw8lp lyTEkVP57GiU2ZCEnfk0LeqCtMI0hVfZowd/eCHhc27otde6ffateVH8a+3A0u6r nFbIJyj4GerVCGIMixUar5w3GoEL+ZDIrX++vwupEIwtJCOx1A1qyEbgjSXnUapG B5u5VadDoarLf5Lbe0rV6LEadB6NB+RKUNelBzkyjkIfPS2LPoHAK8BlK2JoOfrs nQv1qp+j5F9zmjlU3SqvVeSIaigl6ME+csV10cInGq17+IfpBLtUu+Q78iqFrGcW Ds52ya3nS1gBIqTIwGnw8/xjdTBj9VIR =bJh9 -----END PGP SIGNATURE----- --oyUTqETQ0mS9luUI-- From boris@kolpackov.net Thu Mar 11 15:17:00 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1B1XY4-0008MU-CX for notes@kolpackov.net; Thu, 11 Mar 2004 15:17:00 -0600 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i2BLNVTO005693 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 11 Mar 2004 15:23:31 -0600 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i2BLLp6V003965 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 11 Mar 2004 15:21:51 -0600 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i2BLLpOo003963 for notes@kolpackov.net; Thu, 11 Mar 2004 15:21:51 -0600 Date: Thu, 11 Mar 2004 15:21:51 -0600 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040311212151.GA3957@kolpackov.net> References: <20040223222837.GA17775@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="SLDf9lqlvOQaIe6s" Content-Disposition: inline In-Reply-To: <20040223222837.GA17775@kolpackov.net> X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Thu, 11 Mar 2004 15:20:03 -0600 Subject: Re: c++: notes on namespace X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Mar 2004 21:17:00 -0000 --SLDf9lqlvOQaIe6s Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Good day, Some additional notes/corrections:=20 > @@ Using-directive is an efficient way to 'inherit' namespaces. >=20 >=20 > @@ Using-directive allow you to 'override' some declarations=20 > (see also DEC++ 17.4.3 last paragraph; PLC++ 8.2.8.2). The latter using-directive should be using-declaration. As of composing namespaces out of other namespaces I found an interesting GNU extension called "strong using": http://gcc.gnu.org/onlinedocs/gcc/Strong-Using.html#Strong%20Using In particular it shows two potential problems in standard=20 using-directive with regards to the namespace composition=20 technique.=20 hth, -boris --SLDf9lqlvOQaIe6s Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQFDYbsiAKQuuCE8dAQLhawv/XSwDN6LZnhsg7mjLyMb/03sCtIIS5VVL QYW2UCU10P1yBMcYQchItKVCuht0lijhrBCVTjAWE0qRSt1KQUm5CVSFVJV8uPou 5T5Qrq2bLkIipPHDZ4YEGePHkVMBQHkdoV4BjRTuyRm1Bpq9SrTs27yolHZrxsUp UcxlsDbXQFVDK5mK/Fp4Bu/+Wb+ZiLdPdlWKMD3IyofV3jaDIx3vfRBdIhQeD+Qa KN6sHzsh+fvVwh+iwPGwPgUjb6oEWzme62NpPOdbTuBCSJQXTGyXqbJtvL2onXwZ aiGZcDuiXAgsBnqsBtg41QmacW8wX4YivUBgvjReHStypWr4gL2Uuu3YWeYWfVVr WaeDGnwWBc0ZD7YVvMRNyNOCTnoOVTmD62J74xfzFuCFmI0cIH6mUkdDpiiSNWtZ HctTIGz3P+n3dst5dac/1d++wW9eOTLdJK+tDLt8nGavkD78p7uHkRh9gbsdSjlx RDgt2yGP5wwVuRAcp+9J/SdpDW4o4pwK =u2rh -----END PGP SIGNATURE----- --SLDf9lqlvOQaIe6s-- From boris@kolpackov.net Mon Mar 29 13:07:28 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1B826a-0001Kk-57 for notes@kolpackov.net; Mon, 29 Mar 2004 13:07:28 -0600 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i2TJERT9006649 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Mon, 29 Mar 2004 13:14:27 -0600 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i2TJCW6V010875 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 29 Mar 2004 13:12:32 -0600 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i2TJCWDP010873 for notes@kolpackov.net; Mon, 29 Mar 2004 13:12:32 -0600 Date: Mon, 29 Mar 2004 13:12:32 -0600 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040329191232.GA10866@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="huq684BweRXVnRxX" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Mon, 29 Mar 2004 13:10:37 -0600 Subject: biggest c++ contradiction X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 29 Mar 2004 19:07:29 -0000 --huq684BweRXVnRxX Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Good day, Recently I've been reading a lengthy thread where people were naming their favorite uglinesses of c++. Of course, multiple inheritance popped up not once. As I was reading along I started wondering if anyone would name something that I could agree with. Surely nobody did and I had to think one out myself. So, IMO, the biggest c++ contradiction that appears in every c++ book you would care to name is the suggestion to use RAII=20 and not to throw from destructors. have a nice day, -boris --huq684BweRXVnRxX Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQGh1H8iAKQuuCE8dAQIOVgv+LY8GFGFInIvFR3OFr07X3kPOxZXfXFJk 1y3Pkl26ZyNv484G34JruEUY5EdcwKabx8FO1wa/f6Txzy/XbOtWDH7A8o+BBCzb oWiKBsrV/eQuO2bt9qsVLyksLbsLl7iktgGUYahNjqUkj4ctNRQaXmH2nVunbK6V img7vQ0mCKCQwb80OYxwQVCT/YdMT7d/fg1GbOySO4AQhCchZeZVUU6R/6htyPAs y00/gB9qJFBMqYErPeQO2sUYn9/pM87ghwHGMSuNGRLJpsiwDqAgSAL3DYw9XsYf oU3hKTMQLn/FpLjVrc420/0UQZ93QBTxGrynZhVP0NXfmHJzdDUoW608yC6i1kaB K+GPUVQFJAQtjgsv8qpkoWdSI4yrPy5wfduPP0GwPK/eIfOV4fd/NNsy33W13XrQ rWNN0yZFoyRLj+IfJwbkOZgEV7JS5h0hbhrnUsYoQxmEiIpjEVhAwom6gU35nTly +nUif1mcr4Z9n7ojV9O8Nw0C3UYDn4AN =3TM8 -----END PGP SIGNATURE----- --huq684BweRXVnRxX-- From boris@kolpackov.net Wed Mar 31 17:10:47 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1B8or9-0004SO-Ee for notes@kolpackov.net; Wed, 31 Mar 2004 17:10:47 -0600 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i2VNHoT9017246 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Wed, 31 Mar 2004 17:17:50 -0600 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i2VNFo6V011900 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 31 Mar 2004 17:15:50 -0600 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i2VNFoIL011898 for notes@kolpackov.net; Wed, 31 Mar 2004 17:15:50 -0600 Date: Wed, 31 Mar 2004 17:15:50 -0600 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040331231550.GA11835@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="gBBFr7Ir9EOA20Yy" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Wed, 31 Mar 2004 17:20:41 -0600 Subject: gcc: __attribute__ ((weak)) X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 31 Mar 2004 23:10:48 -0000 --gBBFr7Ir9EOA20Yy Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Good day, While playing with glibc I noticed one interesting technique. It is based on gcc's extension that allows you to declare weak symbols. In essence it works like this: extern void weak_f (void) __attribute__ ((weak)); int main () { if (weak_f) { weak_f (); } } When you link such code ld won't complain if weak_f is unresolved.=20 Plus you can check at run-time if symbol has been resolved as shown=20 above. Interesting effects can be achieved using this technique. For example you can make some code thread-safe on-demand. You compile this code once and depending on kind of application it is used in it automatically becomes multi-threaded or single-threaded: #include extern "C" int pthread_create (pthread_t*,=20 const pthread_attr_t*,=20 void* (*)(void*),=20 void*) __attribute__ ((weak)); extern "C" int pthread_mutex_init (pthread_mutex_t*,=20 const pthread_mutexattr_t*) __attribute__ ((weak)); extern "C" int pthread_mutex_lock (pthread_mutex_t*) __attribute__ ((weak)); extern "C" int pthread_mutex_unlock (pthread_mutex_t*) __attribute__ ((weak)); extern "C" int pthread_mutex_destroy (pthread_mutex_t*) __attribute__ ((weak)); class foo { public: foo () { if (pthread_create) pthread_mutex_init (&m_, 0); } =20 ~foo () { if (pthread_create) pthread_mutex_destroy (&m_); } bar () { if (pthread_create) pthread_mutex_lock (&m_); // ... if (pthread_create) pthread_mutex_unlock (&m_); } private: pthread_mutex_t m_; // some other data that mutex protects }; Now if you link your code with libpthread, foo is automatically=20 multi-thread-safe. If you don't then all the calls to mutex API=20 are skipped. This could be especially nice if class foo is in the library that is used by both kinds of applications. -boris --gBBFr7Ir9EOA20Yy Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQGtRJciAKQuuCE8dAQIHawwAwNPuP4PY0CmciS8znHOkziYAOEl4ireY tuDUZY9w/atfvPJk0aawiq10YM7uGP0PNfUA5Jy0jsGuaZMeN2zhnobdsou/cGAv h9BlBEw6PKnDDkoujIGt9etonYMq7wnISzVP3sfVNKq1+1Mb1my/7mo+nwSE4snS unfjHTvKg9qj8lC15ayffss/jbrw3MqvDhLBRuKwrxTiKUxkAQq/cQZ1Nzw0VbHj 1Vm0iU34++Wv4Y3wD3U3yc64dVArxY8SCrVIWRNSSvg468tWke9/p0WX4XQqx5jZ YQt1WxSSZpr51aX1Yivl+RQFgJxkWVYAcBmDu5+u7hvwYxf6yj95dYNHr31MW3mC KjSHVNS3h1La9KZrQPJWUTiuRsCKSgcDx4VThlDp1Zzz4qNkgJkkmqfqklxBDcd1 X1NHtRYZ338bLZiGF9g8niy50NwONcYSXY6Eblb2LDRvlLGy7BTmvSiRkCOeVj/l YDSfqK0hxNWZs1CLflPZYyHhvIpRYDiM =/tI2 -----END PGP SIGNATURE----- --gBBFr7Ir9EOA20Yy-- From boris@kolpackov.net Fri Apr 02 15:22:04 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1B9W71-0004TF-UD for notes@kolpackov.net; Fri, 02 Apr 2004 15:22:03 -0600 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i32LTAT9006107 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Fri, 2 Apr 2004 15:29:10 -0600 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i32LR66V012436 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 2 Apr 2004 15:27:06 -0600 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i32LR6cF012434 for notes@kolpackov.net; Fri, 2 Apr 2004 15:27:06 -0600 Date: Fri, 2 Apr 2004 15:27:06 -0600 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040402212706.GA12425@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="KdquIMZPjGJQvRdI" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Fri, 02 Apr 2004 15:23:09 -0600 Subject: c++: smart auto_ptr X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 02 Apr 2004 21:22:05 -0000 --KdquIMZPjGJQvRdI Content-Type: multipart/mixed; boundary="L6iaP+gRLNZHKoI4" Content-Disposition: inline --L6iaP+gRLNZHKoI4 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Good day, Here is the problem. We want to write template class auto_ptr that supports both invasive and non-invasive reference counting. Here is an example: struct counter {}; =20 struct foo : counter {}; struct bar {}; auto_ptr foo_p; // uses invasive counter auto_ptr bar_p; // uses non-invasive counter Of course we don't want to limit ourselves to only one predefined=20 type of invasive counter. In other words this should work too: struct my_counter {}; struct baz : my_counter {}; auto_ptr baz_p; // uses invasive my_counter So how do we go about implementing this? The first idea may be to=20 specialize auto_ptr for different invasive counters and leave non- specialized implementation to handle the non-invasive case: template struct auto_ptr { auto_ptr () { cerr << "non-invasive" << endl; } }; template <> struct auto_ptr { auto_ptr () { cerr << "counter" << endl; } }; template <> struct auto_ptr { auto_ptr () { cerr << "my_counter" << endl; } }; Looks good, right? The only problem with this approach is that it doesn't work. Consider, for example, this: auto_ptr bar_p; Which specialization will be used? The truth is that the primary non-specialized version will be used. Why? Because parameterization inhibits conversion. In our case c++ prefers=20 instantiation of the primary template with x =3D bar to implicit conversion of bar to counter and instantiation of specialization with x =3D counter. And this makes sense. So does it mean we cannot do what we want? The answer is we can but we will need far more trickier meta-programming techniques and a c++ compiler that supports typeof keyword (e.g. GNU g++ or Intel c++). Here is how we can do this. The main task is to write a type function that for each argument X returns either * a type from predefined (but open for extensions) set of types if x is implicitly-convertible to one of them * x otherwise Such type function will allow us to distinguish between all invasive cases and the non-invasive case. Suppose we=20 have such a function: template struct type { typedef ... r; }; =20 How can we use it to achieve what we want? Here is how. First of all we will need a helper class that will encapsulate counter management. We will call it a counter management unit or cmu: template struct cmu; Now we will use cmu in auto_ptr implementation and that's where we take advantage of the type function: we instantiate cmu with the invasive counter type, not x (well, it will be x if it is the non-invasive case). template struct auto_ptr { cmu::r> cmu_; }; Do you see how everything falls into places? Now we can=20 specialize cmu for whatever counter type we want: template <> struct cmu { cmu () { cerr << "counter" << endl; } }; The trickiest part is the type function. I guess it is easier to show the code since it speaks for itself. template x test (...); template counter test (counter*); template struct type { typedef typeof (test (reinterpret_cast (0))) r; }; The technique is explained in details in both "C++ Templates" and "Modern C++ Design". In order to extend our design with a new counter type we need to do two things: add another test function and specialize cmu. template my_counter test (my_counter*); template <> struct cmu { cmu () { cerr << "my_counter" << endl; } }; Let's now put everything together and see how it work: int main () { auto_ptr i_p; auto_ptr bar_p; auto_ptr c_p; auto_ptr foo_p; auto_ptr m_p; auto_ptr baz_p; } This program prints the following non-invasive non-invasive counter counter my_counter my_counter which is what we would expect. Attached is the complete source code. hth, -boris --L6iaP+gRLNZHKoI4 Content-Type: text/x-c++src; charset=us-ascii Content-Disposition: attachment; filename="test.cxx" #include using std::cerr; using std::endl; struct counter {}; struct foo : counter {}; struct bar { }; namespace auto_ptr_impl { template x test (...); template counter test (counter*); template struct type { typedef typeof (test (reinterpret_cast (0))) r; }; template struct cmu { cmu () { cerr << "using non-invasive ref counter" << endl; } }; template <> struct cmu { cmu () { cerr << "using invasive ref counter of type 'counter'" << endl; } }; } template struct auto_ptr { auto_ptr_impl::cmu::r> cmu_; }; struct my_counter {}; struct taz : my_counter {}; namespace auto_ptr_impl { template my_counter test (my_counter*); template <> struct cmu { cmu () { cerr << "using invasive ref counter of type 'my_counter'" << endl; } }; } struct fwd; typedef auto_ptr fwd_ptr; struct fwd : counter { fwd_ptr foo () { return fwd_ptr (); } }; int main () { auto_ptr ip; auto_ptr bp; auto_ptr cp; auto_ptr fp; auto_ptr mp; auto_ptr tp; fwd fwd; fwd_ptr fwdp = fwd.foo (); } --L6iaP+gRLNZHKoI4-- --KdquIMZPjGJQvRdI Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQG3aqsiAKQuuCE8dAQIwhQv/eH263T3qQ4HVbSA4aYDqNrCroET63YGD I31KZ7tCWvIoQMSPNrvxsLwx75dyePUq/FZSI6m7Dp51sRkAeszBRt6RSha4FiKE fiqfGTPyh8QCw2cNG6SjuHcOJakkjufcMYZ1PY2OoeymvroC3X34nTBi+C31PlvE HxC8vyjYSS2bS/3bkQV6pV3tSr6d0yF8esJPLnPZFsOicLZ8JziJJxkA7ldsMSle P85pLX1CkkQ57zOWWQ0jZYrc00pApVgZWd8HINpAXsTbDtp23v/HsOlFfgxDsfPH 3oooTUOb7xRXnqiiPTTFm7feEvfJ4eeTVv8tqLaJCbUeRwzqg/IHz3E4IX1OijUE WbX8/zyjjiMwOuwth01KearQo8foElxjm1oEU8GcPn2qGLJDwpMybNPNF/mz+g8X oELYLTPMaaGH5YxdnkLTrL32TCokh82hUvYtsfgZ4RCFsIMKa6xwfWASCn+00O3H clXqWAVsFpyryUUd2ttDjQvKpcD720sn =NLxw -----END PGP SIGNATURE----- --KdquIMZPjGJQvRdI-- From boris@kolpackov.net Fri Apr 09 15:14:04 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1BC2O4-0002Ez-7f for notes@kolpackov.net; Fri, 09 Apr 2004 15:14:04 -0500 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i39KKmT9021114 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Fri, 9 Apr 2004 15:20:48 -0500 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i39KIa6V023417 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 9 Apr 2004 15:18:36 -0500 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i39KIa2R023415 for notes@kolpackov.net; Fri, 9 Apr 2004 15:18:36 -0500 Date: Fri, 9 Apr 2004 15:18:36 -0500 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040409201836.GA23405@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="opJtzjQTFsWo+cga" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Fri, 09 Apr 2004 15:16:25 -0500 Subject: c++: constructor template X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Apr 2004 20:14:06 -0000 --opJtzjQTFsWo+cga Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Good day, There is this interesting technique (or idiom, if you please) that I found a really elegant example of. The code explains it: class auto_lock { template static void unlock (void* p) { reinterpret_cast (p)->unlock (); } public: template auto_lock (x& m) : m_ (reinterpret_cast(&m), unlock_ (&unlock) { m.lock (); } ~auto_lock () { unlock_ (m_); } private: void* m_; void (*unlock_) (void*); }; -boris --opJtzjQTFsWo+cga Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQHcFHMiAKQuuCE8dAQKTegv/axik2p+cawelGqEFKDe7y3jAFL6taFtP w/8eMb6F9VjKnx0J7sbAhCQjmigA97ievl7bZz2lBxEZRGTcmtSkmNLfKCDPcw5+ sh8Lj2qvbPNFksUTqTw+MjQNLj5dmAvN1phSGJ3fO58Jm6kv0Zc32Ho0d+YvGtZV lgU8bUAAR8AUzp2zShCYPbJ8ZWk+0XjTbVXy7TJ7pl3Sta7G4/CvoKBfzIoDJpDW jlE2gR0D4HbIyWfjvfOzYo9S/uXl+BOjyx7KBSxpnyRDp/DI71tscCBNLPvKkxiA JdagNq8HxXTzdypsSfPvhvHbHLHzirkCIye2CANJL3LJnvahvgeRwoCO1bFupqHG za+BjnYScSPLN1WN4Nd4Xv7KS4YOCbMuypiEuPCeP/7Gc7e6JxQbsxfw/FRrp01S nBo2Yis4u/jZ9XVex8v6isIlX5WhovQ6iGhDmi23EWgw7Q50/2i7zUwgae13GcqM ZfBCdRyUkijJzQ5e4M3cMLcl2HA9ok1D =ZuMu -----END PGP SIGNATURE----- --opJtzjQTFsWo+cga-- From boris@kolpackov.net Wed Apr 21 14:30:13 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.24) id 1BGNQD-0000qu-Dg for notes@kolpackov.net; Wed, 21 Apr 2004 14:30:13 -0500 Received: from cepsa.kolpackov.net (root@cepsa.dre.Vanderbilt.Edu [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i3LJbnT9000725 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Wed, 21 Apr 2004 14:37:49 -0500 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i3LJZT6V002116 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 21 Apr 2004 14:35:29 -0500 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i3LJZT1G002114 for notes@kolpackov.net; Wed, 21 Apr 2004 14:35:29 -0500 Date: Wed, 21 Apr 2004 14:35:29 -0500 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040421193529.GA2106@kolpackov.net> References: <20040223222837.GA17775@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="TB36FDmn/VVEgNH/" Content-Disposition: inline In-Reply-To: <20040223222837.GA17775@kolpackov.net> X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.4i X-Mailman-Approved-At: Wed, 21 Apr 2004 15:12:10 -0500 Subject: Re: c++: notes on namespace X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 21 Apr 2004 19:30:13 -0000 --TB36FDmn/VVEgNH/ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Some time ago I wrote: =20 > @@ Namespace models: 'flat' (like std::) and 'tree' (with nested > namespaces). >=20 >=20 > @@ A 'tree' model can potentially be transformed into a 'flat'=20 > model via using-directives. >=20 >=20 > @@ In the 'tree' model the outer namespace is usually for name- > clash avoidance; the inner namespaces are for the concept=20 > grouping. Recently I discovered one interesting advantage of the tree model over the flat model: when you say=20 using namespace std; you make all names in the standard library accessible from this=20 point. When you say using namespace std::mm; you know you have access only to memory-management-related names. In other words, it feels more comfortable to use using-directive in a=20 tree-like namespace organization that in a flat one. -boris --TB36FDmn/VVEgNH/ Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQIbNAMiAKQuuCE8dAQIguAwArneSDEcCA+1S/GUNe6HlLjQ6HJP90w8J VEZbJ2uY8Be8a2I98s8t1BBJ28pqrnM9ak3ht5fnXFVOXq1PUM/lOpU4tdjqKpfZ bEnGChZmVih2YDUAKTjfOnKU3oN7LtSxsRl9SYvm6Qmny3tq/MOXvgGNF++fe2PK CBhOmIYsRIIMhdT6ONFkDfQdPuzUgwBokbppOJ7MkWN906QojIqFvDpY3p7aqtev 81mdqgSOZcXdCaTYeWOSHytBUB5u/I5Ns7X4YeeM0VREFRqFBStA5W0fpQjS5oOB GAyg5fai6v65+FhAHrVfVdWJLuZ4hc9STmZwwmsMul1dpl+aIf7VAk1iaPzjq0Le CwIIha+qW+3Q/WAY4i+ur4KwU7SalUu25uV6GIxO7ZocVW7x7vYwMwSezenR0NxB yhvhSONSYlmFxHH5ZOy4A7rSu65OSvjhfDl4ihSot2oa4px9NWLbfmlyDiGUU/+T pKPP1Kv1fBiFM+yg0XmEdYfZFhfsziF/ =4ApL -----END PGP SIGNATURE----- --TB36FDmn/VVEgNH/-- From boris@kolpackov.net Thu Jul 01 21:51:35 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.34) id 1BgE9H-0005jE-D5 for notes@kolpackov.net; Thu, 01 Jul 2004 21:51:35 -0500 Received: from cepsa.kolpackov.net (adsl-32-223-178.bna.bellsouth.net [67.32.223.178]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i6230Q0Y027758 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 1 Jul 2004 22:00:27 -0500 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i622vWe1007531 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 1 Jul 2004 21:57:32 -0500 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i622vW08007529 for notes@kolpackov.net; Thu, 1 Jul 2004 21:57:32 -0500 Date: Thu, 1 Jul 2004 21:57:32 -0500 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040702025732.GA7516@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="3V7upXqbjpZ4EhLz" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.6i X-Mailman-Approved-At: Thu, 01 Jul 2004 22:06:51 -0500 Subject: c++: inlining code away X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 02 Jul 2004 02:51:37 -0000 --3V7upXqbjpZ4EhLz Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Good day, Sometimes you want the same line of source code to do something in one case and completely disappear in the other. assert() is a good example. The common way of achieving this in a C/C++ environment is to use the preprocessor. With this approach, however, you are stuck with the function call notation. For assert() that's exactly what we need but what if we want code like a + b or even cerr << "allocation " << size << "bytes" << endl; to go away? We could write if_debug (cerr << "allocation " << size << "bytes" << endl;) or something along those lines but it doesn't look very appealing. To restate the problem: can we achieve conditional compilation for operator-based language constructs like cerr << "hello"? The answer could be a do-nothing inline function and a C++ compiler optimization. But will this actually work? That's what we are going to test today. Our example will be a piece of tracing facility I've been playing with lately. One of the requirements were to be able to turn tracing completely off with zero overhead in resulting code. Also I didn't want to pose any notational burden on the user so I decided to provide an interface similar to the one in the iostream library: tout << "operator new (" << size << "): " << p; Even though the code snippet above looks very innocent, there is quite a lot of things going on under the hood. While the inter-workings of the tracing facility is not the topic of this essay, the number of actions performed under the hood is quite relevant to our discussion. Therefore, I am going to provide a quick overview of how everything works. There are two main object involved: a record and a stream. The records are traced into the stream: class record { public: // ... template record& operator<< (x const& arg); }; class stream { public: // ... stream& operator<< (record const& r); }; Having these definitions we can write something like this: stream tout; record r; r << "operator new (" << size << "): " << p; tout << r; Or even this: tout << (record () << "operator new (" << size << "): " << p); It is not exactly what we want, however. We would like the temporary record to be automatically created for us: class stream { // ... private: class mediator { public: mediator (stream& s) : s_ (s) { } ~mediator () { s_ << r_; } stream& s_; record r_; }; friend record& operator<< (mediator const& mc, char const* s) { mediator& m (const_cast (mc)); return m.r_ << s; } template friend record& operator<< (mediator const& m, x const& arg) { mediator& m (const_cast (mc)); return m.r_ << arg; } }; Do you see how this works? Let's start from a simple example and walk through it step-by-step: tout << "hello"; When the compiler sees this line, it must decide which operator<< to call. Let's see what choices it has: stream& stream:: operator << (record const& r); This one doesn't work since "hello" is of type char const [6], not record, and there is no conversion from char const[6] (or decayed char const*) to the type record. record& operator<< (mediator const& mc, char const* s); The second argument matches after decaying to char const*. The first formal argument is of type mediator, the stream can be implicitly converted to the type mediator (see mediator::mediator (stream&)). We've got the match. In order to make the call the compiler creates a temporary of type mediator and passes a const reference to it as the first actual argument. The generated code will be something equivalent to this: { mediator m (tout); operator<< (m, "hello"); } And our original example tout << "operator new (" << size << "): " << p; will be turned into this: { mediator m (tout); operator<< (m, "operator new (").operator<< (size). operator<< ("): ").operator<< (p); } The innocent looking piece of code turned out to do quite a lot: the compiler has to create the temporary (with all the constructors) and then call a number of functions each of which depends on the return value of the previous. Now let's go back to our zero-overhead problem: if we provide a do-nothing inlined implementation, will the compiler be able to optimize the whole thing away? Here is our zero-overhead implementation: class record { public: // ... template record& operator<< (x const& arg) { return *this; } }; class stream { // ... private: class mediator { public: mediator (stream& s) : s_ (s) { } ~mediator () { } stream& s_; record r_; }; friend record& operator<< (mediator const& mc, char const* s) { return const_cast (mc); } template friend record& operator<< (mediator const& m, x const& arg) { return const_cast (mc); } }; Even though it's a do-nothing implementation, we are still performing some initializations and return some values. Therefore, it's not quite obvious that the compiler will be able to figure out that all those actions don't produce anything. Our test case will be a simple function, assembler code of which we are going to inspect: stream tout; int bar (size_t size, void* p) { tout << "operator new (" << size << "): " << p; return 0; } Here is the assembler code for this function when compiled by g++ 3.4.0 with -O2: .globl _Z3barmPv .type _Z3barmPv, @function _Z3barmPv: .LFB1528: .L11: xorl %eax, %eax ret For comparison here is the same function but compiled with -g: .globl _Z3barmPv .type _Z3barmPv, @function _Z3barmPv: .LFB1496: .loc 2 26 0 pushq %rbp .LCFI6: movq %rsp, %rbp .LCFI7: pushq %rbx .LCFI8: subq $72, %rsp .LCFI9: movq %rdi, -24(%rbp) movq %rsi, -32(%rbp) .LBB6: .loc 2 27 0 leaq -64(%rbp), %rdi movl $tout, %esi call _ZN4cult5trace6stream8mediatorC1ERS1_ leaq -64(%rbp), %rdi movl $.LC1, %esi call _ZN4cult5tracelsERKNS0_6stream8mediatorEPKc movq %rax, %rdi leaq -24(%rbp), %rsi .LEHB0: call _ZN4cult5trace6recordlsImEERS1_RKT_ movq %rax, %rdi movl $.LC2, %esi call _ZN4cult5trace6recordlsIA4_cEERS1_RKT_ movq %rax, %rdi leaq -32(%rbp), %rsi call _ZN4cult5trace6recordlsIPvEERS1_RKT_ .LEHE0: jmp .L13 .L16: movq %rax, -72(%rbp) .L12: movq -72(%rbp), %rbx leaq -64(%rbp), %rdi call _ZN4cult5trace6stream8mediatorD1Ev movq %rbx, -72(%rbp) .L14: movq -72(%rbp), %rdi .LEHB1: call _Unwind_Resume .LEHE1: .L13: leaq -64(%rbp), %rdi call _ZN4cult5trace6stream8mediatorD1Ev .loc 2 28 0 movl $0, %eax .LBE6: .loc 2 29 0 addq $72, %rsp popq %rbx leave ret I also ran this test on Intel C++ with the same results. This shows that contemporary compilers are smart enough to make the technique of inlining code away practical. Keep in mind, however, that in order for this technique to work, the compiler should be able too see through function calls until elementary operations. In particular, if you have a call to a non-inline function as part of your expression there is nothing the compiler can do about it except making the call. To illustrate, consider this code fragment: stream tout; char const* foo (); int bar (size_t size, void* p) { tout << foo () << size << p; return 0; } When compiled by gcc 3.4.0 with -O2: .globl _Z3barmPv .type _Z3barmPv, @function _Z3barmPv: .LFB1527: subq $40, %rsp .LCFI0: movq tout(%rip), %rax movq $tout, (%rsp) movq %rax, 8(%rsp) movl tout+8(%rip), %eax movl %eax, 16(%rsp) .LEHB0: call _Z3foov .LEHE0: xorl %eax, %eax addq $40, %rsp ret This is because a C/C++ compiler cannot make any assumptions about arbitrary functions. Using GCC's function attributes we can specify that our function is "pure" and consequently can be called fewer times than the program says: char const* foo () __attribute__ ((pure)); With this hint GCC eliminates the call: .globl _Z3barmPv .type _Z3barmPv, @function _Z3barmPv: .LFB1528: .L11: xorl %eax, %eax ret If you have made it this far, thank you for your time. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. --3V7upXqbjpZ4EhLz Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQOTPG8iAKQuuCE8dAQLlMAv+JmXebG7eHUdTEFhe1uYEElQSNIAks8x8 PlmBxV3XaE9QZRfMQ2dj3rpoP1Qr0QwKWHr5XMsYAlHlUZpMyH/4zbHsjihxsLuv dJd2pNOLNNh9JDQzrvOVUbSBFO/c1VK0BPIE6/SMCYlVkSVL4MqE4XJQMcnrAKqH fo64amGrfeX71xbQTfKRrLHW92y9JQcwp+L9ey4bMPYucv6W/NfH/pci7zDjquKz aGtB1HkzK5iy6qnqABgLkvG7Txf4utX01swS+89cF4RSVgXnAX6pqE0np6ucA2mp 5OGW+GYfeBkk6LMbyYoVnY1me2DES3TFuQnqoMSgFaC8tBlDl78hSABx0c7vDszG SYzFBiLgkngUKaLn+1wy7itrh2clDOPwH8QXzsdqrn2QF7tA1pz25UlBJze9t/AF +/ke/SsQMyLrdtSj29+TAovxICEpnQTSsaSfnHCpIZOf9KlXEbMkTFgdNB5aYfLf zy/ajYo04IqpCQDgxbuIvgGNcqXNNKLI =pNam -----END PGP SIGNATURE----- --3V7upXqbjpZ4EhLz-- From boris@kolpackov.net Wed Sep 01 10:33:34 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.34) id 1C2X77-0003fu-UA for notes@kolpackov.net; Wed, 01 Sep 2004 10:33:34 -0500 Received: from cepsa.kolpackov.net (root@cepsa [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i81Fi4bx024906 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Wed, 1 Sep 2004 10:44:04 -0500 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i81Femgf007692 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 1 Sep 2004 10:40:48 -0500 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i81Fem3O007690 for notes@kolpackov.net; Wed, 1 Sep 2004 10:40:48 -0500 Date: Wed, 1 Sep 2004 10:40:48 -0500 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040901154048.GA7683@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="OXfL5xGRrasGEqWY" Content-Disposition: inline X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.6i X-Mailman-Approved-At: Wed, 01 Sep 2004 10:35:33 -0500 Subject: make: custom up-to-date X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Sep 2004 15:33:35 -0000 --OXfL5xGRrasGEqWY Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Good day, GNU make has only one way of determining up-to-date-ness: modification timestamp. This is an efficient and in most cases sufficient mechanism. But every now and then a situation arises where you want a custom up-to-date check. If such a need is local and you have full control over the makefile fragment then everything can be arranged using so-called "sentinel" file technique. The technique is based on the way make decides when to update targets and whether the targets were actually updated. Consider a small example: foo: foo.o $(CC) -o $@ $^ foo.o: foo.c $(CC) -o $@ -c $< Let's assume both `foo.o' and `foo.c' exist and `foo.c' is older than `foo.o'. After make compares timestamps of `foo.c' and `foo.o' it realizes that `foo.o' should be updated and runs the corresponding command. After the command is successfully completed, make compares modification times of `foo.o' before and after the command execution. If they are the same, make concludes that `foo.o' was up-to-date and there is no need to rebuild anything that depends on it (`foo' in our case). The "sentinel" file technique is based on this before-after comparison. Suppose `foo.c' gets updated frequently but the content of the file often does not change. It would be nice to use custom up-to-date-ness check on this file which will trigger updates only if content of the file has changed. One way to achieve this is to use `foo.c.md5' "sentinel" file: foo: foo.o $(CC) -o $@ $^ foo.o: foo.c.md5 $(CC) -o $@ -c $(<:.md5=) foo.c.md5: foo.c @md5sum $< | cmp -s $@ -; if test $$? -ne 0; then md5sum $< > $@; fi In this example `foo.c.md5' serves two purposes: it keeps the previous md5 hash sum and triggers an update of `foo.o' when the previous and current hash sums do not match. While this example may look neat, it has one problem: it is not user-makefile-transparent. To understand what I mean let's transform our original example above to be a little closer to real life: # Things we cannot change. # foo: foo.o foo.o: foo.c foo.h # Things we can change. # %: %.o $(CC) -o $@ $^ %.o: %.c $(CC) -o $@ -c $< To implement md5-based up-to-date check we need to change this line foo.o: foo.c foo.h to be foo.o: foo.c.md5 foo.h.md5 This is not very practical since it will most likely lead to changes in a lot of user makefiles (even if it is acceptable, sure it would be nice not to have to). It is also bad because we embed a particular method into user makefiles which makes the whole construction very inflexible. The ideal solution would require changes only to the part marked "Things we can change" which is usually located in a common file included by every user makefile. A long story short you can't do it in current GNU make. But we are just a few logical features away from being able to. Right now pattern rules allow you to add prerequisites to the original rule. What's missing is the ability to remove and query prerequisites from the original rule. If we had this ability we would be able to automatically mangle `foo.c foo.h' to become `foo.c.md5 foo.h.md5'. In fact I went ahead and implemented those two features in `bk' patch-set ( http://kolpackov.net/projects/make/bk/ ). Here's how it works: # Things we cannot change. # foo: foo.o foo.o: foo.c foo.h # Things we can change. # %: %.o $(CC) -o $@ $^ %.o: %.c.md5 $$(addsuffix\ .md5,$$^) $$- $(CC) -o $@ -c $(<:.md5=) .PRECIOUS: %.md5 %.md5: % @md5sum $< | cmp -s $@ -; if test $$? -ne 0; then md5sum $< > $@; fi The second pattern rule is where all the action happens. The first prerequisite pattern (`%.c.md5') ensures that we have a `.c' file for every `.o' file. The second prerequisite (`$$(addsuffix\ .md5,$$^)') is where changing `foo.c foo.h' to `foo.c.md5 foo.h.md5' is done. `$$^' expands to the list of prerequisites from the original rule (just like in command script). Note, that we need to escape it so that it will survive the first round of expansions (happens when makefile is read). And the last prerequisite (`$$-') is a special variable that expands to nothing but also removes all the prerequisites that came from the original rule (`foo.c foo.h' in our case). The complete example shown above is available in the `bk5' patch-set. If you have made it this far, thank you for your time. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. --OXfL5xGRrasGEqWY Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQTXtgMiAKQuuCE8dAQJjRgv/faLDeKXgeAWNZxJCmTig/LYt5C8qSgQg MdFTTDFxPO2B8WgwFY+mn8ksMd+UElVAJ0esqHysu6ZjklxY08MvsQ4wPT5Pc/75 T+bNLkeKv5U7Z6gSoaiVLJGRV1n8ljCfULqMcbkHmpkTmQQADboS83gbfncjbYpT VkFtAN5rQoa6f2wdrU2vEhd1xUGTTAD2DV4BpRWVBt5LelxoE1x/6HYvQLmHvRSM zkLic+c1DH+rM23O5LMdD+Cnd4CB5FZSP5/18tzcnwScAsD/A9fd5PHAzn67rR8j EX4daT1OqvGqkobaUz4yV5YgB0jUnbq+cdAPVW08QpN0tcVzAXrGJ9WW4CKC74WV kswek0ckOm5wyVk6rOstEBAyvR45P+08T1JD8IetSaE0deZSbOqxs1XUnG3cTbRN yteouvKS9YUepxVWdlQe+fG2YW1RMniGxajNmBxT/w8QkqlVTVTwjrs2lrxHEtMg wV7/dJWlEH4i9gdDC1sU8Eo4/Kp6YUut =/847 -----END PGP SIGNATURE----- --OXfL5xGRrasGEqWY-- From boris@kolpackov.net Thu Sep 09 10:26:13 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.34) id 1C5QoP-00044g-D9 for notes@kolpackov.net; Thu, 09 Sep 2004 10:26:13 -0500 Received: from cepsa.kolpackov.net (root@cepsa [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i89FcNbx002842 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 9 Sep 2004 10:38:23 -0500 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i89FZ3gf011562 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 9 Sep 2004 10:35:03 -0500 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i89FZ3JZ011560 for notes@kolpackov.net; Thu, 9 Sep 2004 10:35:03 -0500 Date: Thu, 9 Sep 2004 10:35:03 -0500 From: Ian Dunbar To: notes@kolpackov.net Message-ID: <20040909153503.GA11539@kolpackov.net> References: <20040901154048.GA7683@kolpackov.net> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20040901154048.GA7683@kolpackov.net> User-Agent: Mutt/1.5.6i X-Mailman-Approved-At: Thu, 09 Sep 2004 10:29:28 -0500 Subject: Re: make: custom up-to-date X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 09 Sep 2004 15:26:15 -0000 Hi Boris, On your custom up-to-date system there seems to be one small bug/feature. If everything is up to date according to the md5 test, but changed according to timestamps you can end up with this kind of situation: >make md5sum a.c | cmp -s a.c.md5 -; if test $? -ne 0; then md5sum a.c > a.c.md5; fi md5sum b.c | cmp -s b.c.md5 -; if test $? -ne 0; then md5sum b.c > b.c.md5; fi etc.... i.e. On each make invocation, md5sum is always run for every .c file that is "touched" but not "changed". Also you don't get the reassuring "make: `foo' is up to date." message. One possible workaround might be, in the md5 rule, to touch the .c to be the same (older) date as the .md5 as an else part of your if statement. Unfortunately touch doesn't have a use-same-timestamp-as-this-other-file option, so getting the timestamp information might be tricky. Best regards, Ian From boris@kolpackov.net Thu Sep 09 10:31:49 2004 Received: from [129.59.129.74] (helo=skukuza.dre.vanderbilt.edu ident=root) by vj.hostingplus.com with esmtp (TLSv1:DES-CBC3-SHA:168) (Exim 4.34) id 1C5Qtp-0004Cw-GR for notes@kolpackov.net; Thu, 09 Sep 2004 10:31:49 -0500 Received: from cepsa.kolpackov.net (root@cepsa [129.59.129.75]) (authenticated bits=0) by skukuza.dre.vanderbilt.edu (8.12.9/8.12.9/Debian-3) with ESMTP id i89Fhxbx002873 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 9 Sep 2004 10:43:59 -0500 Received: from cepsa.kolpackov.net (boris@cepsa [127.0.0.1]) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) with ESMTP id i89Fedgf011587 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 9 Sep 2004 10:40:39 -0500 Received: (from boris@localhost) by cepsa.kolpackov.net (8.12.9/8.12.9/Debian-3) id i89FedZf011585 for notes@kolpackov.net; Thu, 9 Sep 2004 10:40:39 -0500 Date: Thu, 9 Sep 2004 10:40:39 -0500 From: Boris Kolpackov To: notes@kolpackov.net Message-ID: <20040909154039.GA11575@kolpackov.net> References: <20040901154048.GA7683@kolpackov.net> <20040909153503.GA11539@kolpackov.net> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="2fHTh5uZTiUOsy+g" Content-Disposition: inline In-Reply-To: <20040909153503.GA11539@kolpackov.net> X-Accept-Language: ru, en X-URL: http://kolpackov.net X-PGP-Key-ID: 3072R/AE084F1D X-PGP-Key-FP: F608 942F 312E D82E 5B84 0407 C880 290B AE08 4F1D X-PGP-Key-URL: http://kolpackov.net/pgp/AE084F1D.asc User-Agent: Mutt/1.5.6i X-Mailman-Approved-At: Thu, 09 Sep 2004 10:32:10 -0500 Subject: Re: make: custom up-to-date X-BeenThere: notes@kolpackov.net X-Mailman-Version: 2.1.3 Precedence: list List-Id: notes, ideas, announcements List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 09 Sep 2004 15:31:49 -0000 --2fHTh5uZTiUOsy+g Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Ian Dunbar writes: =20 > On your custom up-to-date system there seems to be one small bug/feature. >=20 > If everything is up to date according to the md5 test, but changed=20 > according to timestamps you can end up with this kind of situation: >=20 > >make > md5sum a.c | cmp -s a.c.md5 -; if test $? -ne 0; then md5sum a.c > a.c.md= 5;=20 > fi > md5sum b.c | cmp -s b.c.md5 -; if test $? -ne 0; then md5sum b.c > b.c.md= 5;=20 > fi > etc.... >=20 > i.e. On each make invocation, md5sum is always run for every .c file that= =20 > is "touched" but not "changed". Well, that's your custom up-to-date check therefore it is run every time the up-to-date-ness is in question. > Also you don't get the reassuring "make: `foo' is up to date." message. That's actually a make bug. > One possible workaround might be, in the md5 rule, to touch the .c to be= =20 > the same (older) date as the .md5 as an else part of your if statement.= =20 > Unfortunately touch doesn't have a use-same-timestamp-as-this-other-file= =20 > option, so getting the timestamp information might be tricky. Actually it does: see -r option to POSIX touch. I just rewrote the command above like this: md5sum $< | cmp -s $@ -; if test $$? -ne 0; then md5sum $< > $@; \ else touch -r $@ $<; fi This is a nice optimization but we should be careful here: we are changing timestamp of a file behind make's back which can back fire (e.g., if we have more than one target built from a particular prerequisite, one via md5 and the other directly). -boris --2fHTh5uZTiUOsy+g Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) iQGVAwUBQUB5d8iAKQuuCE8dAQLwxQv7B5/z5rtOBNf1+W6kEi4ihejqGSA2dMsS PMSpjAuhVYSoDykYjgvAPsDdrWN5CLMVL+ULLANMXXFknvhRdgpYHSv7Awj+2QoW 7LPKgwVmY5pKvfucCYuwbvuH5Eb/HEMj+SOYyMm57AKt37nES+YW6u4R3cAe+k8Z 3S9BWZumDODQwYoGimP4ES60AOSY8al4nlJATILi4AlY8GilcTiSaQvHmhPNW1rR Cj5X9mp4fpzbL5jq8pmhizHSv3U2CY0z9EMGXmE2jdhniM4284aXPu3CG/XWLAvy 5HzKWtsnfcbpWavk5JhirFYY0AGnKg96fYl3SJ35j0qJfmTVo0LJ+kFEiTPkjqXb iVLhkaF/mUPDpKQP5VUpM7Of1ORLnI/B/MpBRXaArSOycchJVqa6KjDm0NRMwd2p VAmugoss7X/KVo62PJCf21EBoeT8XYhUk37QxpTTPbk4JhH8gwDWSvucUNaTsEuy tju3jomghdODjukkdOCTCtLI4ipXZikj =Tt+Z -----END PGP SIGNATURE----- --2fHTh5uZTiUOsy+g--