Announcement

Collapse
No announcement yet.

efsInternal and function pointer arg issue (not as the first arg)

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • efsInternal and function pointer arg issue (not as the first arg)

    While debugging some code that passes a function pointer to efsInternal (not as its first parameter) I realized there was a problem when creating two series. Specifically, it seems that under certain circumstances the second series to be created always contains the first series' values.

    I whittled my original code down to the test code that follows, plus I added a few extra test cases. I would be appreciative if anybody could tell me why the two approaches that don't seem to work display their horizontal lines on top of each other instead of separately? I.e. why do their series have the same values? Thx.

    Jeff

    PHP Code:
    function preMain()
    {
        var 
    fp = new FunctionParameter("approach"FunctionParameter.STRING);
        
    fp.addOption("doesntwork");
        
    fp.addOption("doesntworkeither");
        
    fp.addOption("butthisworks");
        
    fp.addOption("andthisworkstoo");
        
    fp.setDefault("doesntwork");
    }

    var 
    series1 null;
    var 
    series2 null;
    var 
    fullyInitialized null;

    function 
    main(approach)
    {
        if (!
    fullyInitialized)
        {
        if (
    approach == "doesntwork")
        {
            if (
    series1 == null)
                    
    series1 efsInternal("functionProxy"regurgitate, [1]);
            if (
    series2 == null)
                    
    series2 efsInternal("functionProxy"regurgitate, [2]);
        }
        else if (
    approach == "doesntworkeither")
        {
            if (
    series1 == null)
                    
    series1 efsInternal("functionProxy"regurgitate, [1]);
            if (
    series2 == null)
                    
    series2 efsInternal("functionProxy"anotherRegurgitate, [2]);
        }
        else if (
    approach == "butthisworks")
        {
            if (
    series1 == null)
                    
    series1 efsInternal("functionProxy"regurgitate, [1]);
            if (
    series2 == null)
                    
    series2 efsInternal("anotherFunctionProxy"regurgitate, [2]);
        }
        else if (
    approach == "andthisworkstoo")
        {
            if (
    series1 == null)
                    
    series1 efsInternal("regurgitate"1);
            if (
    series2 == null)
                    
    series2 efsInternal("regurgitate"2);
        }
        else
        {
            throw 
    "oops!";
        }
            
    fullyInitialized true;
        }

        if (
    getCurrentBarIndex() == -4)
        {
        
    debugPrintln(approach);
        
    debugPrintln("  series1 = " series1.getValue(0));
        
    debugPrintln("  series2 = " series2.getValue(0));
        }

        return [
    series1.getValue(0), series2.getValue(0)];
    }

    function 
    functionProxy(functionPtrargs)
    {
        return 
    functionPtr.apply(nullargs);
    }

    function 
    anotherFunctionProxy(functionPtrargs)
    {
        return 
    functionPtr.apply(nullargs);
    }

    function 
    regurgitate(arg)
    {
        return 
    arg;
    }

    function 
    anotherRegurgitate(arg)
    {
        return 
    arg;


  • #2
    It seems the problem has nothing to do with function pointers. I added the "howeverthisdoesntwork" test case (see the new code below) and got the undesired behavior. That case is very similar to the "andthisworkstoo" case, so it appears that passing an array of values as a parameter to efsInternal is what is causing the problem. Is this a misuse of efsInternal on my part?

    PHP Code:
    function preMain()
    {
        var 
    fp = new FunctionParameter("approach"FunctionParameter.STRING);
        
    fp.addOption("doesntwork");
        
    fp.addOption("doesntworkeither");
        
    fp.addOption("butthisworks");
        
    fp.addOption("andthisworkstoo");
        
    fp.addOption("howeverthisdoesntwork");
        
    fp.setDefault("doesntwork");
    }

    var 
    series1 null;
    var 
    series2 null;
    var 
    fullyInitialized null;

    function 
    main(approach)
    {
        if (!
    fullyInitialized)
        {
            if (
    approach == "doesntwork")
            {
                if (
    series1 == null)
                    
    series1 efsInternal("functionProxy"regurgitate, [1]);
                if (
    series2 == null)
                    
    series2 efsInternal("functionProxy"regurgitate, [2]);
            }
            else if (
    approach == "doesntworkeither")
            {
                if (
    series1 == null)
                    
    series1 efsInternal("functionProxy"regurgitate, [1]);
                if (
    series2 == null)
                    
    series2 efsInternal("functionProxy"anotherRegurgitate, [2]);
            }
            else if (
    approach == "butthisworks")
            {
                if (
    series1 == null)
                    
    series1 efsInternal("functionProxy"regurgitate, [1]);
                if (
    series2 == null)
                    
    series2 efsInternal("anotherFunctionProxy"regurgitate, [2]);
            }
            else if (
    approach == "andthisworkstoo")
            {
                if (
    series1 == null)
                    
    series1 efsInternal("regurgitate"1);
                if (
    series2 == null)
                    
    series2 efsInternal("regurgitate"2);
            }
            else if (
    approach == "howeverthisdoesntwork")
            {
                if (
    series1 == null)
                    
    series1 efsInternal("regurgitate", [1]);
                if (
    series2 == null)
                    
    series2 efsInternal("regurgitate", [2]);
            }
            else
            {
                throw 
    "oops!";
            }
            
    fullyInitialized true;
        }

        if (
    getCurrentBarIndex() == -4)
        {
            
    debugPrintln(approach);
            
    debugPrintln("  series1 = " series1.getValue(0));
            
    debugPrintln("  series2 = " series2.getValue(0));
        }

        return [
    series1.getValue(0), series2.getValue(0)];
    }

    function 
    functionProxy(functionPtrargs)
    {
        return 
    functionPtr.apply(nullargs);
    }

    function 
    anotherFunctionProxy(functionPtrargs)
    {
        return 
    functionPtr.apply(nullargs);
    }

    function 
    isArray(obj)
    {
        return (
    obj!==null) && (obj!=undefined) && (obj.constructor == Array);
    }

    function 
    regurgitate(arg)
    {
        if (
    isArray(arg))
            return 
    arg[0];
        else
            return 
    arg;
    }

    function 
    anotherRegurgitate(arg)
    {
        return 
    arg;

    Comment


    • #3
      Hello jphelps,

      Thanks for posting your code examples.

      The efsInternal() and efsExternal() have a built-in mechanism to first check to see if a series object with the same parameters has already been created. If one exists the variable is assigned to the existing series object. A second instance of the object is not created. This was done to avoid an "out of memory" problem that would occur prior to EFS2 where a user would do something like below.

      PHP Code:
      function main() {
          var 
      ma = new MAStudy(...);

      The EFS1 engine would create a new instance of an MAStudy() object each time main() was executed. This would eventually fill up all available memory.

      The EFS2 engine resolves this problem. One of the main reasons for developing the EFS2 functions was to help get away from using JavaScript arrays as this adds complexity for the more novice programmers. We didn't anticipate that arrays would be used as parameters in the manner in which you currently are.

      At this point I'm sure you're thinking that an array of [1] is different than [2] so there shouldn't be a problem. These two arrays do contain different values. That part is true. However, the EFS2 engine is not looking at the values within these arrays. It is only looking at what this parameter is. In essence, it sees an Array object of size 1. So, in your following example,

      PHP Code:
      if (approach == "doesntwork")
              {
                  if (
      series1 == null)
                      
      series1 efsInternal("functionProxy"regurgitate, [1]);
                  if (
      series2 == null)
                      
      series2 efsInternal("functionProxy"regurgitate, [2]);
              } 
      series1 instantiates the series object, which the EFS2 engine sees as functionProxy(pointer to regurgitate, Array of size 1).

      When efsInternal() is evaluated for the series2 variable, the engine sees functionProxy(pointer to regurgitate, Array of size 1) and thinks this object with these parameters has already been created. So series2 now references the same series object as series1. This is why they both plot a line at 1.

      For example sake, if you changed the array size of one of these array parameters as below,

      PHP Code:
      if (approach == "doesntwork")
              {
                  if (
      series1 == null)
                      
      series1 efsInternal("functionProxy"regurgitate, [11]);
                  if (
      series2 == null)
                      
      series2 efsInternal("functionProxy"regurgitate, [2]);
              } 
      the EFS2 engine now sees series1 with an array parameter of size 2 and series2 with an array parameter of size 1. In this case the parameters are different and will initialize two unique series objects, which will then plot at line at 1 and 2 as expected. Hope this helps.
      Jason K.
      Project Manager
      eSignal - an Interactive Data company

      EFS KnowledgeBase
      JavaScript for EFS Video Series
      EFS Beginner Tutorial Series
      EFS Glossary
      Custom EFS Development Policy

      New User Orientation

      Comment


      • #4
        Jason,

        Thanks for the explanation. FWIW, before reading your reply I had already trudged forward with a solution where I put the array into a unique global variable, passed the name of that variable to the function used by efsInternal, and then accessed the array stored in that global var from within the function when it gets called. This seems to work. However, after reading your response and experimenting a little I have decided to do away with the global var approach and simply add an unused unique string parameter to the function's parameter list. As long as that string is unique it seems to work fine (which is probably the sole reason the global var approach worked.) Thanks for your help.

        Jeff

        Comment


        • #5
          Hello Jeff,

          You're most welcome.

          I like your solution for adding the additional unused string parameter as well. Great idea.
          Jason K.
          Project Manager
          eSignal - an Interactive Data company

          EFS KnowledgeBase
          JavaScript for EFS Video Series
          EFS Beginner Tutorial Series
          EFS Glossary
          Custom EFS Development Policy

          New User Orientation

          Comment

          Working...
          X