Boost logo

Boost :

From: Noel Yap (Noel.Yap_at_[hidden])
Date: 2003-05-05 08:19:51


"Justin M. Lewis" wrote:
> It DOES affect the caller, since x was modified internally inside f.
>
> int & f(int &x)
> {
> x++;
> return(x);
> }
>
> int x;
> int &y = f(x);
>
> What indication is there that x was changed inside of f?

I see, you're right. Rather than the current proposal, why not:

  int x;
  int& y = f( in( x ) ); // x isn't changed, but not so great since f owns the return value

  int x;
  int& y = f( in_out( x ) ); // x can be changed, but not se great since f owns the return value

Or, IMHO, better still since only one new class is introduced:

  int x;
  int y = f( dumb_ref< int const >( x ) ); // x isn't changed, return value is a cheap copy

  int x;
  int y = f( dumb_ref< int >( x ) ); // x may be changed, return value is a cheap copy

> int * f(int *x)
> {
> *x++;
> return(x);
> }
>
> int x;
> int *y = f(&x);
>
> Again, what indication is there that x was modified internally?

The fact that the writer of the function decided to have a pointer passed in. It sounds like you're not aware of this convention. Aside from disallowing NULL, the proposed classes won't be any different -- it'll be a convention.

> How do I
> know that what's being returned isn't being allocated by f?

Because the pointer is being passed by value. If f were intended to allocate something new, one could do either of:

  void f( T** x );
  std::auto_ptr< T > f(); // this is much clearer than the above

> You can't tell
> just by looking at the call, you have to go track down the definition of the
> function.

No, you don't; they're equivalent:

  void f( in_out< T > p_ ); // indicates p_ may be changed, NULL not allowed
  void f( T* p_ ); // indicates p_ may be changed, NULL allowed

> Like I've said, the system does require that the programmer use the objects
> properly. BUT, assuming they are used properly, just like we assume that
> when we pass a const object it's not being const_cast, then it tells you for
> sure that f is dependent on the value inside x and y, so they have to be
> initialized to something, AND, it tells you that the values in x and y may
> change.

Right; it's a convention just like all the other existing ones. I think the value added is that it's clear at the call site what the function signature is. OTOH, there are other ways of achieving this.

> Our definitions of c_in are different, I'm using bad naming in this regard,
> it should be something that indicates that ownership of the object is
> changing hands. For your version of c_in, I wouldn't want the common case
> to have to be decorated. In only params are the most common.

If ownership changes hands, either a copy is necessary, or dynamic memory is necessary:

  f( T in_ ); // pass by value
  f( std::auto_ptr< T > in_ ); // pass ownership of memory in

> void f(const CObj &o)
> {
> cout << o << endl;
> }
>
> Something like that, I think that's your version of an in param.

Yes, exactly. It's passed in, but changes don't get passed back out.

> I wouldn't
> want to have to decorate all of those. I want the ones that are the odd
> case decorated, so it's explicit that, hey, this isn't the common case, this
> function IS going to modify these parameters, so heads up.

We're still left with in_out<> in this case:

  void f( T const& in_ );
  void f( in_out< T > inOut_ );

Since out acts just like in_out<> but is just syntactic sugar:

  template< typename T >
  class out:
    public in_out< T >
  {
  };

Noel


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk