Notice: On April 23, 2014, Statalist moved from an email list to a forum, based at statalist.org.
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: st: Pointer to class member function?
From
Richard Foltyn <[email protected]>
To
[email protected]
Subject
Re: st: Pointer to class member function?
Date
Sat, 4 May 2013 19:22:56 +0200
Thank you very much for taking the time to write such an elaborate answer!
It was highly appreciated.
Best,
Richard
On Fri, May 3, 2013 at 6:36 PM, William Gould, StataCorp LP
<[email protected]> wrote:
> Richard Foltyn ([email protected]) is doing advanced class
> programming in Mata. He is trying to take the address of a
> class-member function and then use that address later to invoke the
> function.
>
> The short answer is that what Richard is trying to do will not work and
> is not supported.
>
> I'm about to explain why it's not supported, but I don't really expect
> that will alleviate Richard's disappointment.
>
> Richard offered the following example:
>
> mata:
>
> class testClass {
> void run1()
> void run2()
> real scalar func()
> }
>
> real scalar testClass::func(real scalar arg)
> {
> return(arg)
> }
>
> void testClass::run2(pointer(real scalar function) scalar f, ///
> real scalar arg)
> {
> (*f)(arg)
> }
>
> void testClass::run1()
> {
> this.run2(&func(), 1)
> }
>
> foo = testClass()
> foo.run1()
>
> end
>
> The result of running example, Richard correctly reports, is,
>
> : foo.run1()
> testClass::run1(): 3499 func() not found [3]
> <istmt>: - function returned error [1]
>
> Richard took a good stab and writing what wanted to achieve. Even so,
> there is conceptually too little information in what Richard wrote
> above for any compiler to interpret or to compile the code correctly.
>
> To understand the issue, I first need to tell you how class functions
> are implemented by compilers. When a programmer codes
>
> a.myfunc()
>
> The compiler in fact compiles
>
> <name_of_class>memberfunction_myfunc(a)
>
> That is, the a. at the front becomes an argument to more-or-less regular
> function! Details vary, but all compilers do this. When programmer
> codes
>
> a.func2(d, e)
>
> compiles in fact compile
>
> <name_of_class>memberfunction_func2(a, d, e)
>
> The class object again moves to being just an argument of the function.
>
> The class object had to to be passed to the function in some way, and
> because the mechanism already exists to pass arguments, it's easiest
> for compilers to simply pass the class object using them.
>
> So now consider one of the functions Richard wrote,
>
>
> void testClass::run1()
> {
> this.run2(&func(), 1)
> }
>
> That is where the error occurred, but at this point, the conceptual
> problem has not yet arisen. It is merely that Mata will not allow the
> & operator to be applied to member functions. That is not implemented
> because, as I am about to show you, even if you had the address, we are
> about to run into a substantive problem.
>
> So pretend that Mata did return the address of member function
> func(). It would have been easy enough for Mata do to that. In fact,
> extra code had to be added to prevent Mata from doing that.
>
> That substantive problem would arise when Richard when to use the
> pointer. In Richard's case, that would be in the following code:
>
> void testClass::run2(pointer(real scalar function) scalar f, ///
> real scalar arg)
> {
> (*f)(arg)
> }
>
> All Mata knows about object f is that it is a pointer to a real scalar
> function. It does not know that the pointer is in fact a pointer to a
> member function of some class, nor does it know the name of the class.
> Thus, if Mata were to compile
>
> (*f)(arg)
>
> It would not know that it needed to add a first argument to the
> function containing a pointer to the class object! So even if we had
> the address of the member function, the code would be miscompiled and
> that would lead to another error.
>
> And that is why Mata won't let you take the address of a member
> function. There is nothing useful you could do with it.
>
> As I said, we actually went to extra work to prevent Mata from
> returning the address of the function. So how might we extend the
> programming language so that in the definition of member function
> run2() Mata would know that *f is a member of function and of this same
> class.
>
> One way would be,
>
> void testClass::run2(
> pointer(real scalar member(testClass) function) scalar f,
> real scalar arg)
> {
> (*f)(arg)
> }
>
> We could teach Mata to understand that, although we will not do that.
>
> One feature of Mata is that Mata never crashes. Errors are
> caught and Stata stays running. If we opened this door, You
> could specify the name of the class incorrectly. How would we
> know that you did not? If you did, a crash would be possible
> unless we also add run-time code to catch the problem, and that will
> slow down the execution of all functions in all contexts.
>
> In C++, you can do something like Richard wants, but if you do it
> incorrectly, the resulting code crashes. Moreover, even in C++, the
> standard implementations do not provide exactly what Richard wants.
> C++ requires that a pointer to the class object be passed along with a
> pointer to the function. And you must be sure that you get the
> pointers right or the resulting code crashes.
>
> One solution Richard might consider is to move the functions outside
> of the class and pass the class object explicitly to the functions.
> Mata does allow pointers to ordinary functions and they may be used
> even inside classes.
>
> The other possible solution, which can be implemented inside the class,
> is to use codes rather than address and a switcher function inside
> the class to call the appropriate function. The code would look like this:
>
>
> mata:
>
> class testClass {
> void run1()
> void run2()
> real scalar func(), func2(), func3()
> real scalar switch()
> }
>
> real scalar testClass::func(real scalar arg)
> {
> return(arg)
> }
>
> /* define func2(), func3() how you wish */
>
> real scalar testClass::switch(real scalar id, real scalar arg)
> {
> if (id==1) return(this.func(arg))
> if (id==2) return(this.func2(arg))
> if (id==3) return(this.func3(arg))
> _error("invalid id"
> }
>
> ...
>
> -- Bill -- Hua Peng
> [email protected] [email protected]
>
> *
> * For searches and help try:
> * http://www.stata.com/help.cgi?search
> * http://www.stata.com/support/faqs/resources/statalist-faq/
> * http://www.ats.ucla.edu/stat/stata/
*
* For searches and help try:
* http://www.stata.com/help.cgi?search
* http://www.stata.com/support/faqs/resources/statalist-faq/
* http://www.ats.ucla.edu/stat/stata/