[std-interval] Parameter passing

first.i.last at comcast.net first.i.last at comcast.net
Wed Apr 5 22:48:47 PDT 2006


 -------------- Original message ----------------------
From: std-interval-request at compgeom.poly.edu
> Send Std-interval mailing list submissions to
> 	std-interval at compgeom.poly.edu
> 
> ------------------------------
> Message: 3
> Date: Tue, 04 Apr 2006 23:20:27 -0600
> From: Alan Eliasen <eliasen at mindspring.com>
> Subject: Re: [std-interval] C++ interval std
> To: For discussions concerning the C++ standardization of intervals
> 	<std-interval at compgeom.poly.edu>
> Message-ID: <4433539B.5000604 at mindspring.com>
> Content-Type: text/plain; charset=us-ascii
> 
> 
> George Corliss wrote:
> >> Lawrence feels strongly that the standard should be to pass by
> >> value.  Intervals are small data structures; by value allows them
> >> to be passed in registers for speed.  That is how the current Sun
> >> C++ compiler works.  There is no reason to follow the C++ complex
> >> standard.  The library is often taken as an example by coders, and
> >> there is no good reason to follow the tradition of C from 20 years
> >> ago that structures should be passed by reference.
> 
> Sylvain Pion wrote:
> > I don't have any strong opinion on this.
> > I only did a very local experiment on some code of mine on x86, and
> > changing to pass-by-value slowed the code down a bit.
> 
>    I was curious to see about the speed difference between passing by
> value and passing by reference, because passing by value always has been
> slower and always *has* to be slower because it (unnecessarily) creates
> a copy of the object when passed in.

No it does not have to be slower.  First, the pass-by-value copies created by 
the constructor can be optimized away in some cases, especially when inlining is 
active.  Second, on primitive architectures such as x86 pass by reference is 
much worse because the compiler cannot create the address of a value in the FPU.  
So it has to copy the values back to the CPU and write them to memory (always a 
BadThing(tm)) typically on the stack.  The region around the top-of-stack 
usually has good cache response so a cache miss will be rare.  But writing a 
value to memory is still expensive.  Then the addrss is passed to the receiving 
routine which copies the values back into the FPU to operate upon them.  
Efficient this is not.

Compare that sequence with the worst case pass-by-value which takes two FPU 
instructions to duplicate a value on the FPU stack.  Those instructions are 
extremely common, and thus heavily optimized.  On the more deeply pipelined FPUs 
with register renaming the copy might take zero time.  If the values are not 
modified the copies might be eliminated completely (by a post-optimizer) even if 
the copy constructor is called and generates the copy instructions.

Optimizing floating point is a treacherous area even within the implementation 
variations of a single generation of a single architecture.  It will never make 
it into the standard because the Committee will almost certainly object to 
mandates that restrict implementor's freedom to implement.

>  I tried three ways on x86_64, gcc

[omitted]

In general these kinds of tests are not useful because they are not reliable 
guidelines.  They rely upon the competence of the compiler which can only be 
determined by inspecting the code generated.

>    There's a bit of noise in the numbers, but passing by value is always 
significantly slower.

On that machine with that compiler.  Others mileage will _certainly_ vary.

>    Also ran on x86 Windows.  Pattern was the same.  With -O2, passing by
> value took about 2.6 times as long!

See what turning off optimizations can do to you?  If you inspect the generated 
code you are going to find lots of silly register transfers.

> 
>    I didn't test passing by pointer, but I can.
> 
>    Passing in unmodifiable objects as constant references when
> appropriate both obviates the need for copying and gives explicit
> const-correctness from the start.  We don't have to worry about
> dereferencing pointers or memory ownership issues.  It's indeed the
> pattern followed by most modern libraries.

Over specification is always a mistake unless the target platform is very 
narrowly defined.  See some of Bernstein's work on optimization wherein the 
comments in the C code are actually the assembly instructions he expects to 
generate on a specific platform.

> ------------------------------
> 
> Message: 4
> Date: Wed, 05 Apr 2006 16:27:51 +1000
> From: Bill Clarke <llib at computer.org>
> Subject: Re: [std-interval] C++ interval std
> To: For discussions concerning the C++ standardization of intervals
> 	<std-interval at compgeom.poly.edu>
> Message-ID: <44336367.9060400 at computer.org>
> Content-Type: text/plain; charset="iso-8859-1"
> 
> Alan Eliasen wrote, On 04/05/06 15:20:
> > George Corliss wrote:
> >>>Lawrence feels strongly that the standard should be to pass by
> >>>value.  Intervals are small data structures; by value allows them
> >>>to be passed in registers for speed.
> [...]
> >    I was curious to see about the speed difference between passing by
> > value and passing by reference, because passing by value always has been
> > slower and always *has* to be slower because it (unnecessarily) creates
> > a copy of the object when passed in.  I tried three ways on x86_64, gcc
> > 3.4.4, linux:
> [...]
> >    To the caller of the functions, it just looks like an ordinary
> > pass-by-value, but is faster, and allows the compiler to catch a lot of
> > types of problems.
> > 
> >    I recommend that for long-term performance and const-correctness,
> > that objects be passed as constant references when possible.
> 
> This experiment is extremely platform specific, as you probably are
> aware.  Most platforms in use today other than x86 will be the other way
> around (add-by-value will be faster than add-by-const-ref).
> (Was this 64-bit code?  I thought x86_64 would be faster with
> pass-by-value since I got the impression the ABI passed parameters in
> registers)

Long doubles won't fit.  And typical argument passing occurs int he CPU 
registers rather than on the FPU stack.

> 
> With inlining then they should be identical (perhaps you could re-run
> your experiment with inlining to verify this?).
> 
> Surely it is possible to permit the implementer to choose the parameter
> passing convention, between pass-by-value and pass-by-const-ref?  It
> should have no visible impact on the programmer which is used.

Exactly.

----------------------------------------------------------------------
> 
> Message: 1
> Date: Wed, 05 Apr 2006 01:02:40 -0700
> From: Steve Clamage <Stephen.Clamage at Sun.COM>
> Subject: Re: [std-interval] C++ interval std
> To: For discussions concerning the C++ standardization of intervals
> 	<std-interval at compgeom.poly.edu>
> Message-ID: <443379A0.7010800 at sun.com>
> Content-Type: text/plain; charset=us-ascii; format=flowed
> 
> Bill Clarke wrote:
> > 
> > Surely it is possible to permit the implementer to choose the parameter
> > passing convention, between pass-by-value and pass-by-const-ref?  It
> > should have no visible impact on the programmer which is used.
> 
> The standard can state, for example, that that whether a parameter is passed 
by 
> value or by reference is implementation-defined, meaning that an 
implementation 
> can choose either and must document the choice. Or it could say that the 
choice 
> is unspecified, meaning that the implementation does not need to document what 
> it does, and does not need to be consistent.
> 
> The choice can have an effect on programmers, however, since the types of the 
> functions
>    interval foo(interval);
>    interval foo(const interval&);
> are different.

This is not an appropriate example.  The counter is as follows:

----- platform1.h, value -----
    typedef  IntervalArg  Interval;

----- platform2.h, ref2const -----
    typedef  IntervalArg  Interval const &;

----- Interval.h, agnostic -----
    interval atan2( IntervalArg Y, IntervalArg X );

----- User.cpp, agnostic -----
    void slope( IntervalArg height, IntervalArg width )
    {
        return atan2( height, width );
    }

This approach gives user code the portability benefit of the argument type with 
no user-level platform dependency.

> 
> 1. If you create a function pointer interval(*)(interval), it cannot be used 
to 
> hold the address of "interval foo(const interval&)". I don't know of a 
> convenient way to deal with this problem, where you need to modify your code 
> based on details of a predefined type.

You don't need to modify code that uses an abstract argument type.  It is rare 
that it matters, but it can for templates, type_info, RTTI, and other 
type-sensitive constructs.  But that can be solved by giving IntervalArg a 
static member such as shown below:

----- platform2.h, ref2const -----
    class IntervalArg {
        interval const & ref_to_const;
        static int /* can't be bool */ const by_value = false;
    };

> 
> 2. The result of typeid(foo) is different in the two cases, which can affect 
the 
> operation of a program.
>      interval bar(const interval&);
>      if( typeid(foo) == typeid(bar) ) ...
> 
> That said, it is already the case that member functions of classes in the 
> standard library are explicitly allowed to vary from the exemplars listed in 
the 
> standard. But the implementation is required to accept code that is valid for 
> the exemplars.

So we provide an exemplar that is abstract and maximize the freedom of the 
implementors.  Note that the definition of IntervalArg might vary based on the 
compile-time switches provided to the translator.

> 
> Example: An implementation can add a default parameter to a class member 
> function. If the standard says this:
>       class Foo {
>       public:
>             fun(int);
>       };
> An implemtation can have this:
>      class Foo {
>      public:
>            fun(int, int=0);
>      };
> According to the standard, the following is valid:
>      Foo f;
>      f.fun(3);
> and indeed that code compiles with the modified implementation.
> 
> Similarly, code that can call one of the versions of the interval function foo 
> above can also call the other version.
> 
> My point is that allowing freedom of implementation is not without 
consequences 
> for C++ programmers, but there is already some precedent for that freedom of 
> implementation. We need to be aware of the potential problems for programmers, 
> and make a considered choice.

Let's not make a choice.  The one of the very worst problems in software 
engineering is premature optimization.  A choice now would be an instance os 
that haste.  Think of parameter typing as subject to delayed evaluation.  It 
should be delayed until the very last moment possible because that is the point 
in time at which the most information is avalable upon which to make a good 
decision.  Up until that point in time we hide the indecision behind an abstract 
type.

> ------------------------------
> 
> Message: 2
> Date: Wed, 05 Apr 2006 11:32:52 +0200
> From: Sylvain Pion <Sylvain.Pion at sophia.inria.fr>
> Subject: [std-interval] passing by value vs reference
> To: std-interval at compgeom.poly.edu
> Message-ID: <44338EC4.4020106 at sophia.inria.fr>
> Content-Type: text/plain; charset=ISO-8859-1; format=flowed
> 
> [ Let me create separate threads of discussion on each point. ]
> 
> 
> Summary of the arguments on this issue:
> 
> 1- pass by value can be faster or slower than pass by reference
>     depending on the processor/ABI.
> 2- pass by value can be faster due to removal of aliasing issues.
> 3- pass by value is safer in general as a programming idiom
>     (an example is operator*= which may need tweaking to protect
>      itself multipliying by *this)

I question this assertion (re safety, I understand op= quite well), but I doubt 
this issue will be decisive, so let's not pursue it until necessary.

> 4- pass by reference is consistent with std::complex

That is not a particularly attractive property.

> 5- having it specified is useful when taking addresses of functions.

That is false.  And having it specified is not neutral either.  It is a 
detriment -- it tends to embed platform degisn decision in user code, which is 
always a Bad Thing(tm).

> 
> 
> Possible solutions, assuming we want a uniform treatment for all
> functions on intervals:
> 
> 1- enforce pass-by-value
> 2- enforce pass-by-ref
> 3- leave freedom for the implementation to choose
> 4- leave freedom for the implementation and have it provide
>     a standard specified way to obtain this information.

5. Provide an abstraction that masks the issue from users so that only those 
concerned with the issue need deal with it, i.e., implementors.

> 
> 
> Now, I assume that users want the best performance on all
> compilers/processors, so I don't like 1 nor 2.
> I also do not see a large need for manipulating function
> pointers for the intervals, I never needed that personnaly
> at least (speak up if you think it is an important use case).
> If there is indeed no large need for these, and given that it
> is always possible (though painful) to write function wrappers
> to get function pointers, then I would prefer 3 to 4.  I think
> the complexity of implementing 4 is not worth it.  Moreover,
> specifying 4- can be proposed later as an addition (e.g. in
> the more general context of the whole standard library).

I agree but for different reasons.  There should be nothing in the standard that 
is no required by standardization.  If explicit manipulation of parameter types 
is perceived to be necessary (it is not so perceived by me), then an explicit 
type is called for.
But there is no showing that such explicit manipulation of parameter types is 
actually called for.  So the standard should use call-by-value syntax and allow 
call-by-ref2const semantics.

> 
> 
> So, as for the proper text in the proposal, let me propose:
> - to have the text of the function prototypes use pass-by-value,
>    as it fulfills the "advocate safer programming style" argument
>    of Lawrence, and it is also shorter.
> - a note at the beginning mentionning that the implementation
>    is free to use pass-by-reference.
> 
> 
> Does this seem reasonnable ?

Yes, but the proposal will need a rationale note explaining that implementors 
are explicitly permitted to vary the parameter handling as necessary to improve 
their quality of implementation.

> ------------------------------
> 
> Message: 3
> Date: Wed, 05 Apr 2006 04:52:50 -0600
> From: Alan Eliasen <eliasen at mindspring.com>
> Subject: Re: [std-interval] C++ interval std
> To: For discussions concerning the C++ standardization of intervals
> 	<std-interval at compgeom.poly.edu>
> Message-ID: <4433A182.7060405 at mindspring.com>
> Content-Type: text/plain; charset=us-ascii
> 
> Bill Clarke wrote:
> > This experiment is extremely platform specific, as you probably are
> > aware.  Most platforms in use today other than x86 will be the other way
> > around (add-by-value will be faster than add-by-const-ref).
> 
>    How can that assertion possibly be made?  As you know, if a parameter
> is passed by value, then the copy constructor is automatically called
> for each object (e.g. twice for an add operator) on function entry, and
> then the destructor is called (twice) on function exit.

Those function calls can be eliminated as unnecessary or optimized away after 
gode generation.  In many cases they will disappear when debugging is turned off 
and full optimization is turned on.

>  The passed-in
> objects should not be modified in the interim.  So pass-by-value
> *always* has completely unnecessary overhead.  There is absolutely no
> reason to copy and subsequently destroy the objects being passed in.
> Passing by constant reference will *always* be faster in this respect,
> as the copy constructors and destructors will never be called.

On some architectures/compilers this is true.  On others it is never true.

> 
>    The architecture doesn't matter.

Sure it does.  If there are no addresses for the memory holds operands for 
arithmetic instructions then mandating the creation of an address triggers huge 
overhead.  Suhc is life on platforms descended from calculator/watch chips.

>  Say, for an addition operator, if
> you pass by value, you're *always* incurring the additional overhead of
> two unnecessary object copies and two unnecessary object destructions.
> There is simply no advantage to pass-by-value over
> pass-by-constant-reference in any way.

On some popular architecture there is a huge advantage in avoiding the defects 
in the architecture.  Not all computer as carefully designed as a PDP-11.  There 
is a strong case for that claim that the most popular architecture wasn't really 
designed -- it "jest growd lak 'at".

>  Your compiler might be smart
> enough to optimize out the copies and destructions, but pass-by-value
> should *never* be faster with a reasonable compiler.

Our definitions of "reasonable" certainly differ.

> 
>    Why would one ever want the compiler to potentially call copy
> constructors and destructors when we *know* they're a total waste of
> cycles?  We can simply prevent that inefficiency in advance for all
> compilers.

Premature optimization cannot be justified no matter how good the underlying 
intentions are.

> 
> > (Was this 64-bit code?  I thought x86_64 would be faster with
> > pass-by-value since I got the impression the ABI passed parameters in
> > registers)
> 
>    As I mentioned in my original message, I did the test with both
> x86_64 code and x86.  The x86_64 code was 64-bit code, and those were
> the numbers cited.

But did you inspect the generated code?

> The difference in performance, as I noted, was even
> greater on the x86.  (Pass-by-value was about 1.7 times slower on
> x86_64, about 2.6 times slower on x86.)  Registers don't enter into the
> picture.

I don't understand that statement.  It is quite contrary to my experience.

>  Pass-by-constant-reference arguments can be passed in
> registers too, of course.
> 
>    The difference is that pass-by-value is likely to perform unnecessary
> copy constructors and unnecessary destructions.  There is simply no
> advantage to this, when we can be smart and tell even the dumbest
> compilers that these copying and destroying operations should never even
> be attempted.  Silly, useless performance problems (e.g. unnecessary
> copy constructor calls) will be avoided in advance.  That's a good thing.

That's what code optimizers are for.  These days they are quite smart about 
fixing the kind of simple inefficiencies you have mentioned.

> 
> > With inlining then they should be identical (perhaps you could re-run
> > your experiment with inlining to verify this?).
> 
>    The constructor was inlined.  I fail to see how inlining could ever
> make pass-by-value faster, as it always has unnecessary overhead.  A
> smart compiler could make it *as* fast as pass-by-constant-reference,
> but I can't see how it could ever make it faster.

Then try the experiment and see what happens to the inlined code sequence.  It 
can be quite a bit smaller/faster than an outlined function.

>  Specifying
> pass-by-constant-reference would simply eliminate a source of
> inefficiency with broken compilers.
> 
> > Surely it is possible to permit the implementer to choose the parameter
> > passing convention, between pass-by-value and pass-by-const-ref?  It
> > should have no visible impact on the programmer which is used.
> 
>    I agree that it should have no visible impact on the library user.
> But there is really no reason to *not* use pass-by-constant-reference.

If the argument for pass-by reference is so compelling than we should trust the 
implementors to be so compelled.  Otherwise the proposal should mandate either 
LSB-first or MSB-first memory layouts.  Anyone up for a food fight?  ;-) 

>  Even if you are doing lazy operations and need to modify some part of
> the passed-in object, you can always use the "mutable" keyword.
> 
>    In short, if you can find a compiler that does pass-by-value faster
> than pass-by-constant-ref, I'll show you a broken compiler.
> 
>    Specifying pass-by-constant-reference also allows the compiler to
> detect and prevent accidental modification of the objects being passed
> in, or erroneous programmer attempts to modify a passed-in object (which
> is probably never what you want to do, and should always fail.)
> 
>    Const-correctness is also a desirable goal, in my opinion.  It
> becomes prohibitive and breaks code to add const-correctness late in the
> game, which is why we should get it right the first time.

Const correctness should be a requirement.  But that does not have any effect 
upon calling conventions because both conventions can be const-correct.

> ------------------------------
> 
> Message: 6
> Date: Wed, 05 Apr 2006 04:51:32 -0700
> From: Steve Clamage <Stephen.Clamage at Sun.COM>
> Subject: Re: [std-interval] C++ interval std
> To: For discussions concerning the C++ standardization of intervals
> 	<std-interval at compgeom.poly.edu>
> Message-ID: <4433AF44.8020308 at sun.com>
> Content-Type: text/plain; charset=us-ascii; format=flowed
> 
> Alan Eliasen wrote:
> > Bill Clarke wrote:
> > 
> >>This experiment is extremely platform specific, as you probably are
> >>aware.  Most platforms in use today other than x86 will be the other way
> >>around (add-by-value will be faster than add-by-const-ref).
> > 
> > 
> >    How can that assertion possibly be made?  As you know, if a parameter
> > is passed by value, then the copy constructor is automatically called
> > for each object (e.g. twice for an add operator) on function entry, and
> > then the destructor is called (twice) on function exit.
> 
> A simple object like complex or interval should have no user-defined copy 
> constructor or destructor.

A desirable property, but unnecessarily restrictive.  In particular interval 
objects with explicit properties might not be PODs.  Histories of dependencies 
and restartable evaluations require pointers.  Pointer members will require an 
intelligent copy ctor and a deep dtor (modulo reference counting).

> That is, the default copy constructor generated by 
> the compiler does the right thing and does not need to be user-defined. The 
> destructor has nothing to do, and so should not be user-defined. In that case, 
> pass-by-value can be optimized into register passing with no additional 
copying.

That makes sense for PODs.  But any non-trivial imeplentations will not be able 
to use POD representations without fantastically high performance cost.

> ------------------------------
> 
> Message: 7
> Date: Wed, 05 Apr 2006 13:55:35 +0200
> From: Guillaume Melquiond <guillaume.melquiond at ens-lyon.fr>
> Subject: Re: [std-interval] C++ interval std
> To: std-interval at compgeom.poly.edu
> Message-ID: <1144238135.1575.25.camel at localhost>
> Content-Type: text/plain; charset=ISO-8859-1
> 
> Le mercredi 05 avril 2006 à 04:52 -0600, Alan Eliasen a écrit :
> > Bill Clarke wrote:
> > > This experiment is extremely platform specific, as you probably are
> > > aware.  Most platforms in use today other than x86 will be the other way
> > > around (add-by-value will be faster than add-by-const-ref).
> > 
> >    How can that assertion possibly be made?  As you know, if a parameter
> > is passed by value, then the copy constructor is automatically called
> > for each object (e.g. twice for an add operator) on function entry, and
> > then the destructor is called (twice) on function exit.  The passed-in
> > objects should not be modified in the interim.  So pass-by-value
> > *always* has completely unnecessary overhead.  There is absolutely no
> > reason to copy and subsequently destroy the objects being passed in.
> > Passing by constant reference will *always* be faster in this respect,
> > as the copy constructors and destructors will never be called.
> 
> Please note that our proposed interval type is meant to be a POD (plain
> old data) type and as such has no copy constructor nor destructor.

Is it your plan that the proposal include the POD-only requirement?  I would 
suggest that it is an obvious possibility that yeilds good performence 
improvements, but how important is it to get fat intervals quickly?

I would must prefer not to see such a requirement in the standard.

> As a
> consequence, on some architectures and with non-broken compilers, they
> will behave no differently than if the function arguments were simply
> integers; except that the register will probably be bigger, or two
> registers will be used. When this happens, passing by value will be
> faster than passing by const-reference. Indeed there is no architecture
> such that foo(int) is slower than bar(int const &).

Of course there is.  When addresses are narrow (fit in a register) and ints are 
wide (don't fit in a register).  64-bit code on 32-bit hardware.  32-bit code on 
16-bit hardware.  16-bit code on 8-bit hardware.  I've even worked on a 
bit-slice machine with 20-bit ints and 16-bit addresses.

----------------------------------------------------------------------
> 
> Message: 1
> Date: Wed, 05 Apr 2006 14:05:54 +0200
> From: Guillaume Melquiond <guillaume.melquiond at ens-lyon.fr>
> Subject: Re: [std-interval] passing by value vs reference
> To: std-interval at compgeom.poly.edu
> Message-ID: <1144238754.1575.37.camel at localhost>
> Content-Type: text/plain; charset=ISO-8859-1
> 
> Le mercredi 05 avril 2006 à 11:32 +0200, Sylvain Pion a écrit :
> 
> > 3- leave freedom for the implementation to choose
> > 4- leave freedom for the implementation and have it provide
> >     a standard specified way to obtain this information.
> 
> > I would prefer 3 to 4.  I think
> > the complexity of implementing 4 is not worth it.
> 
> I don't see any additional complexity in 4 with respect to 3. As already
> mentioned by Bill Clarke, you could simply have a typedef member in
> interval<T> to express the calling convention of the functions of the
> interval library: typedef interval<T> const &param_type;
> 
> This requires all the functions of the library to use the same calling
> convention.

How do you derive this requirement?  I don't see it.

> ------------------------------
> 
> Message: 2
> Date: Wed, 05 Apr 2006 05:24:54 -0700
> From: Lawrence.Crowl at Sun.com
> Subject: Re: [std-interval] C++ interval std 
> To: For discussions concerning the C++ standardization of intervals
> 	<std-interval at compgeom.poly.edu>
> Message-ID: <200604051224.k35COsbd029560 at philmont.sfbay.sun.com>
> 
> Alan Eliasen <eliasen at mindspring.com> writes:
>  >   I was curious to see about the speed difference between passing by
>  >value and passing by reference, because passing by value always has been
>  >slower and always *has* to be slower because it (unnecessarily) creates
>  >a copy of the object when passed in.
> 
> It does not unnecessarily create an object.  In particular, when the
> parameter to a function is the result of an expression, the const ref
> approach requires allocating a temporary and passing its address.  In
> contrast, pass-by-value can put the result of the expression directly
> into the parameter register; no copies are required.
> 
> Pass-by-reference aften introduces additional copies because the
> programmer must copy the parameter into a local variable in order to
> avoid aliases between parameters.
> 
>  >I tried three ways on x86_64, gcc 3.4.4, linux:
> 
> I would need the benchmark source in order to evaluate it and to
> execute it on other systems.
> 
> In developing the SPARC V9 ABI, I showed a 7x performance advantage for
> pass-by-value over pass-by-reference when computing Mandelbrot with
> complex numbers.

This is easily understandable for narrow function interfaces.  When the register 
set gets.  But the C99 suite of functions have up four fp arguments.  For quads 
it would be 128*2*4 = 1024 bits.  That's a lot of registers even at 64 bits 
each.  And even more of a concern on some of the crippled architectures still in 
use.

> 
>  >   Passing in unmodifiable objects as constant references when
>  >appropriate both obviates the need for copying and gives explicit
>  >const-correctness from the start.  We don't have to worry about
>  >dereferencing pointers or memory ownership issues.  It's indeed the
>  >pattern followed by most modern libraries.
> 
> You are assuming that "const" means "unmodifiable".  It does not.  It
> means that non-mutuable fields may not change when accessed through the
> const-qualified name.  The object may still change via access through
> non-const-qualified names.  The distinction between a value and a
> reference is critical here, because the former is unaliased and the
> latter is potentially aliased.  This aliasing can also have substantial
> effect on the ability of the compiler to apply global optimizations.
> 
>  >   To the caller of the functions, it just looks like an ordinary
>  >pass-by-value, but is faster, and allows the compiler to catch a lot of
>  >types of problems.
> 
> But it doesn't look the same, because of the aliasing issue.  With
> reference parameters, the function must make an explicit declaration
> about its behavior in the presence of aliasing.

That is an aspect of the language rather than the implementation.  Are we 
setting out to fix the aliasing problem WRT intervals?  It would be a huge 
change in scope.

> 
>  >   I recommend that for long-term performance and const-correctness,
>  >that objects be passed as constant references when possible.
> 
> Would you recommend that ints be passed by const reference?

Rarely.  But I would resist the argument that it is never necessary.
> ------------------------------
> 
> Message: 3
> Date: Wed, 05 Apr 2006 05:49:41 -0700
> From: Lawrence.Crowl at Sun.com
> Subject: Re: [std-interval] Re: C++ interval std
> To: For discussions concerning the C++ standardization of intervals
> 	<std-interval at compgeom.poly.edu>
> Message-ID: <200604051249.k35Cnfbd008613 at philmont.sfbay.sun.com>
> 
> first.i.last at comcast.net writes:
>  >> Lawrence feels strongly that the standard should be to pass by
>  >> value.  Intervals are small data structures;
>  >
>  >That perspective causes problems, just as it did for complex.
>  >Intervals should be considered atomic types whose internal structure
>  >is opaque.  We don't consider fp types as structures even though they
>  >consist of three distinct fields (and in fact are t reated as separate
>  >fields in software implementations of the run-time library).
> 
> The issue was the mechanism for passing the representation, not the
> logical opacity of the type.

The issue is the atomicity of the type.  Atomicity often implies effective 
opacity.  Opacity always implies atomicity.

In a few years we will expect to see hardware supporting native intervals types 
(the design papers have been around for decades).  At that point intervals are 
no longer "small data structures" as you described them.  They are native types.  
As soon as there are two dissimilar hardware implementations in existence all 
arguments about the internals of the representation leave the standard.

FP layouts are famous for being diverse.  There is almost every possible byte 
ordering available for 32-bit values.  We should not expect that historical 
trend to vanish even though it would make everyone's life easier.

So we should not predicate premature design decision on the current state of the 
art when we plan to drive a vigorous change process.

> 
>  >> by value allows them
>  >> to be passed in registers for speed.  That is how the current Sun
>  >> C++ compiler works.  There is no reason to follow the C++ complex
>  >> standard.  The library is often taken as an example by coders, and
>  >> there is no good reason to follow the tradition of C from 20 years
>  >> ago that structures should be passed by reference.
>  >
>  >There may or may not be a good reason for it.  On FPUs with weak
>  >connections to the CPU, such as x87, passing by value is strongly
>  >preferred.  Yet on FPUs with strong connections to the main CPU
>  >passing by reference might be much more efficient.
> 
> I don't follow the reasoning here.

To create a reference on weakly connected systems one must copy from the FPU to 
addressable memory, create the address in the CPU, pass the address to the 
recipient function and then copy the values from memory back into the FPU.

On strongly connected systems where there is one stack containing intergers, fp 
values, and addresses one simply passes the address of the fp values without 
moving them.

The effect of aliasing is irrelevant because we should be most concered with the 
passage of parameters during expression evaluation where there are cannot be 
aliases because there are no references or pointers to temporary objects.

> 
>  >If the standard syntax is pass by value then a compiler that prefered
>  >pass by reference would be free to do so internally (assuming
>  >appropriate referential safe guards).
> 
> SPARC V7 (32-bit) does in fact do this.  SPARC V9 (64-bit) does so
> for large structs, but passes in registers for small structs.

I'm certain Sun is not alone in that.  Watcom C/C++ provides explicit control 
over the passing conventions right down to individual function prototypes.

>  >> Pass-by-value is also a correctness issue.
>  >
>  >How so?
> 
> Because users will copy the style of interval function declarations.
> If that style includes reference paramters, the programmers will litter
> their programs with unintended aliases.  These aliases are the source of bugs.

OK, we appear to be agreed that the _syntax_ of parameter passing should not 
contain explicit references.  But implicit references, i.e., the semantics of 
parameter passing, whether via an explicit abstract type for interval parameters 
or by hidden manpilation by the compiler, are not affected by this issue.

> ------------------------------
> 
> Message: 7
> Date: 05 Apr 2006 15:37:20 +0200
> From: Gabriel Dos Reis <gdr at integrable-solutions.net>
> Subject: Re: [std-interval] passing by value vs reference
> To: For discussions concerning the C++ standardization of intervals
> 	<std-interval at compgeom.poly.edu>
> Message-ID: <m3d5fwcfe7.fsf at uniton.integrable-solutions.net>
> Content-Type: text/plain; charset=iso-8859-1
> 
> Guillaume Melquiond <guillaume.melquiond at ens-lyon.fr> writes:
> 
> | Le mercredi 05 avril 2006 à 11:32 +0200, Sylvain Pion a écrit :
> | 
> | > 3- leave freedom for the implementation to choose
> | > 4- leave freedom for the implementation and have it provide
> | >     a standard specified way to obtain this information.
> | 
> | > I would prefer 3 to 4.  I think
> | > the complexity of implementing 4 is not worth it.
> | 
> | I don't see any additional complexity in 4 with respect to 3. As already
> | mentioned by Bill Clarke, you could simply have a typedef member in
> | interval<T> to express the calling convention of the functions of the
> | interval library: typedef interval<T> const &param_type;
> 
> If done that way, in the typical cases, the "T" would then appear in
> non-deducible context. 

It need not be a dependent type.  It could easily by a parallel set of 
templates.

========================

-- Lee Winter

P.S.  Does anyone know how I can get out of digest mode?


More information about the Std-interval mailing list