Injecting local variable to a function - Can it be done?

Discussion in 'Javascript' started by tai, Nov 17, 2006.

  1. tai

    tai Guest

    Hi.

    I'm looking for a way to define a function that's only effective inside
    specified function.

    Featurewise, here's what I want to do:

    bar_plugin_func = function() { ...; setTimeout(...); ... };
    wrap_func(bar_plugin_func);
    bar_plugin_func(); // calls custom "setTimeout"

    So while plugin developer thinks s/he's calling top-level function,
    I want to hook it by somehow injecting local variable with the same
    name.

    Simply doing something like

    ;(function() { setTimeout = function() { ...my custom implementation
    })();

    is not ideal, as that'll taint global scope. Actually, I can live with
    that for now,
    but it's my technical interest to find a way to define it locally.

    >From the quote in following reference, it says:


    - http://www.unix.org.ua/orelly/web/jscript/ch11_05.html
    > Variable Scope
    > We saw above that top-level variables are implemented as properties of the current window
    > or frame object. In Chapter 6, Functions, we saw that local variables in a function are
    > implemented as transient properties of the function object itself.


    So how can I manipulate "transient properties of the function object
    itself"?

    Thanks in advance.
    tai, Nov 17, 2006
    #1
    1. Advertising

  2. tai

    tai Guest

    > Perhaps some more clarification would be in order?

    OK...let me try again.

    I'm currently developing a JS-based framework that handles
    user-registered functions. Just before executing these registered
    functions, the framework redefines, or newly defines several
    "top-level" methods to coordinate interaction between each
    registered functions. So it's not limited to "setTimeout" method only.

    Here's somewhat different, but more concrete example.
    One of my framework components is FSM (finite state machine)
    class, and it can be used in following manner:

    var func0 = function func0(arg) { alert("func0"); goto(func2);
    alert("notreached") };
    var func1 = function func1(arg) { alert("func1"); goto(-1) };
    var func2 = function func2(arg) { alert("func2"); goto(-1, true) };

    var sm = new StateMachine(func0, func1, func2);
    sm.start(func0, arg); // alerts in order of: func0, func2, func1

    In above example, the framework defines "goto" method, which
    cause a immediate transition to specified state. And this is
    where my initial question comes in.

    To provide "goto" or any other external functions, I currently
    add them to global scope. However, I feel that's an overkill -
    these just need to be effective in registered functions. I want
    to use them as if they are "top-level", but I also want global
    namespace kept clean.

    I know JS's scoping rule will make any attempt void once these
    registered functions do a nested function call (which resets
    scope chain). However, how about directly inside these registered
    functions? Is it possible to re-define top-level functions just
    directly inside these (= func0, func1, func2) registered methods?

    > > Featurewise, here's what I want to do:
    > >
    > > bar_plugin_func = function() { ...; setTimeout(...); ... };
    > > wrap_func(bar_plugin_func);
    > > bar_plugin_func(); // calls custom "setTimeout"
    > >
    > > So while plugin developer thinks s/he's calling top-level function,
    > > I want to hook it by somehow injecting local variable with the same
    > > name.
    > >
    > > Simply doing something like
    > >
    > > ;(function() { setTimeout = function() { ...my custom implementation
    > > })();
    > >
    > > is not ideal, as that'll taint global scope. Actually, I can live with
    > > that for now, but it's my technical interest to find a way to define it locally.
    tai, Nov 18, 2006
    #2
    1. Advertising

  3. tai

    VK Guest

    > I know JS's scoping rule will make any attempt void once these
    > registered functions do a nested function call (which resets
    > scope chain). However, how about directly inside these registered
    > functions? Is it possible to re-define top-level functions just
    > directly inside these (= func0, func1, func2) registered methods?


    Other words, is it possible to re-compile run-time the execution
    context? Actually JavaScript is one of few programming languages (if
    not the single one at all) that allows you to do such things, but for
    that you have of course to abandon the idea of working with the
    compiled code itself and use new Function(strSource) instead.

    By carefully tweaking and a bit memory leaking :) you can emulate
    Perl-like local scope for a set of function (var visible in this
    function and all functions called from within this function). But
    AFAICT it doesn't help in your situation because you want the effect
    for *any* random function sent to the constructor.
    VK, Nov 18, 2006
    #3
  4. tai

    tai Guest

    Hmm...maybe some clever use of "eval" might solve this problem.
    Say there's a method like

    var replacements = { needtrap: function() { ... } };
    var func0 = function() { needtrap() };

    What I want to do is something like

    with (replacements) { // install intercepting scope
    func0();
    }

    Of course this won't work because scope chain gets reset when calling
    func0 method. But with eval, maybe I can redefine it dynamically to

    var func0 = function() { with (replacements) { func0 } };

    But evaling function definition has a issue of "free"ing a binding to a
    local scope at the time of initial definition. So I guess the real
    solution
    is to redefine it as

    var func0 = function() {
    with (original_func0_scope) { // preserve original scope at the
    time of initial definition
    with (replacements) { // install intercepting scope
    // "needtrap" will be intercepted, bu others will work as
    originally defined
    func0;
    }
    }
    };

    which I'm not sure if it's possible or not.

    Maybe I need to require registering functions to provide an API to
    return such information (original_func0_scope = func0.get_scope()) ,
    or just go with global override.

    > > I know JS's scoping rule will make any attempt void once these
    > > registered functions do a nested function call (which resets
    > > scope chain). However, how about directly inside these registered
    > > functions? Is it possible to re-define top-level functions just
    > > directly inside these (= func0, func1, func2) registered methods?

    >
    > Other words, is it possible to re-compile run-time the execution
    > context? Actually JavaScript is one of few programming languages (if
    > not the single one at all) that allows you to do such things, but for
    > that you have of course to abandon the idea of working with the
    > compiled code itself and use new Function(strSource) instead.
    >
    > By carefully tweaking and a bit memory leaking :) you can emulate
    > Perl-like local scope for a set of function (var visible in this
    > function and all functions called from within this function). But
    > AFAICT it doesn't help in your situation because you want the effect
    > for *any* random function sent to the constructor.
    tai, Nov 19, 2006
    #4
  5. tai

    tai Guest

    > For starters, "goto" is a reserved keyword, so you'll need a different
    > name for your function there.


    Thanks, I simply thought "goto" was OK as JS does not have "goto" and
    IE JScript accepted it - I'll change that.

    > Hm, this is a distinctly non-JavaScript way of going about things,
    > which leads me to think that you're experience in a different language
    > (Java, perhaps?) and are trying out techniques that may be appropriate
    > in a different language but are quite non-idiomatic to JavaScript.


    Close, but not really. For FSM, I first started with something similar
    to your example, but following two goals drove me to this state:

    1. I wanted the use of this framework straightforward and transparent
    2. Asynchronous operation support (like XmlHttpRequest)

    For goal #1, I wanted to keep registering function look clean as
    possible so they would not depend too much on this framework.
    This helps porting/reusing existing functions.

    And due to goal #2, I had to abandon use of "return <next>;" way
    to initiate state shift - thus introduction of "goto". This is somewhat
    off-topic, but things start to look interesting when you think about
    integrating async op like below into FSM:

    var func0 = function() {
    var img = new Image(); img.src = "..."; img.onload = function() {
    .... }; ...;
    }
    ...
    var sm = new StateMachine(func0, func1, ...);
    sm.start(func0, arg);

    But I must agree this is "quite non-idiomatic to JavaScript" like
    you said, as this implementation was really tricky. OTOH, I think
    I'm getting close to establishing goal #1.

    > > var func0 = function func0(arg) { alert("func0"); goto(func2);
    > > alert("notreached") };
    > > var func1 = function func1(arg) { alert("func1"); goto(-1) };
    > > var func2 = function func2(arg) { alert("func2"); goto(-1, true) };
    > >
    > > var sm = new StateMachine(func0, func1, func2);
    > > sm.start(func0, arg); // alerts in order of: func0, func2, func1

    >
    >
    > I would do this (if I understand you correctly) like so:
    >
    > function StateMachine() {
    > // assumes all arguments are callable as functions -
    > // in real life you'll want to verify this
    > this.funcs = arguments;
    > }
    >
    >
    > StateMachine.prototype.callFunc = function(args) {
    > var num = -1;
    > if (args.length && args.length >= 1) {
    > num = args[0];
    > args = args[1];
    > }
    > if (num >= 0) {
    > this.callFunc(this.funcs[num](args));
    > }
    > }
    >
    > // You can either pass in the functions as anonymous like so,
    > // or first define some functions and pass them in by name
    > var sm = new StateMachine(function() {
    > alert(1);
    > // return value determines next function to be called
    > // you can also have some logic here to decide what
    > // that should be
    > return [2];
    > },
    > function(arg) {
    > alert(arg);
    > return [-1];
    > },
    > function() {
    > alert(3);
    > return [1, 'howdy!'];
    > });
    >
    > // then you call the number you want to start with as first item in an
    > array
    > // if you want multiple args you can pass those as a nested array
    > // remember in JS you can mix types in a single array
    > sm.callFunc([0]);
    tai, Nov 19, 2006
    #5
  6. tai

    VK Guest

    tai wrote:
    > Hmm...maybe some clever use of "eval" might solve this problem.
    > Say there's a method like
    >
    > var replacements = { needtrap: function() { ... } };
    > var func0 = function() { needtrap() };
    >
    > What I want to do is something like
    >
    > with (replacements) { // install intercepting scope
    > func0();
    > }
    >
    > Of course this won't work because scope chain gets reset when calling
    > func0 method. But with eval, maybe I can redefine it dynamically to
    >
    > var func0 = function() { with (replacements) { func0 } };


    I am still not sure if I got right the architecture you are willing to
    achieve, so sorry if a useless advise below.

    Unless you need to run your code in JScript.NET compiled with /quick -
    unless that you can always augment the function object:

    <script type="text/javascript">
    function CallDispatcher() {
    for (var i=0; i<arguments.length; ++i) {
    if (typeof arguments == 'function') {
    arguments['$goto'] = new Function('window.alert('+i+');');
    arguments();
    }
    }
    }

    function f1() {
    if (f1.$goto) {
    f1.$goto();
    }
    }

    function f2() {
    if (f2.$goto) {
    f2.$goto();
    }
    }

    function f3() {
    if (f3.$goto) {
    f3.$goto();
    }
    }


    function init(arg) {
    CallDispatcher(f2,f3,f1);
    }

    window.onload = init;
    </script>

    >From the other side (as other poster pointed out) it looks like you are

    brute force trying to emplement a structure of one language into all
    another language. Usually it doesn't work or it leads to ugly and
    unstable solutions. Maybe instead of code samples it would be more
    helpful to see the block-schema you want to implement: so some standard
    OOP solution could be suggested.
    VK, Nov 19, 2006
    #6
  7. tai

    Bart Lateur Guest

    tai wrote:

    >Simply doing something like
    >
    > ;(function() { setTimeout = function() { ...my custom implementation
    >})();
    >
    >is not ideal, as that'll taint global scope. Actually, I can live with
    >that for now,
    >but it's my technical interest to find a way to define it locally.


    make setTimeout a (local) var?

    var setTimeout = function () { .... };

    --
    Bart.
    Bart Lateur, Nov 19, 2006
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Thaddius39
    Replies:
    0
    Views:
    359
    Thaddius39
    Nov 20, 2005
  2. Jamie R. Parent

    Injecting a C side object into the local dict

    Jamie R. Parent, Feb 11, 2005, in forum: Python
    Replies:
    1
    Views:
    252
    python
    Feb 11, 2005
  3. sairam
    Replies:
    2
    Views:
    354
    Steve Holden
    Apr 5, 2007
  4. Zhidian Du
    Replies:
    0
    Views:
    140
    Zhidian Du
    Feb 21, 2004
  5. Jake Barnes
    Replies:
    13
    Views:
    135
    Thomas 'PointedEars' Lahn
    Feb 13, 2006
Loading...

Share This Page