How does dereferencing work in Krpano?

  • Consider this:

    Result:

    Please shed some light on this?

  • Hi hitodenashi,

    I have played a little with your request....
    I have noticed 2 things:
    It seems that setting a parameter of an action in this way:

    Code
    set(%3,"2");


    it is not possible.... I think parameters must be set inside the calling of the action...
    in fact the code above is equal to:

    Code
    set(null,"2");


    Try this:

    Code
    trace('%3 ',%3);


    The result is:

    Code
    INFO: null 2


    That's why:

    Code
    trace('i is ',i, ' testarry.point[i] is ', get(testarray.point[get(i)].name));
    trace('i is ',i, ' testarry.point[i] is ', get(testarray.point[i].name));


    Returns:

    Code
    INFO: i is 2 testarry.point[i] is 2
    INFO: i is 2 testarry.point[i] is 2


    The two trace returns null, so 2....

    Also, it seems that using get() like this:

    Code
    testarray.point[get(i)].name


    it is not resolved as expected... the same is true when a variable is used as part of a variable like:

    Code
    testarray.point[i].name


    and then:

    Code
    get(testarray.point[get(i)].name)
    get(testarray.point[i].name)


    returns null....

    Sorry about my rudimentary explanation... I hope this can help in a way...

    SAlut.

  • Thank you!
    I'm grateful for any advice. The documentation is...a tad lacking, and most of the good stuff is somewhere deep in the forums, often under misleading titles *huh*

    I've been just throwing stuff at krpano and trying to make sense of the results.

    What is bugging me most is that I can't find a way to use variable names in other variables. Like this:

    Code
    txtadd(newname,'spot-',get(testarray.point[%1].name));
    trace(newname);
    trace('newname is ',newname, ' testarry.spot[newname] is ', testarray.spot[newname].x);

    That doesn't work :/

    But if I pass it through an action call, like this:

    Code
    dereference-this(get(newname));
    
    
    <action name="dereference-this">
    trace('arg1 is ',%1, ' testarry.spot[%1] is ', testarray.spot[%1].x);
    </action>

    It's magically working.

    Seems as though % sigil variables are not treated the same as regular ones?
    I also learned that using 'set(x,"0")' makes a global variable x. Any way to make it local variables?
    Also what's the deal with the $ sigil variables?


    That leads me to this:

    It works, but it makes no sense? Maybe I'm approaching it from the wrong angle?

    Why not something like this:

    Code
    <action name="scale-stuff">
    		foreach(mappoints.stuff,i,
    txtadd(tmpname,'loc-',get(mappoints.stuff[i].name));	
     			switch(plugin[tmpname].destscale,1,0.3);
    			tween(plugin[tmpname].scale,$destscale);   
    		);
    		</action>

    I hope Klaus can lend a hand here.

  • Wow Michel!!!!!!

    There's not a week that goes by where I don't learn something from one of your posts, but this one takes the cake. I was looking at the results from hitodenashi's test function and I couldn't figure out why the "2" kept showing up. I did notice that he set(%3,2), but hadn't figured out that this assigns a value to null (which is of course is a very bad thing). Bravo for reasoning this out!

    hitodenashi,

    There are a couple of ways to accomplish what you're trying to do. The easiest method to use a variable as an index is to pass the dereferenced value through an action argument. This is essentially the method you used in lines 24,27,36,39,66, and 69 of your test-dereferencing example.

    Here's a simplified example:

    Here note that we dereference the variable i with the get() function, pass the value through the argument where it is substituted into the square brackets and used to index the point. Action arguments are simply substituted into the action code. It doesn't matter what the context of the code surrounding the argument is, it can even be in quotes, the argument is simply substituted in much the same manner as a macro substitution in C.

    This is important because you can't dereference a variable between square brackets in the krpano scripting language. So

    Code
    testarray.point[0]

    works and

    Code
    testarray.point[%1]

    works if %1 is a valid address
    but

    Code
    testarray.point[i].name

    won't work, nor will

    Code
    testarray.point[get(i)].name

    because the square brackets do not allow internal dereferencing.

    I've posted before that variable dereferencing is one of the most confusing aspects of krpano's scripting language. I believe the confusing inconsistencies arise because of Klaus' need to keep the scripts as backward compatible as possible. Since the scripts support unquoted strings, there are a number of unconventional behaviors in the language.

    I'm only aware of two places where krpano automatically dereferences variables:
    1) the predicate of an if statement --so don't use get() in there
    2) the arguments of the trace function.

    You'll note that

    Code
    trace(testarray.point[%1].name);

    will produce the correct result for a valid address. That's because the trace function automatically dereferences the variable when it is a standalone argument. (that's why the i variable in lines 18-21 of your example were properly resolved in the 'i =',i, part of the trace statement).

    One of the confusing things about automatic variable dereferencing (in if statements and trace statements), is that when the variable resolves to null, krpano converts it back to the original variable description. Thus, if foo is a null variable, trace(foo) prints "foo" rather than "null". This is Klaus' way of supporting unquoted strings. Unfortunately it can be confusing, for example if we provide an invalid address to your example array:


    This code prints out

    Quote


    INFO: testarray point 0 =one
    INFO: testarray point 1 =two
    INFO: testarray point 2 =three
    INFO: testarray point 3 =testarray.point[3]

    the value of testarray.point[3].name is actually null, but krpano substitutes the original string back in for the trace.

    Note that the fact that variables are automatically dereferenced in the trace function, but are not automatically dereferenced in action arguments, can lead to very confusing debugging sessions. Note that in the following example the arguments are exactly the same for the trace statement and the trace_action statement, but the resulting traces are different!

    Here are the results:

    Quote


    INFO: i=0 j=i k=0
    INFO: i=i j=j k=k
    INFO: get(i)=0 get(j)=0 get(k)=0
    INFO: get(i)=0 get(j)=i get(k)=0

    By now I'm sure you're head is about to explode so we'll stop here. I hope this was helpful.

    steve

    Edited once, last by pinsane (March 16, 2010 at 7:01 AM).

  • Seems as though % variables are not treated the same as regular ones?

    Yes, they are simple substitutions so they can go between square brackets.


    It works, but it makes no sense? Maybe I'm approaching it from the wrong angle?

    Actually, you're using the most readable approach. It works because you are evaluating the variable and then passing it through an argument where it is substituted into the square brackets. It's the most straightforward method.

    Here's another solution more along the lines of your request, but unfortunately you still have to use hack-ey txtadd commands. Personally, I think your earlier approach is easier to understand!


    Also what's the deal with the $ variables?

    I believe they only work with the tween function.


    I also learned that using 'set(x,"0")' makes a global variable x. Any way to make it local variables?

    Not really. I'd really like to find a way to use scoped variables but haven't found an elegant solution. Krpano kinda supports local variables in that functions called from plugins inherit the plugin's attributes as variables. Perhaps Klaus could shine some light as to how we might exploit that from a general programming point of view (ie. when the actions are not called from a plugin event).

    I too don't like cluttering up the global-variable space. I've been using the attributes of the action as pseudo local variables but it makes the code look uglier and you need to be very careful if you use recursion. Here's the above example recoded using attributes as fake local variables:


    I'm almost embarrassed to post such ugly code *unsure*

    Hope this was helpful

    steve

  • Thanks Steve!
    I was on the verge of just dropping krpano and doing something easier, like debugging obfuscated perl. *g*
    This stuff should really go into the documentation or a wiki.

    BTW, I propose a new attribute/pragma in the krpano node: scripting="sane" which drops all the nasty backward compatibility.

    Quote from pinsane


    Actually, you're using the most readable approach. It works because you are evaluating the variable and then passing it through an argument where it is substituted into the square brackets. It's the most straightforward method.


    Ah, I meant to say that it doesn't make sense to program that way....and then you go and say that it's the most straightforward way *pinch*
    What's worse, seems you're right *wacko*

    Some other observations (this was/is a long night!):

    Having node names start with numbers is a bad idea:

    Code
    <mapthings>
    <floor name="2nd" />
    </mapthings>


    There is a problem here:

    Code
    foreach(things,i,scale-things(get(i)));
    is a no-go, but
    foreach(things,i,scalethings(get(i)));
    is ok.
    foreach(things,i,do-scale-things(get(i)));
    is ok.

    WTF?
    foreach(things,i,scale-things(get(i))) works but scale-things() gets passed a null?

    Krpano is practicing some kind of bizarre psychological warfare on me *confused*


  • I was on the verge of just dropping krpano and doing something easier, like debugging obfuscated perl. *g*

    BTW, I propose a new attribute/pragma in the krpano node: scripting="sane" which drops all the nasty backward compatibility.


    Thanks hitodenashi, I laughed out loud when reading this. I should know better than to read this board when eating breakfast. Anyone know how to get Count Chocula off a computer monitor?


    Having node names start with numbers is a bad idea:

    True dat. Krpano will try to interpret them as a number. Don't start variable names with a + or - either! *wink*

    Code
    foreach(things,i,scale-things(get(i)));
    is a no-go, but
    foreach(things,i,scalethings(get(i)));
    is ok.
    foreach(things,i,do-scale-things(get(i)));
    is ok.


    WTF?
    foreach(things,i,scale-things(get(i))) works but scale-things() gets passed a null?

    foreach(things,i,scale-things(get(i))); works for me. Can you post a complete example? scale-things() should pass a null to all %# arguments.

    steve


  • Thanks hitodenashi, I laughed out loud when reading this. I should know better than to read this board when eating breakfast. Anyone know how to get Count Chocula off a computer monitor?

    Glad I could help! Monitors need their cereals too, you know.


    foreach(things,i,scale-things(get(i))); works for me. Can you post a complete example? scale-things() should pass a null to all %# arguments.

    Um, my bad. Should have gone to bed 6 hours earlier, at least.
    Turns out I already had one scale-things() action I forgot about, that's what happens when you need three subroutines instead of one :(
    That, and the lack of sleep.

    OTOH I was happy with this little thing:

    Now I can have one action for all plugins :)


  • OTOH I was happy with this little thing:

    Now I can have one action for all plugins :)


    Very nice! Nice use of %0 for a general purpose function!

    steve

  • Hi,

    I haven't read all yet, but here a summary about variables/parameters and the placeholders
    and about how are they currently working:

    • when calling an action - the code of the action will be first parsed for the the %0 - %9 placeholders,
      and when found these will be replaced with the corresponding parameter,
      e.g. %1 is the first parameter, %2 the second one and so on,
      %0 is the name of the action itself
    • about the - get() - this is a special function, it will be only parsed when an action/function will be called,
      and it will be resolved before passing the parameters to the action,
      e.g.
      test(get(view.hlookat));
      will become first:
      test(0.000);
      and then the action 'test' will be called with this value, and there the value (here '0.000') will replace the %1 placeholders
    • using - get() - to the content of a variable is no necessary in some functions (e.g. in the add/sub/mul),
      because these functions are looking itself first if there is a variable with the given name, and if not they take the value,
      (the main reason for this behavior - these functions where implemented before get())
    • something about the array access via - []

      • the access to an array element is possible either it's 'name' or by a numeric index (0 - array.count),
        e.g. plugin[testname] or plugin[0]
      • using get inside [] is not possible!
      • since 1.0.8 beta 9 there is a way to use variables inside []
        variables can used by putting a '%' in front of their name,
        but only 'global' variables can be used there at the moment - e.g. set(plugin[%i].var, ...);
        variables with a path like "%plugin[name].var" can not be used inside []

        update for version 1.0.8.10:
        now it's also possible to use get inside the [] - e.g. set(plugin[get(var)].var, ...);
      • and it's not possible yet to use this %variable access for tween() function
    • 'local' variables
      when an action/code will be called from a plugin or hotspot event (e.g. onclick,...) the 'context' of the plugin/hotspot is used for variable access, that means the full path to the variable (e.g. plugin[name].var) is not needed in this case,


    best regards,
    Klaus

  • Thank you Klaus!!!!!! This new method of simple dereferencing will clean up alot of code in the future.

    May I respectfully make an observation? While this new capability is much appreciated, I'm worried that using the % character to dereference a variable may introduce confusion. The use of the %varname looks too similar to argument substitution (eg. %1 %2 etc). Right now %varname only works for global variables in indices, but I'm sure people will expect not only "path" dereferencing to work (ie. %plugin[foo].url) but for the %varname to work in a manner equivalent to arguments (allowed anywhere in the action, used in quoted strings etc). Perhaps a better choice would be instead to allow get(varname) to work in the brackets. The initial release could be limited to globals but eventually this could be expanded to "path" variables. I think this is what most people would expect to be the solution rather than a special case usage of the % symbol.

    If I could have my druthers, I'd rather the % symbol be used to extend the number of arguments for actions %1 - %9 then %a - %z.

    Once again, thanks for the great new feature, and thanks for krpano!

    submitted with respect,
    steve

  • Hi,

    thanks for your suggestions!
    yes, get() would be probably more logically
    I will add it in one of the next releases (and maybe let the '%' access in array indices undocumented)

    using "fullpath" variables will also come in one of the next releases,
    but this will take more time,

    using %a-%z is a good and simple idea for extending the number of parameters,
    but I have already added (in the next release) the possibility for using %10-%99

    best regards,
    Klaus


  • yes, get() would be probably more logically
    I will add it in one of the next releases

    ...

    have already added (in the next release) the possibility for using %10-%99


    Klaus, I was once the Director of Marketing for a couple of software companies, so I know how rarely one gets all of what they ask for. Thanks for adding these features and making such a great tool.

    steve

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!