Prev: Generating a derived class from a base class
Next: Why is the return type of count_if() "signed" rather than "unsigned"?
From: Andre Kaufmann on 7 Jul 2010 12:56 Mathias Gaunard wrote: > On Jul 7, 3:21 am, Andre Kaufmann <akfmn...(a)t-online.de> wrote: > >> Function objects yes. But the C++ compiler hasn't any notion of semantic >> of the function (internals) anymore - it has generated code. > > I do not really understand what you're talking about, and neither why > it would be a problem. Hope some additional samples will make it clear. > >> You can't (that easily) pass function objects to another function > > There is nothing hard about it. Besides I have to use typed parameters. (see sample composition below) > [...] >> use pattern matching (e.g. if parameter number2 is of type int and has >> value 5 then emit that code). > > Pattern matching is a feature of sum types, not of functions. They are > tagged unions of different possible types, and pattern matching is a > process that happens at runtime. I think it's rather comparable to template specialization (at least in F#) Sample: F# pattern matching let f x = match x with | int -> "integer" | _ -> "other" let value = f 8 printfn "%A" value Prints: "integer" The compiled code results to the following pseudo code: value = "integer"; print(value) Definitively (in this case) it's statically matched. >> It's more like a mixture of C++ templates >> and delegates, but without the restrictions. Sorry meant, lambda functions instead of delegates. > I don't get what that is about. Another sample: F# let Compose f1 f2 = let ret = fun n -> f1(f2 n) ret let Double x = x * x let Tripple x = x * x * x let DoubleTripple x = Compose Double Tripple x let result = DoubleTripple 3 printfn "%A" result Function DoubleTripple parameter is not typed: I can call DoubleTripple with an integer or with an double. The best equivalent in Cpp I could get compiled is: template <typename T, typename f1, typename f2> std::function<T(T)> Compose(f1 foo1, f2 foo2) { return [&] (T n) { return foo1(foo2(n)); }; } void foo() { auto Double = [] (int x) { return x * x; }; auto Tripple = [] (int x) { return x * x * x; }; auto DoubleTripple = Compose<int>(Double, Tripple); printf("%d\r\n", DoubleTripple(3)); } How do I get rid of the type [int] ? I could wrap the functions Double and Tripple in template functions too, but how do I combine 2 functions with Compose, without specifying a type ? I tried to get a compilable template function of Compose with a combination of "auto" and "decltype" to forward the type, but couldn't get it compiled, without specifying the parameter type. >> Besides that it's more compact to write: >> >> Example: >> >> let r f(x, y, z) = fx + fy + fz; > > I do not know what this syntax is supposed to do. Should do the same as the Cpp sample ;-) > This is not valid OCaml for example. Sorry haven't specified the language. It's F# code. Since F# is derived from OCaml and ML I often write code, which isn't compilable in OCaml (anymore). Unfortunately there is a typo anyways: Should read: let r f x y z = f x + f y + f z > >> would be something like: >> >> template <typename T, typename F, typename X, typename Y, typename Z> >> T r(F function, X x, Y y, Z z) >> { >> return function(x) + function(y) + function(z); >> >> } > > Well yeah, when you name the function "function", the code tends to be > more verbose than when you name it "f" ;). Sorry wasn't my intention. But anyways C++ is too verbose. Why can't I write instead of: template <typename T, typename F, typename X, typename Y, typename Z> simply: template <T, F, X, Y, Z> ? If there are ambiguities, they should be prevented by adding a keyword, to the rare cases, which might cause ambiguities. > [...] >> Hm, but this ABI standard (wasn't aware of it) isn't part of the C++ >> standard ? > > No it isn't, it's an industry standard. Would be more "pushing" for compiler vendors to implement it, if it would be part of the C++ standard. > [...] >> But any "basic open (C++) ABI standard" for each platform should exist >> and supported by all C++ compilers for this platform. > > Isn't that basically the state of things? > All platforms follow the Itanium C++ ABI adapted to their Is it really the case that all platforms (ARM , Apple etc.) adapted the Itanium C++ ABI ? > architecture, except the windows platforms that follows the Microsoft > ABI. As I wrote, I don't know if its necessary for Microsoft to follow this ABI standard. But anyways there should exist an ABI standard for Windows, which each compiler for Windows should follow. Additionally I think it's somewhat easier to change the current ABI standard on an Open Source system, rather than on a commercial closed source one, because all necessary libraries can be recompiled to be ABI compatible more easily under e.g. Linux, since the sources are available. Andre -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Walter Bright on 7 Jul 2010 22:14 Dragan Milenkovic wrote: > GCC features precompiled headers for C++. I believe it solves > all mentioned problems. Precompiled header compilers for C++ have been around for 20 years. http://www.digitalmars.com/ctg/precompiled.html If it could solve the compile speed problems, it would have by now. The other problem pch files have is there is no way to implement them in a Standard conforming manner. > One question - how do D modules get along with templates? In order to instantiate a template, the template body must be available in one form or another. Hence, D imports include the template bodies. The speedup comes from, as Andre pointed out, each import only has to be compiled once per project rather than once per source file. (Exported templates were an attempt to graft import semantics onto the preprocessor based C++ compilation model. That design was a disaster. It doesn't mean imports cannot be integrated in with C++, but it does mean it'll be a difficult design job.) -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Walter Bright on 7 Jul 2010 22:16 Ian Collins wrote: > On 07/ 8/10 08:16 AM, Walter Bright wrote: >> Mathias Gaunard wrote: >>> I personally don't understand the point of non-recoverable exceptions >>> at all. If they're non recoverable, it means it is something that >>> should *never* happen, and therefore is a bug in the program itself. >>> The program might as well abort and terminate directly. Trying to >>> clean up in the face of something that should never happen in the >>> first place cannot work, and might actually lead to even more errors. >> >> Yes, you're quite right. >> >> Being able to catch them, however, can make debugging a program easier. > > Isn't a breakpoint on abort() a better alternative? I wouldn't want any > unwinding or object clean-up to occur under those conditions. Along > with the risk of more damage being done, valuable state information may > be lost. Usually, yes, a breakpoint is better. But consider what a breakpoint is - it's a debugger installing an exception handler! A debugger is sometimes not available, and so it's nice to be able to build in a bit of debugger capability into the program. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: lucdanton on 7 Jul 2010 22:33 On Jul 8, 5:56 am, Andre Kaufmann <akfmn...(a)t-online.de> wrote: > Mathias Gaunard wrote: > [snip] > The best equivalent in Cpp I could get compiled is: > > template <typename T, typename f1, typename f2> std::function<T(T)> > Compose(f1 foo1, f2 foo2) > { > return [&] (T n) { return foo1(foo2(n)); }; > > } > > void foo() > { > auto Double = [] (int x) { return x * x; }; > auto Tripple = [] (int x) { return x * x * x; }; > auto DoubleTripple = Compose<int>(Double, Tripple); > printf("%d\r\n", DoubleTripple(3)); > > } > > How do I get rid of the type [int] ? I could wrap the functions Double > and Tripple in template functions too, but how do I combine 2 functions > with Compose, without specifying a type ? > I tried to get a compilable template function of Compose with a > combination of "auto" and "decltype" to forward the type, but couldn't > get it compiled, without specifying the parameter type. > [snip] C++0x: template<typename F1, typename F2> auto compose(F1&& f1, F2&& f2) -> decltype( std::bind(std::forward<F1>(f1), std::bind(std::forward<F2>(f2), std::placeholders::_1)) ) { using std::placeholders; return std::bind(std::forward<F1>(f1), std::bind(std::forward<F2>(f2, _1)); } How about that for verbosity (and duplication) ? We can only hope that we will one day have true type inference (just auto prototype(Type t, ..) without the "-> ret_t" late return specifier) ;). I suppose it could easily come as an extension and once popular be enshrined in the standard... Also note that formally there is no guarantee that this code will do as advertised: while the return type of std::bind is specified as implementation-defined (instead of say, std::function<>), it could still do type-erasure (like, say, std::function<>). I know that the libstdc++ does use a functor template so all the signature (incl. return type) is part of the type of what is returned. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Edward Rosten on 9 Jul 2010 23:04
On Jul 6, 8:27 pm, Walter Bright <newshou...(a)digitalmars.com> wrote: > Without support for transitive immutability of the pure function's arguments, I > don't see how the compiler can verify purity. > > C++ const falls short in 3 areas: > > 1. It is only a single level. Const applied to a type does not recursively apply > to any types that are embedded within that type. I.e. it's not transitive. Indeed. There have been a number of discussions about why it doesn't work properly for slice types, especially with templates, since the compiler is only happy to add const in an inappropriate place. All the solutions revolve around having uglier, more verbose and therefore harder to read code, or code which the compiler cannot properly check. And that ignores the following points, too. > 2. Const is a read-only view of the data, it does not apply to the data itself - > there's no commitment that there may be another, non-const, mutating reference > to the same data. (When using const as a type constructor, not as a storage class.) > > 3. Const may be legally cast away and the underlying data mutated. (When using > const as a type constructor, not as a storage class.) > > Without transitive immutability of the pure function arguments, there's no way > to guarantee that two calls to the pure function with the same arguments will > produce the same result. Indeed. Basically, the C++ type system, including const allows one to use the compiler to make sure certain classes of error can never happen. Pure functions will help this by adding expressiveness. In fact, I would argue that most of the time that const is used, what is actually wanted is pure. Also, it is not like C++ programmers are even remotely unfamiliar with the concept. In the template language, there is no way of generating side effects at all. In many ways, this makes template code easier to reason about. I mean it would make no sense whatsoever to have: foo<int> a; foo<int> b; a and b being different types. In many, many cases, it makes just as little sense to allow the same with data. Finally, I agree that code reviews are not a solution. The compiler is better, faster and more accurate and I personally do not have anything like the resources to have my code reviewed to ensure purity correctness. -Ed -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |