[std-interval] PODs and parameter passing

Gabriel Dos Reis gdr at integrable-solutions.net
Fri Apr 7 00:06:44 PDT 2006


first.i.last at comcast.net writes:

[...]

| > | > The proposal would need to be precise about whether internal<T> is a
| > | > POD or not; that is unavoidable.
| > | 
| > | Why?
| > 
| > because if the proposal is accepted, it is going to be part of a much
| > larger context.  They are some operations on can do on types depending
| > on whether they are PODs or not, like offsetof, initializations and
| > other fine details.  The standard needs to say whether such operations
| > are permitted or not.
| 
| OK, I did not ask a sufficiently precise question.  Why is
| "implementation defined" unacceptable?  I.e., why does PODness have
| to be a constant for all implementations? 

Because whether the operations in question are permitted or not would
depend on the compiler; I don't see any compelling reason for that
sort of non-portability.

| I hope offsetof() is not going to be used much on intervals. 

It is a reasonable hope; others have other reasonable expectations
too.  The question is not whether it would be used "too much", but
whether it should be permitted at all.  I can see arguments both
ways; but none that convinces me of the non-portability you suggest.

| There
| would be little point in scrounging around inside an interval unless
| you are trying to cause (yourself) some trouble. 

That is your expectation; others expect to "serialize" things, using
offsetof among other things -- and we do have an open issue with
std::complex for example, from various point of view.

| Initialization of an interval is almost certainly going to require a
| ctor due to the problem of compiler mangling of literal constants,

I'm sorry; I don't see the connection.  Could you elaborate?

| so for purposes of initialization intervals aren't going to behave
| like PODs even if they are PODs. 

I don't see why.

| Can you think of any other fine details (other than things like
| binary IO) that might influence the preference for PODs over "real"
| objects? 

It all depends on the degree of non-PODness; there are ABIs out there
on popular platforms that make optimization decisions based on degree
of PODness.

[...]

| > | > | > 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.
| > | > 
| > | > Yet, at the end of the day the proposal needs to spell out the
| > | > mechanism for passing the representation.  At the moment, I don't see
| > | > how the committee would buy a proposal that is very vague about such
| > | > issue.  Past experience with vagueness in that area has been a fertile
| > | > source of programmer confusion, and defect reports (that the committee
| > | > had to deal with).
| > | 
| > | Is an abstract type for parameters vague?
| > 
| > In C++, there is the notion of "abstract class" but I doubt that is
| > what you were refering to.  One has to be more specific than general
| > terms; this is not a language independent specification.
| 
| Abstractions hide implementation details.  The previous suggestion
| (yours?) of interval::param_type

(no, it was not mine)

| would hide either "interval const
| &" or "interval" type definitions.  That would certainly be usefu,
| but  dependent types are problematic.  The only variation I'm
| suggesting is to make that parameter type independent of the
| interval template type. 

and that begs the question of to what degree the problem worths that
level of complexity.  

[...]

| > | ----- interval.h -----
| > |     template< T > struct Interval    { ... };
| > |     template< T > struct IntervalArg { ... };
| > 
| > That is half of it; the other half is how are they used concretely in
| > specifying function parameters?  That is the most interesting bits.
| > Please don't be afraid to be concrete, otherwise I fear we would not
| > communicate effectively: the issue at hand is too concrete.
| > 
| > | Such an abstraction would require each implementor to document the
| > | calling convention actually used so that interfacing with other
| > | languages was possible, but implementations already have to document
| > | all kinds of calling convention properties of which parameter
| > | passing is only one. 
| > 
| > How is IntervalArg<T> is different from IntervalArg<T>?  What do they
| > contain? 
| 
| OK, I'll bite.  For this discussion assume Interval<T> is the same
| as the existing proposal.  If Interval<T> were not a template, say
| intervalf, interval, and intervalld, and intervalq in C99-style
| naming,  then we would use intervalf_arg_t, interval_arg_t,
| intervalld_arg_t, and intervalq_arg_t as corresponding argument
| types.  They would be implementation defined.  Everywhere that one
| wanted to pass in interval argument one would use the corresponding
| *arg_t to maintain platform optimization agility. 
| 
| But Interval is going to be a template.  It is tempting to want to
| derive the argument type, hre named IntervalArg from the value type
| Interval.  But templates ahve weaknesses, one of which inhibits that
| derivation. 
| 
| So I'm suggesting an independent template.  In crudest terms it
| would be something like this : 
|     
| namespace pbr {
| 
|     template< typename T >
|     struct IntervalArg { typedef T const & _t; };
| 
|     struct IntervalArg<float>
|     { typedef Interval<float> const & _t; };
| 
|     struct IntervalArg<double>
|     { typedef Interval<double> const & _t; };
| 
|     ... ditto for other fp types
| 
| } // pbr
| 
| namespace pbv {
| 
|     template< typename T >
|     struct IntervalArg { typedef T const & _t; };
| 
|     struct IntervalArg<float>
|     { typedef Interval<float> _t; };
| 
|     struct IntervalArg<double>
|     { typedef Interval<double> _t; };
| 
|     ... ditto for other fp types
| 
| } // pbv
| 
| In use it would be a bit ugly:
| 
|     using namespace pbv; // or pbr
|     template< typename T >
|     Interval<T> agile_func( IntervalArg<T>::_t arg1 ) { ... }

Now, I can't call agile_func() using the "natural" syntax; I have to
explicitly specify the argument type.  It is a clutter and a level
of complexity that I'm having trouble finding convincing justification
for. 

| A subtlety that may not be immediately apparent is that the purpose
| of the unspecialized template is to address contexts in which a
| template parameter T represents an interval type, whose base type is
| not specific.  Thus: 
| 
|     template< typename T /* in truth Interval<U> */ >
|     struct userdefined {
|         ...
|         T interval_func( IntervalArg<T>::_t arg );
|         ...
|     }; // userdefined
| 
| A more complex implementation would eliminate the unsightly ::_t
| along the lines of a proxy type.  It would rely upon the compiler to
| optimize away all of the bookkeepping: 

So now, we have to add increasing levels of complexity to "solve"
something I'm not sure is a problem.  Simple things should be simple.

| namespace pbr {
| 
|     template < typename T >
|     struct IntervalArg {  // for discussion purposes only
|         IntervalArg( Interval<T> arg )
|         : ref_( val )
|         {}
|         operator Interval<T> () const
|         { return ref_; }
|     private:
|         Interval<T> const & ref_;
|     };
| 
| } // pbr

ABIs that unconditionally pass structs by "invisible" references would
now go through two indirections to access the data passed to the
function.  What really is the problem this is supposed to solve?

| namespace pbv { // all of this optimizes away
| 
|     template < typename T >
|     struct IntervalArg {  // for discussion purposes only
|         IntervalArg( Interval<T> arg )
|         : val_( arg )
|         {}
|         operator Interval<T> () const
|         { return val_; }
|     private:
|         Interval<T> val_;
|     };
| 
| } // pbv
| 
| Usage is then straightforward:
| 
|     using namespace pbv; // or pbr
|     template< typename T >
|     Interval<T> agile_func( IntervalArg<T> arg1 ) { ... }
| 
| Lest any reader misunferstand, I am _not_ proposing that both pbr
| and pbv be available.  I only used the namespaces to separate the
| alternative implementations for the purposes of clarity within this
| discussion. 

I understand that.  However, from my perspective -- because C++ has
template, argument deduction, overloading -- it really is
essential that non-portability be minimized when they can't be
avoided.  I'm not sure it cannot be avoided here.  Yes, we have
instances of such non-portability in the current standard; but past
lessons suggest that we don't multiply the existing troubles.

| > | Does the interval standard need to be specific about who cleans
| > | arguments off of the stack?
| > 
| > Once we know what IntervalArg<T> and Interval<T> contain and do, we
| > can get to that question.
| 
| I was being facetious.  I suppose that's an error in judgement when
| one is indulging in language laywering.  ;-) 

For the interest of the discussion, we should refrain from suggesting
people are "language lawyer" just because they don't agree with us.

| Stack cleaning conventions don't belong in the standard IMHO.
| 
| > 
| > [...]
| > 
| > | > [ As I mentioned earlier, I'm not sure template aliases help in this
| > | > case. ]
| > | 
| > | I don't understand the term template alias.  Coud you describe one?
| > 
| > A "template alias" is an alias for a family of types
| > 
| >    http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1489.pdf
| 
| Nope.  I'm not going there!  Not now, and probably not ever.

Good.  For the interest of the discussion, writing

    template<typename T>
      using IntervalArg = const Interval<T>&;

would make the "T" in a deducible context; remove needs for proxies
and such.  

>From my perspective, It is still a level of complexity (like any other
alternative you've suggested) for which I have not seen real
justification for -- e.g. what problems it supposed to solve, why that
problem is important, why that is a better alternative.

-- Gaby


More information about the Std-interval mailing list