Topic: Idea for calling multiple methods on a single object.


Author: tom_usenet@hotmail.com (tom_usenet)
Date: Wed, 9 Jun 2004 17:07:25 +0000 (UTC)
Raw View
On Tue, 8 Jun 2004 17:58:55 +0000 (UTC), dietmar_kuehl@yahoo.com
(Dietmar Kuehl) wrote:

>richard@ex-parrot.com (Richard Smith) wrote:
>> So use a reference:
>>
>>   Type const& tmp = foo();
>>   tmp.method1();
>>   tmp.method2();
>
>Note that this means that 'method1()' and 'method2()' can only be
>'const' methods. This can be a serious restriction.

How about this:

Type const& tmpHolder = foo(); //needed for lifetime extension
Type& tmp = const_cast<Type&>(tmpHolder); //Mmmm, nice.
tmp.method1();
tmp.method2();

Or even this:

Type&& tmp = foo(); //will rvalue references extend lifetime?
//...

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: vm@nowhere.invalid ("Vladim r Marko")
Date: Mon, 7 Jun 2004 16:46:42 +0000 (UTC)
Raw View
X-No-Acknowledgement
X-No-Reject-Notice
"Helium" <bekkah@web.de> wrote in message
news:194c1211.0406060903.6731d4ee@posting.google.com...
> Multiple method-call:
>
> At the moment calling more than one method on one object is
> complicated. Imagine you want to call two methods on the (temporary)
> result of a function. How dod you do this? One possibility is to call
> the function twice.
>
> foo ().method1 ();
> foo ().method2 ();
>
> This is a working solution, but calling the function twice could be
> time consuming or even worse, the function could have some side
> effects you only ant to appear once. So this isn't a solution.
>
> Another possible solution is to store the rusult somewhere.
>
> {
>    Type tmp = foo ();
>    tmp.method1 ();
>    tmp.method2 ();
> }
>
>
> This is very unconvenient and the result has to be copied which cvan
> be time consuming as well. And you have to know the function's return
> type. If it's a reference to an object its type isn't know at
> compile-time, so you have to use a reference, too. If it's a temporary
> object you can't store it in a reference but you have to make a copy
> of it. In both cases you have to create an additional temporary
> (weither a reference or a complete object).
>
>
>
> I suggest a new synthax to call multiple methods on a single object.
> The notation I propose looks like this:
>
> object.(method_1 (), method_2 (), ..., method_n ());
> pointer->(method_1 (), method_2 (), ..., method_n ());
>
>
> The result is that of the last function. This should feel familiar, as
> a multiple method-call looks similar to calling several functions
> using the operator ,:
>
> (function_1 (), function_2 (), ..., function_n ());
>
>
> This way the problem I showed above could easiely be solved like this:
>
> foo ().(
>    method1 (),
>    method2 ()
> );

This is just another case where "bind to r-value" would help.
A simple addition to of a fun_list_t and fun_list templates
as shown below would work. The example can be compiled
but it makes a copy of the object since the "bind to r-value"
has not been implemented yet.

Regards,

Vladimir Marko

#include <functional>
#include <iostream>

// compile time assertion struct
template <typename C1,typename C2>
struct assert_same_class {
  // `type' is not defined
};

template <typename C>
struct assert_same_class<C,C> {
  typedef void type; // `type' is defined
};

// the class to hold function list
template <typename Fun1,typename Fun2>
class fun_list_t
  : public std::unary_function<
    typename Fun1::argument_type,
    typename Fun2::result_type
  >
{
 public:
  typedef typename Fun1::argument_type argument_type;
  typedef typename Fun2::result_type result_type;

  fun_list_t(Fun1 f1,Fun2 f2) : f1_(f1),f2_(f2) { }

  result_type operator () (argument_type arg){
    f1_(arg);
    return f2_(arg);
  }

 private:
  Fun1 f1_;
  Fun2 f2_;

  typedef typename assert_same_class<
    typename Fun1::argument_type,
    typename Fun2::argument_type
  >::type assertion_;
};

// Specializations for functions should be here since the template
//   accepts only function objects with argument_type and result_type now.

// fun_list_t creator
template <typename Fun1,typename Fun2>
fun_list_t<Fun1,Fun2> fun_list(Fun1 f1,Fun2 f2){
  return fun_list_t<Fun1,Fun2>(f1,f2);
}

// A mem_fun_t variant that takes a reference to r-value instead of a
pointer
//   to the object (may be the mem_fun_t could be modified so that it
accepts
//   both).
template <typename Res,typename Cl>
class ref_mem_fun_t : public std::unary_function<Cl,Res> // should be Cl&&
{
 public:
  ref_mem_fun_t(Res (Cl::*f)()) : f_(f) { }

  Res operator () (Cl& obj){ // should be Cl&&
    return (obj.*f_)();
  }
 private:
  Res (Cl::*f_)();
};

// ref_mem_fun_t creator
template <typename Res,typename Cl>
ref_mem_fun_t<Res,Cl> ref_mem_fun(Res (Cl::*f)()){
  return ref_mem_fun_t<Res,Cl>(f);
}

// test struct
struct s_foo{
  int foo1(){
    std::cout << "foo1" << std::endl;
    return 1;
  }
  double foo2(){
    std::cout << "foo2" << std::endl;
    return 2.002;
  }
};

s_foo s_foo_creator(){
  return s_foo();
}

int main(){
  // simple test
  std::cout <<
    fun_list(
      ref_mem_fun(&s_foo::foo1),
      ref_mem_fun(&s_foo::foo2)
    )(s_foo_creator())
  << "\n" << std::endl;

  // big test
  std::cout <<
    fun_list(
      fun_list(
        ref_mem_fun(&s_foo::foo1),
        ref_mem_fun(&s_foo::foo2)
      ),
      fun_list(
        fun_list(
          ref_mem_fun(&s_foo::foo2),
          ref_mem_fun(&s_foo::foo1)
        ),
        ref_mem_fun(&s_foo::foo1)
      )
    )(s_foo_creator())
  << std::endl;

  return 0;
}






---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: richard@ex-parrot.com (Richard Smith)
Date: Mon, 7 Jun 2004 16:47:14 +0000 (UTC)
Raw View
bekkah@web.de (Helium) wrote in message news:<194c1211.0406060903.6731d4ee@posting.google.com>...
> Multiple method-call:
  [...]
> Another possible solution is to store the rusult somewhere.
>
> {
>    Type tmp = foo ();
>    tmp.method1 ();
>    tmp.method2 ();
> }
>
>
> This is very unconvenient and the result has to be copied which cvan
> be time consuming as well.

So use a reference:

  Type const& tmp = foo();
  tmp.method1();
  tmp.method2();

> And you have to know the function's return
> type.

This is true.  Hopefully the next version of the Standard will allow
this to be solved using the auto keyword:

  auto const& tmp = foo(); // Or whatever the syntax is going to be.
  tmp.method1();
  tmp.method2();

>If it's a reference to an object its type isn't know at
> compile-time,

You mean the type needn't be complete: it is still known.

>so you have to use a reference, too. If it's a temporary
> object you can't store it in a reference but you have to make a copy
> of it.

You can bind a temporary to a reference which extends the lifetime of
the temporary.  Suppose foo() returns a Type by value, I can still
write

  Type const& tmp = foo();

and the lifetime of the temporary is extended for the lifetime of the
reference. (The compiler is allowed to make a copy of the return
value, but a good compiler will not.  -- See 8.5.3/5, bullet 2,
sub-bullet 1.)

> In both cases you have to create an additional temporary
> (weither a reference or a complete object).

Creating a reference is very cheap.  It may well not involve any
additional runtime overhead.

--
Richard Smith

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: v.Abazarov@comAcast.net (Victor Bazarov)
Date: Mon, 7 Jun 2004 16:47:28 +0000 (UTC)
Raw View
Helium wrote:
> Multiple method-call:
>
> At the moment calling more than one method on one object is
> complicated. Imagine you want to call two methods on the (temporary)
> result of a function. How dod you do this? One possibility is to call
> the function twice.
>
> foo ().method1 ();
> foo ().method2 ();

If your 'method1' returns a reference suitable for calling 'method2'
(usually *this), you may write

     foo().method1().method2();

> [...]

Victor

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: llewelly.at@xmission.dot.com (llewelly)
Date: Mon, 7 Jun 2004 16:48:45 +0000 (UTC)
Raw View
bekkah@web.de (Helium) writes:

> Multiple method-call:
>
> At the moment calling more than one method on one object is
> complicated. Imagine you want to call two methods on the (temporary)
> result of a function. How dod you do this? One possibility is to call
> the function twice.
>
> foo ().method1 ();
> foo ().method2 ();
>
> This is a working solution, but calling the function twice could be
> time consuming or even worse, the function could have some side
> effects you only ant to appear once. So this isn't a solution.
>
> Another possible solution is to store the rusult somewhere.
>
> {
>    Type tmp = foo ();
>    tmp.method1 ();
>    tmp.method2 ();
> }
>
>
> This is very unconvenient and the result has to be copied which cvan
> be time consuming as well. And you have to know the function's return
> type. If it's a reference to an object its type isn't know at
> compile-time, so you have to use a reference, too. If it's a temporary
> object you can't store it in a reference but you have to make a copy
> of it. In both cases you have to create an additional temporary
> (weither a reference or a complete object).
>
> I suggest a new synthax to call multiple methods on a single object.
> The notation I propose looks like this:
>
> object.(method_1 (), method_2 (), ..., method_n ());
> pointer->(method_1 (), method_2 (), ..., method_n ());
>
>
> The result is that of the last function. This should feel familiar, as
> a multiple method-call looks similar to calling several functions
> using the operator ,:
>
> (function_1 (), function_2 (), ..., function_n ());
>
>
> This way the problem I showed above could easiely be solved like this:
>
> foo ().(
>    method1 (),
>    method2 ()
> );

How is this better than using a reference:

Type& r= foo();
r.method1();
r.method2();

?

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Tue, 8 Jun 2004 17:58:42 +0000 (UTC)
Raw View
llewelly.at@xmission.dot.com (llewelly) wrote:
> bekkah@web.de (Helium) writes:
> > This way the problem I showed above could easiely be solved like this:
> >
> > foo ().(
> >    method1 (),
> >    method2 ()
> > );
>
> How is this better than using a reference:
>
> Type& r= foo();
> r.method1();
> r.method2();

Are you proposing to change the language rules such that binding a
temporary to a non-const reference is allowed? Otherwise I would
claim that Helium's approach works while yours does not...

Nitpicking aside, I don't think that there is any real need for a
language extension allowing only multiple calls for two reasons:
- I think it is rarely necessary to call multiple functions on a
  single object.
- Where it is, a [n inline] function taking the parameter by value
  should do the right thing and is not that much harder to write.

I would rather change the rules for reference handling, possibly
introducing a kind of rvalue reference which accepts binding to
temporaries in addition to what a non-const reference can be bound
to. This would also handle the multiple calls issue: I don't buy
the inconvenience argument but there is an issue with copying. The
issue about needing to know the return type is likely to go away
with whatever approach comes out of the "typeof" discussion.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dietmar_kuehl@yahoo.com (Dietmar Kuehl)
Date: Tue, 8 Jun 2004 17:58:55 +0000 (UTC)
Raw View
richard@ex-parrot.com (Richard Smith) wrote:
> So use a reference:
>
>   Type const& tmp = foo();
>   tmp.method1();
>   tmp.method2();

Note that this means that 'method1()' and 'method2()' can only be
'const' methods. This can be a serious restriction.
--
<mailto:dietmar_kuehl@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: llewelly.at@xmission.dot.com (llewelly)
Date: Tue, 8 Jun 2004 19:06:32 +0000 (UTC)
Raw View
dietmar_kuehl@yahoo.com (Dietmar Kuehl) writes:

> llewelly.at@xmission.dot.com (llewelly) wrote:
>> bekkah@web.de (Helium) writes:
>> > This way the problem I showed above could easiely be solved like this:
>> >
>> > foo ().(
>> >    method1 (),
>> >    method2 ()
>> > );
>>
>> How is this better than using a reference:
>>
>> Type& r= foo();
>> r.method1();
>> r.method2();
>
> Are you proposing to change the language rules such that binding a
> temporary to a non-const reference is allowed? Otherwise I would
> claim that Helium's approach works while yours does not...
[snip]

no, I intended:

Type const& r= foo();
r.method1();
r.method2();

which of course requires that method1() and method2() be const, but
    it works in many cases.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: bekkah@web.de (Helium)
Date: Sun, 6 Jun 2004 23:54:22 +0000 (UTC)
Raw View
Multiple method-call:

At the moment calling more than one method on one object is
complicated. Imagine you want to call two methods on the (temporary)
result of a function. How dod you do this? One possibility is to call
the function twice.

foo ().method1 ();
foo ().method2 ();

This is a working solution, but calling the function twice could be
time consuming or even worse, the function could have some side
effects you only ant to appear once. So this isn't a solution.

Another possible solution is to store the rusult somewhere.

{
   Type tmp = foo ();
   tmp.method1 ();
   tmp.method2 ();
}


This is very unconvenient and the result has to be copied which cvan
be time consuming as well. And you have to know the function's return
type. If it's a reference to an object its type isn't know at
compile-time, so you have to use a reference, too. If it's a temporary
object you can't store it in a reference but you have to make a copy
of it. In both cases you have to create an additional temporary
(weither a reference or a complete object).



I suggest a new synthax to call multiple methods on a single object.
The notation I propose looks like this:

object.(method_1 (), method_2 (), ..., method_n ());
pointer->(method_1 (), method_2 (), ..., method_n ());


The result is that of the last function. This should feel familiar, as
a multiple method-call looks similar to calling several functions
using the operator ,:

(function_1 (), function_2 (), ..., function_n ());


This way the problem I showed above could easiely be solved like this:

foo ().(
   method1 (),
   method2 ()
);

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]