18 Replies Latest reply on Sep 7, 2006 1:55 PM by scriptkiddie

    passing method as a parameter to another method -- does not work!!!!!!

    scriptkiddie
      Inside a class, I am trying to pass one member method as a parmaeter to another member method. It seems not to work, although the same code would work in languages like C++/Java. What is wrong?

      Now, there must be a way to do it, right? Anybody ever done something like that?

      You can see a discussion on this issue here. However, no solution has been found:
      http://www.kirupa.com/forum/showthread.php?t=227111

      Here is my code (I have an instance of MyClass on the stage, no other code on the stage):


      class MyClass extends MovieClip {

      public function load_pic():Void {
      this.createEmptyMovieClip("holder",100);
      this["holder"].loadMovie("peas_n_carrots.jpg");
      }

      public function do_something(f:Function):Void {
      f();
      }

      // Constructor

      public function MyClass() {

      load_pic(); //works
      do_something(load_pic); //DOES NOT WORK!!!!!!!!!!!!!!!!! WHY?????????

      }

      }

      BTW here somebody suggests a way that really works only for global functions.....
      http://www.actionscript.org/forums/showthread.php3?t=56488
        • 1. Re: passing method as a parameter to another method -- does not work!!!!!!
          Craig Grummitt Level 3
          that code worked for me... are you using Flash 8?
          • 2. Re: passing method as a parameter to another method -- does not work!!!!!!
            scriptkiddie Level 1
            Are you sure?
            Try to comment out the 1st line in the constructor.
            Leave only the do_something(load_pic);
            Do you still get a pic loaded?
            Yes I am using Flash 8 pro.
            • 3. Re: passing method as a parameter to another method -- does not work!!!!!!
              Craig Grummitt Level 3
              i see your problem now - i ignored the loadMovie and substituted it with a trace, to test your concern that a method can not be passed as a parameter. but it wasn't passing the method that was the problem...

              though the method passed okay, 'this' inside that method became undefined as the parameters and therefore what they refer to are only local variables. to get around this, you would need to pass the location of the function as well.
              • 4. Re: passing method as a parameter to another method -- does not work!!!!!!
                Craig Grummitt Level 3
                Alternatively you could just pass the name of the function:
                • 5. Re: passing method as a parameter to another method -- does not work!!!!!!
                  scriptkiddie Level 1
                  Yes! It works!

                  Two questions:

                  1. Why does the "this" inside become undefined?... I pass a member method, right? So when do_something() gets load_pic() as a parameter, how come it does not know which instance load_pic() belongs to? The rule is that inside a class, if you use a member method without specifying what instance it belongs to, then it belongs to " this". And within a method that belongs to " this", every this means " this".... what that I am trying to say is that in every other language that I know, my original code would work... so why not in AS?

                  2. How did you check out the value of variables during running.....?
                  • 6. Re: passing method as a parameter to another method -- does not work!!!!!!
                    Craig Grummitt Level 3
                    1. It's been too long since i used C++ and I haven't used Java, so I can only speak for A/S. My interpretation of what's happening here is that the parameter is a placeholder for a function, rather than a pointer to the function. Meaning that the function itself is getting passed as a parameter. Parameters are local temporary variables that do not exist in the movie clip hierarchy. 'This' in the parameter function is therefore undefined.

                    2. There are two ways of checking out the values of variables during running - using trace and using Debug Movie(in the control menu below Test Movie)
                    • 7. Re: passing method as a parameter to another method -- does not work!!!!!!
                      Level 7
                      scriptkiddie wrote:

                      > 1. Why does the "this" inside become undefined?... I pass a member method,
                      > right?

                      No, you passed a (independant) function object.


                      > So when do_something() gets load_pic() as a parameter, how come it
                      > does not know which instance load_pic() belongs to?

                      The compiler knows load_pic belongs to your instance. However the compiler
                      doesn't know that 'f:Function' (the argument of your 'do_something' method)
                      actually is 'load_pic.' For all the compiler knows, 'f:Function' is a
                      Delegate that executes code on a completely different object.


                      > The rule is that
                      > inside a class, if you use a member method without specifying what
                      > instance it belongs to, then it belongs to " this".

                      That's right. However in your case, you didn't use a member method, you used
                      a local variable function object.


                      > And within a
                      > method that belongs to " this", every this means " this"....
                      > what that I am trying to say is that in every other language that I know,
                      > my original code would work... so why not in AS?

                      In AS, functions' scope vary depending on where they are called form: 'this'
                      is dynamic. Because of that, as soon as you pass a function object around,
                      it is detached from its container object. You can attach the function to
                      another object and 'this' inside will then point to it. If you call the
                      function without explicit scope (as a local variable in another function
                      for example), then 'this' will be undefined.

                      To manipulate functions dynamically, you have 2 options:
                      1) use method names to call the function explicitely on an object:
                      myObj["myMethod"]();
                      2) Use Function.call and Function.apply to so that the function object will
                      be invoked in the scope you specifically determine.

                      In your case, I'd go for 2 and your code would then become:
                      f.apply(this);

                      Tim.
                      • 8. Re: passing method as a parameter to another method -- does not work!!!!!!
                        scriptkiddie Level 1
                        regarding (1) this is strange, because as far as I know only primitive variables are passed by value in AS functions.... just like in Java. Why would they build the compiler to pass Function variables by value and not by reference? It's so weird, as one of the things that you always use in member methods is the context, i.e. other member variables (including the default "this") & methods.
                        • 9. Re: passing method as a parameter to another method -- does not work!!!!!!
                          Level 7
                          > class MyClass extends MovieClip {
                          > public function load_pic():Void {
                          > this.createEmptyMovieClip("holder",100);
                          > this["holder"].loadMovie("peas_n_carrots.jpg");
                          > }
                          > public function do_something(f:Function):Void {
                          > f();
                          > }
                          > // Constructor
                          > public function MyClass() {
                          > load_pic(); //works
                          > do_something(load_pic); //DOES NOT WORK!!!!!!!!!!!!!!!!! WHY?????????
                          > }
                          > }

                          What that does is pass a reference to the function load_pic to the method
                          do_something via variable f, and then when it calls f(), that is treated as
                          a function call, not a method call, because f is a local variable.

                          That means 'this' is not defined for load_pic when it is called via the
                          variable f.

                          That is correct behavior.

                          You need to use 'call' to call a function as a method. eg

                          public function do_something(f:Function):Void
                          {
                          f.call(this);
                          }

                          (or you could use 'apply' instead of 'call' .. seeing there are no function
                          arguments being passed, these will work the same)
                          --
                          Jeckyl


                          • 10. Re: passing method as a parameter to another method -- does not work!!!!!!
                            Level 7
                            > 1. Why does the "this" inside become undefined?

                            Because you passed (by value) a reference to a function object (like all
                            objects are passed), and called it as a function, not as a method.

                            > ... I pass a member method, right?

                            No .. you passed a reference to a function object.

                            Both methods and functions are function objects. There is no difference
                            between them. Whether they are treated as a method (and have a 'this')
                            depends on how they are called.

                            A 'method' in a class is nothing more than a function object reference
                            assigned to a member variable. ie you have a member variable called
                            'load_pic' whose value is a reference to a function object.

                            Unless you call the function object via a member variable, it is treated as
                            a function (and so there is no 'this')

                            > So when do_something() gets load_pic() as a parameter, how come it does
                            > not know which instance load_pic() belongs to?

                            How would it know ? .. you only passed a value that is a reference to the
                            function object. Function objects are just code, they don't know that they
                            might be used as a method in a class, just like a number value does know it
                            might be stored in a member variable. There is no context passed with a
                            function object.

                            > The rule is that inside a class, if you use a member method without
                            > specifying what instance it belongs to, then it belongs to "this".

                            Yes .. but inside do_something, f is NOT a member method .. its a local
                            variable (function argument).

                            > what that I am trying to say is that in every other language that I know,
                            > my original code would work... so why not in
                            > AS?

                            It wouldn't work it other languages either.
                            --
                            Jeckyl


                            • 11. passing method as a parameter to another method -- does not work!!!!!!
                              eric76 Level 1
                              This issue has been confusing me too. I guess it is because we are fammiliar with languages with statically scoped semantics of "this" and of functions - which is so much easier to understand. In Java, you always know that "this" refers to the object of the class you are currently coding. You never have to wonder if it might all of a sudden refer to something else. In Scheme (Lisp variant) (and Java), every function always remembers its context. There is no such thing as a function without a context, where "this" would be undefined. My oppinion is that the dynamical scoping of AS is horrible, so much easier for bugs to crop up and harder to debug. Are there even any benefits of removing the context of a function so that "this" becomes undefined?

                              My wishlist for AS includes: make it statically scoped! But until then, is there some good document that covers this topic, AS scoping etc?
                              • 12. Re: passing method as a parameter to another method -- does not work!!!!!!
                                Level 7
                                A function object has no context until it is called ... there is nothing
                                being removed. Unless it is called as a method, it will not have a 'this'
                                defined because there is no 'this' that one can use. If the function object
                                is called as a method, then 'this' refers to the object in whose context the
                                function was called as a method.

                                By having functions as objects (like Smalltalk) AS and JavaScript make them
                                first-class objects .. which is a good thing from an OO point of view.. Not
                                many languages do support that concept fully though. With the power and
                                flexibility comes responsibility though .. and the unwary can find
                                themselves in unfamiliar territory. However, most of the time it makes no
                                difference to any other than those doing more 'advanced' things.
                                --
                                Jeckyl


                                • 13. Re: passing method as a parameter to another method -- does not work!!!!!!
                                  eric76 Level 1

                                  You say that A function object has no context until it is called. My point is that this dynamical semantics of functions is a feature of some languages, like AS. However I think most languages use statical semantics because it makes better design, because then you know just by looking at the context you are coding, what all references mean. Statical semantics = all functions have statical context, and does not depend on where they are called. To allow functions to be first-class objects doesn't in any way prevent statical scoping. Scheme makes virtually all objects first-class, but is completely statically scoped. (True Java doesn't fully make functions first-class, I'm guessing thats an easy way of implementing statical scoping, since you always have to call a function via its object = context.)
                                  • 14. Re: passing method as a parameter to another method -- does not work!!!!!!
                                    Level 7
                                    There are few languages where a context is bound to a method statically.

                                    Every time you call a method of a different object of a given class, the
                                    'this' is set to that object .. the binding happens when the method call is
                                    made.

                                    The difference is that you can ONLY call methods as methods in many
                                    languages .. so you HAVE to have a context in order to call the function.

                                    In AS that is not the case. You can call a method as a function and a
                                    function as a method. Simply because AS does not distinguish between the
                                    two types of function object. Its does leave you open for errors in your
                                    logic .. but (like most things) if you are aware of it, and do the right
                                    things, then the right things will happen.

                                    The problem is that, at compile time, the AS compiler doesn't know that
                                    there is anything wrong.
                                    --
                                    Jeckyl


                                    • 15. Re: passing method as a parameter to another method -- does not work!!!!!!
                                      eric76 Level 1
                                      Whether the binding is actually done when the call is made, is more a question of how the implementation is made at the machine level. What interests me as a programmer, is the meaning of my code at "compile time". And with statical scoping, I know that the context of a function I am coding, will always be the context that I see right there in the code. Very straight forward and simple to understand. I never have to think: "Maybe this function will be used in another context, where the variables this function referenses might be something else than they are here". As you say, with dynamical scoping the compiler can't know if you are making a logical error.

                                      You seem to think that forcing a function to have a context is like a punishment, something you "have to have" in statically scoped languages. Why? To me, statical scoping is a way to make the code simpler to understand. I like type systems too, but some think having to declare what types objects are, is a punishment too. You don't lose anything by forcing each function having a statical scope, I think you gain.

                                      In AS things get more confusing, because sometimes, functions need to be "called" with call(), and in some cases, where this is not possible (eg. onEnterFrame() since it is called automatically by Flash) you have to use Delegate. With statical scoping, all these problems would dissapear.
                                      • 16. Re: passing method as a parameter to another method -- does not work!!!!!!
                                        Level 7
                                        I don't think that its a punishment at all

                                        I'm just explaining what happens in AS. That function objects are
                                        effectively untyped (in terms of their parameters and whether they are
                                        methods or functions.

                                        I'm not saying its better .. it is simpler though

                                        Flash AS has grown from roots where its was merely for very simple movie
                                        control (stop and play etc) and really needs re-doing now that it is being
                                        used for more involved and complicated programming .. hence AS3.
                                        --
                                        Jeckyl


                                        • 17. Re: passing method as a parameter to another method -- does not work!!!!!!
                                          eric76 Level 1
                                          If you mean that the way AS behaves now is easier to implement for the language designers, you're probably completely right. I would guess that it is harder to implement a statically scoped language. And yes I think AS would gain alot from taking some steps forward. One great thing would be to integrate AS closer to the stuff on the Flash side, like MovieClips. It would be great if you could do:
                                          mc:SomeMC = new SomeMC(arg1, arg2, arg3);
                                          someOtherMC.attachMovie(mc);
                                          So that you wouldn't be forced to handle MCs in classes by composition. That's a whole other thread tho, one I tried to discuss on a thread on classes and MovieClips¨.
                                          • 18. Re: passing method as a parameter to another method -- does not work!!!!!!
                                            scriptkiddie Level 1
                                            An excerpt from here:
                                            http://www.adobetutorialz.com/articles/1953/1/ActionScript-3.0-Overview

                                            Method closures

                                            Event handling is simplified in ActionScript 3.0 thanks to method closures, which provide built-in event delegation. In ActionScript 2.0, a closure would not remember what object instance it was extracted from, leading to unexpected behavior when the closure was invoked. The mx.utils.Delegate class was a popular workaround; to use it, you would write code as follows:

                                            myButton.addEventListener("click",
                                            Delegate.create(this, someMethod));

                                            Delegate.create(this, someMethod)

                                            This class is no longer needed because in ActionScript 3.0, a method closure will be generated when someMethod is referenced. The method closure will automatically remember its original object instance. Now, one can simply write:

                                            myButton.addEventListener("click", someMethod);