From: Andre Kaufmann on
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
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
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
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
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! ]