Topic: Automatic creation of postfix operator?


Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/11/07
Raw View
J. Kanze wrote:
>
> Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
>
> |>  What if the constructor and destructor themselves *have* side effects,
> |>  but the combination of both doesn't have them?
> |>  If you f.ex. take reference counted pointers, then the copy constructor
> |>  will increment a reference count, and the destructor will decrement
> |>  it (and possibly destruct the object). Now you would have to write a
> |>  *very* sophisticated compiler to detect that copy constructing the
> |>  pointer, and then deleting it will never cause a visible change.
> |>  With the construct above, you could tell that fact to the compiler.
>
> If the constructor and destructor are inline, and the calls "locally
> paired" (e.g: not in different functions, or optimization blocks), then
> most compilers will optimize this today.  They won't detect that the
> constructor and the destructor are equivalent, but they will see that
> there is an incrementation followed by a decrementation in the code, and
> suppress the pair.
>

You forgot the conditional delete. For this, the compiler would
have to prove that on entry the reference count will never equal 0.
*We* know it is so, as we know it's a reference count, and as
such it's greater than 0, as there's at least one object (the
one we've copied from). But how hard would the compiler have to
work until it finds out?
In addition, it could even optimize out "irrelevant observable
behaviour", that is, behaviour that would in principle be
observable, but doesn't really matter. One example would be for
objects that allocate from an memory pool that can be extended,
but never shrinked. Now if a temporary object is allocated and
then deallocated, this could cause the memory pool to be
extended (observable behaviour!). Of course, if the pool isn't
extended, it doesn't hurt (quite the opposite). Without the
equivalence statement, the compiler will never be able to
optimize this away, as it would violate the as-if rule.

[...]
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/28
Raw View
Valentin Bonnard <bonnardv@pratique.fr> writes:

|>  Paul D. DeRocco wrote:
|>
|>  > I'd say that the ability to redefine the semantics of an
|>  > operator is an unfortunate side effect of operator overloading.
|>  > The "whole point" of operator overloading is usually to retain
|>  > the existing semantics but apply them to a new type.
|>
|>  Yes
|>
|>  > The use of
|>  > << and >> on streams is the only common counterexample I know
|>  > of.
|>
|>  And a violation of this rule is ok only if is very common and
|>  well-understoud (the most common things being the ones in the
|>  std lib).

In fact, given the relative frequencies of IO and shifting, I suspect
that for most people, it is the shifting which is the unexpected
semantics.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
        I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1997/10/24
Raw View
Roger Onslow wrote:
>
> The whole point of operator overloading is so the you can redefine the
> SEMANTICS of an operator (but the syntax remains the same).

I'd say that the ability to redefine the semantics of an
operator is an unfortunate side effect of operator overloading.
The "whole point" of operator overloading is usually to retain
the existing semantics but apply them to a new type. The use of
<< and >> on streams is the only common counterexample I know
of.

--

Ciao,
Paul
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/24
Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:

|>  What if the constructor and destructor themselves *have* side effects,
|>  but the combination of both doesn't have them?
|>  If you f.ex. take reference counted pointers, then the copy constructor
|>  will increment a reference count, and the destructor will decrement
|>  it (and possibly destruct the object). Now you would have to write a
|>  *very* sophisticated compiler to detect that copy constructing the
|>  pointer, and then deleting it will never cause a visible change.
|>  With the construct above, you could tell that fact to the compiler.

If the constructor and destructor are inline, and the calls "locally
paired" (e.g: not in different functions, or optimization blocks), then
most compilers will optimize this today.  They won't detect that the
constructor and the destructor are equivalent, but they will see that
there is an incrementation followed by a decrementation in the code, and
suppress the pair.

And if the calls are not "locally paired", even your suggestion would
not permit the optimization.

So all that you gain is the possibility of the optimisation if the
functions aren't inline'd.  Not much, considering that several modern
compilers are already able to inline across translation unit boundaries.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
        I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/24
Raw View
Paul D. DeRocco wrote:

> I'd say that the ability to redefine the semantics of an
> operator is an unfortunate side effect of operator overloading.
> The "whole point" of operator overloading is usually to retain
> the existing semantics but apply them to a new type.

Yes

> The use of
> << and >> on streams is the only common counterexample I know
> of.

And a violation of this rule is ok only if is very common and
well-understoud (the most common things being the ones in the
std lib).

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/26
Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:

> Valentin Bonnard wrote:
> >
> >
> > template <class T>
> > inline
> > T   operator++ (T& x, int)
> > {
> >     T tmp = x;
> >     ++x;
> >     return tmp;
> > }

Notes:
- 'tmp' stands for temporary
- tmp isn't a temporary object

[...]

> Well, after inlining, the return is a no-op. Now the compiler can
> prove that the copy constructed object isn't used after construction,
> and therefore IMHO can be elided. Is there something I'm missing?

New (London 97) rules for object elision are:
- a return can be elided
- a copy temporary object -> non-temporary (named) object
  can be elided
- no other object can be elided

The correct reasonning is the following:

- the return statement copies tmp to a temporary object of
  type T; let's assume that we can't assume anything about
  the copy ctor of T

- such an object (temporary of function return) can be elided

- the object tmp isn't used after it's created (we have elided
  the return statement); still, the non-temporary object tmp
  copied from the non-temporary object x, thus no object can
  be elided

So we have:

  T tmp = x;
  ++x;

> But if it is not, then it would be a strong argument for a compiler
> generated one,

No, as iterators have bitwise copy semantics, and so copies can
always be elided.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/23
Raw View
Christopher Eltschka wrote:

> This could be useful in other cases as well, say you want to tell
> the compiler that default constructing and destructing a MyClass
> object is in effect a no-op, you could do it like this:
>
> equivalence() { MyClass().~MyClass() } { }

What about simply making MyClass and all sub-objects of MyClass
dtors inline ?

I don't think it's a good idea to add such a thing w/o
practical experience with compilers.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/10/23
Raw View
Valentin Bonnard wrote:
>
> Christopher Eltschka wrote:
>
> > This could be useful in other cases as well, say you want to tell
> > the compiler that default constructing and destructing a MyClass
> > object is in effect a no-op, you could do it like this:
> >
> > equivalence() { MyClass().~MyClass() } { }
>
> What about simply making MyClass and all sub-objects of MyClass
> dtors inline ?
>

What if the constructor and destructor themselves *have* side effects,
but the combination of both doesn't have them?
If you f.ex. take reference counted pointers, then the copy constructor
will increment a reference count, and the destructor will decrement
it (and possibly destruct the object). Now you would have to write a
*very* sophisticated compiler to detect that copy constructing the
pointer, and then deleting it will never cause a visible change.
With the construct above, you could tell that fact to the compiler.

> I don't think it's a good idea to add such a thing w/o
> practical experience with compilers.

Sorry, but I don't understand what this has to do with practical
experience with compilers. It's just a way to tell the compiler:
"If you replace the expression on the left side with the expression
on the right side (or vice versa), I just don't care."
Why should this be problematic (given that the two statements
are really equivalent in their effects)? In the worst case, the
compiler just ignores the hint (which is the more probable, the more
complex the expressions are...)
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/24
Raw View
Christopher Eltschka wrote:
>
> Valentin Bonnard wrote:

> > I don't think it's a good idea to add such a thing w/o
> > practical experience with compilers.
>
> Sorry, but I don't understand what this has to do with practical
> experience with compilers.

It just has to do with the fact that we don't want to introduce
useless 'gadgets' in C++; C++ already is a big language, so don't
add something until you are sure that there'll be a gain. (Don't
add something just because it can't hurt.)

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Roger Onslow" <Roger_Onslow@compsys.com.au>
Date: 1997/10/21
Raw View
The whole point of operator overloading is so the you can redefine the
SEMANTICS of an operator (but the syntax remains the same).

You can give new meaning to (almost) any operator in C++ and there is no
predefined or enforced relationships between any of these - it is entirely
up to the programmer.

Of course it is generally BAD design to change the semantics TOO much - eg.
define an operator+ that subtracts.

As with most powerful features of C and C++, operator overloading should be
used judiciously and with care.

As with the old GOTO debate (now there's a can of worms that hasn't been
opened for a while :-), you can do more damage to the readability of a
program with weird operator overloads etc then any nicely ordered set of
goto's would ever do !!  C++ gives you much more power to create difficult
to read and maintain programs that C ever did - and also the power to make
them extremely readable and maintainable - its up to the intelligent
programmer to use the power wisely!

Roger

Steve Clamage wrote in message <344f8f6f.6665789@engnews1.eng>...
>On 20 Oct 97 09:23:23 GMT, Christopher Eltschka
><celtschk@physik.tu-muenchen.de> wrote:
>
>>Why is there no automatic creation of postfix operator ++/--, if
>>prefix operator ++/-- is defined, but postfix isn't?
>
>Because no assumptions can be made about the semantics of any
>user-defined operator. The operator is allowed to do anything at all.
>Even in non-pathological cases few assumptions can be made (and how
>does the compiler know whether a case is pathological?).
>
>Example 1: The prefix operator does not return the object it operates
>on, but something else. How is the compiler supposed to infer what you
>want the postfix operator to do?
>
>Example 2: The prefix operator acquires and releases a lock. How would
>the compiler know that it was doing so? Even if it did know, how would
>it know the proper sequence of acquiring and releasing the lock
>relative to the rewriting of the prefix function?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Stanislaw Bochnak <S.Bochnak@microtool.com.pl>
Date: 1997/10/21
Raw View
Christopher Eltschka wrote:
>
> Why is there no automatic creation of postfix operator ++/--, if
> prefix operator ++/-- is defined, but postfix isn't?
> I mean, the supposed semantics of the postfix operator ++/-- is
> so much clear that it would not be difficult to generate it
> automatically. This would save typing that doesn't bring any new

If I have a + operator defined in a class C, whuy not to
generate automatically a += operator? A semantics of this
is also obvious ;-)

And in fact, it does not have to be true!!!
By the way, prefix and postfix versions of ++/-- return
modifiable and non-modifiable objects, this means implementation
can be totally different.

> concept. Besides, if the compiler generates it, it knows
> everything about it, and therefore can more easily optimize it.
> For example the eternal question of ++i vs. i++ when the return
> value is not used would not be, as about every compiler would
> optimize the postfix operator just to the prefix operator.

As I've written - a++ is an l-value, while ++a - not. It is not the
same!

> BTW, what was the reason that both operators were to defined
> independently? Given the simple semantic relation of prefix/postfix
> operator++/--, it would have been easy to let the user only
> define prefix at all, and let the compiler care about the correct
> postfix (without even giving the user the possibility to define it
> differently; a possibility where I don't see any benefit from).
> This would also left alone the need of the dummy int parameter,
> which isn't quite intuitive.

Right, this dummy parameter is not the most obvious thing.

Stanislaw Bochnak
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/10/21
Raw View
Valentin Bonnard wrote:
>
> Christopher Eltschka wrote:
> >
> > Why is there no automatic creation of postfix operator ++/--, if
> > prefix operator ++/-- is defined, but postfix isn't?
>
> What about:
>
> template <class T>
> inline
> T   operator++ (T& x, int)
> {
>     T tmp = x;
>     ++x;
>     return tmp;
> }
>

[...]

> > For example the eternal question of ++i vs. i++ when the return
> > value is not used would not be, as about every compiler would
> > optimize the postfix operator just to the prefix operator.
>
> Such elision was possible with the old object elision rule, but
> not with the new one (as x is not a temporary object). Only the
> elision of the copy of tmp on the stack can be done.
>

Well, after inlining, the return is a no-op. Now the compiler can
prove that the copy constructed object isn't used after construction,
and therefore IMHO can be elided. Is there something I'm missing?

But if it is not, then it would be a strong argument for a compiler
generated one, because this one *could* be optimized (assuming
that the only restriction on the generated code is that pre-increment
must be done not after the end of expression - or maybe the next
sequence point -, and of course the result of the expression is the
old value). That is, the compiler could optimize better.

But maybe a better solution would be a way to give the compiler
optimizing hints. For example, you could have an optimize construct,
where you tell the compiler expressions it should view as equivalent
even if it can't prove they are, f. ex.

equivalence(MyClass x) { (void)x++ } { (void)++x }

telling that everywhere the compiler has an increment expression
for MyClass with neglected return statement (cast to void!), it can
view the two expressions as equivalent (this should also be true, if
this constellation occurs only after optimizing; say it's stored
in a variable that is optimized away).
This could be useful in other cases as well, say you want to tell
the compiler that default constructing and destructing a MyClass
object is in effect a no-op, you could do it like this:

equivalence() { MyClass().~MyClass() } { }

Of course the compiler cannot be forced to make use of this hint,
but it would be really nice to have a standard way to give it
those hints (even if it ignores them completely).

But it's too late anyway...

[...]
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/10/20
Raw View
Why is there no automatic creation of postfix operator ++/--, if
prefix operator ++/-- is defined, but postfix isn't?
I mean, the supposed semantics of the postfix operator ++/-- is
so much clear that it would not be difficult to generate it
automatically. This would save typing that doesn't bring any new
concept. Besides, if the compiler generates it, it knows
everything about it, and therefore can more easily optimize it.
For example the eternal question of ++i vs. i++ when the return
value is not used would not be, as about every compiler would
optimize the postfix operator just to the prefix operator.

BTW, what was the reason that both operators were to defined
independently? Given the simple semantic relation of prefix/postfix
operator++/--, it would have been easy to let the user only
define prefix at all, and let the compiler care about the correct
postfix (without even giving the user the possibility to define it
differently; a possibility where I don't see any benefit from).
This would also left alone the need of the dummy int parameter,
which isn't quite intuitive.

Now I can't imagine that this possibility wasn't known by the
commitee, so there must have been a reason to do things like they
are now. What was it?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/10/20
Raw View
Christopher Eltschka wrote:
>
> Why is there no automatic creation of postfix operator ++/--, if
> prefix operator ++/-- is defined, but postfix isn't?

What about:

template <class T>
inline
T   operator++ (T& x, int)
{
    T tmp = x;
    ++x;
    return tmp;
}

> I mean, the supposed semantics of the postfix operator ++/-- is
> so much clear that it would not be difficult to generate it
> automatically.

That's what the template does. And the user cam still provide
an implementation for a particular class.

Note that the same goes for !=, >, and >= when ==, < and <=
are defined. These templates are provided by the library in
namespace rel_op (I think).

> For example the eternal question of ++i vs. i++ when the return
> value is not used would not be, as about every compiler would
> optimize the postfix operator just to the prefix operator.

Such elision was possible with the old object elision rule, but
not with the new one (as x is not a temporary object). Only the
elision of the copy of tmp on the stack can be done.

But iterators often have a bit-wise copy ctor which can be
elided anyway (a C compiler can do that).

> BTW, what was the reason that both operators were to defined
> independently?

The way C++ does operator overloading is that + isn't automatically
defined when += is, the same the other way arround.

It is potentially more flexible, and template functions can provide
a default meaning.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: stephen.clamage_nospam@eng.sun.com (Steve Clamage)
Date: 1997/10/20
Raw View
On 20 Oct 97 09:23:23 GMT, Christopher Eltschka
<celtschk@physik.tu-muenchen.de> wrote:

>Why is there no automatic creation of postfix operator ++/--, if
>prefix operator ++/-- is defined, but postfix isn't?

Because no assumptions can be made about the semantics of any
user-defined operator. The operator is allowed to do anything at all.
Even in non-pathological cases few assumptions can be made (and how
does the compiler know whether a case is pathological?).

Example 1: The prefix operator does not return the object it operates
on, but something else. How is the compiler supposed to infer what you
want the postfix operator to do?

Example 2: The prefix operator acquires and releases a lock. How would
the compiler know that it was doing so? Even if it did know, how would
it know the proper sequence of acquiring and releasing the lock
relative to the rewriting of the prefix function?

---
Steve Clamage, stephen.clamage_nospam@eng.sun.com
( Note: remove "_nospam" when replying )
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]