Could someone please explain? I think I'm losing my mind here.
How does dereferencing work in Krpano?
-
-
Consider this:
Code
Display More<onstart="test-dereferencing(2,'spot-three')" /> <testarray> <point name="one" /> <point name="two" /> <point name="three" /> <spot name="spot-one" x="1" /> <spot name="spot-two" x="2" /> <spot name="spot-three" x="3" /> </testarray> <action name="test-dereferencing"> set(i,"2"); set(%3,"2"); set(tmpname,'spot-three'); trace(" "); trace('i is ',i, ' testarry.point[i] is ', testarray.point[i].name); trace('i is ',i, ' testarry.point[i] is ', testarray.point[get(i)].name); 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)); trace(" "); trace('arg1 is ',%1, ' testarry.point[arg1] is ', testarray.point[%1].name); trace('arg1 is ',%1, ' testarry.point[arg1] is ', testarray.point[get(%1)].name); trace('arg1 is ',%1, ' testarry.point[arg1] is ', get(testarray.point[get(%1)].name)); trace('arg1 is ',%1, ' testarry.point[arg1] is ', get(testarray.point[%1].name)); trace(" "); trace('arg3 is ',%3, ' testarry.point[arg3] is ', testarray.point[%3].name); trace('arg3 is ',%3, ' testarry.point[arg3] is ', testarray.point[get(%3)].name); trace('arg3 is ',%3, ' testarry.point[arg3] is ', get(testarray.point[get(%3)].name)); trace('arg3 is ',%3, ' testarry.point[arg3] is ', get(testarray.point[%3].name)); trace(" "); trace('arg2 is ',%2, ' testarry.spot[arg2] is ', testarray.spot[%2].x); trace('arg2 is ',%2, ' testarry.spot[arg2] is ', testarray.spot[get(%2)].x); trace('arg2 is ',%2, ' testarry.spot[arg2] is ', get(testarray.spot[get(%2)].x)); trace('arg2 is ',%2, ' testarry.spot[arg2] is ', get(testarray.spot[%2].x)); trace(" "); trace('tmpname is ',tmpname, ' testarry.spot[tmpname] is ', testarray.spot[tmpname].x); trace('tmpname is ',tmpname, ' testarry.spot[tmpname] is ', testarray.spot[get(tmpname)].x); trace('tmpname is ',tmpname, ' testarry.spot[tmpname] is ', get(testarray.spot[get(tmpname)].x)); trace('tmpname is ',tmpname, ' testarry.spot[tmpname] is ', get(testarray.spot[tmpname].x)); trace(" "); trace('dereference-this(get(tmpname))'); dereference-this(get(tmpname)); trace(" "); txtadd(newname,'spot-',testarray.point[%1].name); trace(newname); txtadd(newname,'spot-',get(testarray.point[%1].name)); trace(newname); trace('newname is ',newname, ' testarry.spot[newname] is ', testarray.spot[newname].x); trace('newname is ',newname, ' testarry.spot[newname] is ', testarray.spot[get(newname)].x); trace('newname is ',newname, ' testarry.spot[newname] is ', get(testarray.spot[get(newname)].x)); trace('newname is ',newname, ' testarry.spot[newname] is ', get(testarray.spot[newname].x)); trace(" "); dereference-this(get(newname)); </action> <action name="dereference-this"> trace('arg1 is ',%1, ' testarry.spot[%1] is ', testarray.spot[%1].x); trace('arg1 is ',%1, ' testarry.spot[%1] is ', testarray.spot[get(%1)].x); trace('arg1 is ',%1, ' testarry.spot[%1] is ', get(testarray.spot[get(%1)].x)); trace('arg1 is ',%1, ' testarry.spot[%1] is ', get(testarray.spot[%1].x)); </action>
Result:
Code
Display MoreINFO: i is 2 testarry.point[i] is testarray.point[i].name INFO: i is 2 testarry.point[i] is testarray.point[get(i)].name INFO: i is 2 testarry.point[i] is 2 INFO: i is 2 testarry.point[i] is 2 INFO: INFO: arg1 is 2 testarry.point[arg1] is three INFO: arg1 is 2 testarry.point[arg1] is testarray.point[get(2)].name INFO: arg1 is 2 testarry.point[arg1] is 2 INFO: arg1 is 2 testarry.point[arg1] is three INFO: INFO: arg3 is 2 testarry.point[arg3] is testarray.point[null].name INFO: arg3 is 2 testarry.point[arg3] is testarray.point[get(null)].name INFO: arg3 is 2 testarry.point[arg3] is 2 INFO: arg3 is 2 testarry.point[arg3] is 2 INFO: INFO: arg2 is spot-three testarry.spot[arg2] is 3 INFO: arg2 is spot-three testarry.spot[arg2] is testarray.spot[get(spot-three)].x INFO: arg2 is spot-three testarry.spot[arg2] is 2 INFO: arg2 is spot-three testarry.spot[arg2] is 3 INFO: INFO: tmpname is spot-three testarry.spot[tmpname] is testarray.spot[tmpname].x INFO: tmpname is spot-three testarry.spot[tmpname] is testarray.spot[get(tmpname)].x INFO: tmpname is spot-three testarry.spot[tmpname] is 2 INFO: tmpname is spot-three testarry.spot[tmpname] is 2 INFO: INFO: dereference-this(get(tmpname)) INFO: arg1 is spot-three testarry.spot[spot-three] is 3 INFO: arg1 is spot-three testarry.spot[spot-three] is testarray.spot[get(spot-three)].x INFO: arg1 is spot-three testarry.spot[spot-three] is 2 INFO: arg1 is spot-three testarry.spot[spot-three] is 3 INFO: INFO: spot-testarray.point[2].name INFO: spot-three INFO: newname is spot-three testarry.spot[newname] is testarray.spot[newname].x INFO: newname is spot-three testarry.spot[newname] is testarray.spot[get(newname)].x INFO: newname is spot-three testarry.spot[newname] is 2 INFO: newname is spot-three testarry.spot[newname] is 2 INFO: INFO: arg1 is spot-three testarry.spot[spot-three] is 3 INFO: arg1 is spot-three testarry.spot[spot-three] is testarray.spot[get(spot-three)].x INFO: arg1 is spot-three testarry.spot[spot-three] is 2 INFO: arg1 is spot-three testarry.spot[spot-three] is 3
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:
it is not possible.... I think parameters must be set inside the calling of the action...
in fact the code above is equal to:
Try this:
The result is:
That's why:Codetrace('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:
The two trace returns null, so 2....Also, it seems that using get() like this:
it is not resolved as expected... the same is true when a variable is used as part of a variable like:
and then:
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 titlesI'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:
Codetxtadd(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:
Codedereference-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:
Code
Display More<mappoints> <stuff name="one" /> <stuff name="two" /> </mappoints> <plugin name="loc-one" /> <plugin name="loc-two" /> <action name="scale-stuff"> foreach(mappoints.stuff,i, scale2(get(i)); ); </action> <action name="scale2"> txtadd(tmpname,'loc-',get(mappoints.stuff[%1].name)); do-scale-stuff(get(tmpname)); </action> <action name="do-scale-stuff"> switch(plugin[%1].destscale,1,0.3); tween(plugin[%1].scale,$destscale); </action>
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:
Code
Display More<krpano version="1.0.8" onstart="test-dereferencing()" > <testarray> <point name="one" /> <point name="two" /> <point name="three" /> <spot name="spot-one" x="1" /> <spot name="spot-two" x="2" /> <spot name="spot-three" x="3" /> </testarray> <action name="trace_testarray_point"> trace("testarray point %1 =",testarray.point[%1].name); </action> <action name="test-dereferencing"> set(i,0); trace_testarray_point(get(i)); inc(i); trace_testarray_point(get(i)); inc(i); trace_testarray_point(get(i)); </action> </krpano>
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
works and
works if %1 is a valid address
butwon't work, nor will
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
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:
Code
Display More<krpano version="1.0.8" onstart="test-dereferencing()" > <testarray> <point name="one" /> <point name="two" /> <point name="three" /> <spot name="spot-one" x="1" /> <spot name="spot-two" x="2" /> <spot name="spot-three" x="3" /> </testarray> <action name="trace_testarray_point"> trace("testarray point %1 =",testarray.point[%1].name); </action> <action name="test-dereferencing"> set(i,0); trace_testarray_point(get(i)); inc(i); trace_testarray_point(get(i)); inc(i); trace_testarray_point(get(i)); inc(i); trace_testarray_point(get(i)); </action> </krpano>
This code prints outQuote
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!
Code
Display More<krpano version="1.0.8" onstart="test-dereferencing()" > <action name="trace_action"> trace("%1%2%3%4%5%6"); </action> <action name="test-dereferencing"> set(i,0); set(j,i);<!--note this sets j to the string "i"--> set(k,get(i)); trace("i=",i," j=",j," k=",k); trace_action("i=",i," j=",j," k=",k); trace(" get(i)=",get(i)," get(j)=",get(j)," get(k)=",get(k)); trace_action(" get(i)=",get(i)," get(j)=",get(j)," get(k)=",get(k)); </action> </krpano>
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)=0By now I'm sure you're head is about to explode so we'll stop here. I hope this was helpful.
steve
-
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!
Code
Display More<krpano version="1.0.8" onstart="why_not_something_like_this()" > <mappoints> <stuff name="one" /> <stuff name="two" /> </mappoints> <plugin name="loc-one" /> <plugin name="loc-two" /> <action name="why_not_something_like_this"> foreach(mappoints.stuff,i, txtadd(tmp,'txtadd(tmpname,"loc-",get(mappoints.stuff[',get(i),'].name));'); eval_str(get(tmp)); txtadd(tmp,' switch(plugin[',get(tmpname),'].destscale,1,0.3); tween(plugin[',get(tmpname),'].scale,$destscale); '); eval_str(get(tmp)); ); </action> <!-- _eval_action private function to execute eval action --> <action name="_eval_action"> trace("Error in eval: push/pop stack corrupted"); <!-- this line should never execute --> </action> <!-- eval_str(evalstr.str); accepts a single string of action[s] which are executing in a blocking manner--> <action name="eval_str"> <!--evalstr.str--> push(action[_eval_action].content); set(action[_eval_action].content,%1); _eval_action(%2,%3,%4,%5,%6,%7,%8,%9); pop(action[_eval_action]content); </action> <!-- _foreach_action private function to execute foreach loop body action --> <action name="_foreach_action"> trace("Error in foreach loop: push/pop stack corrupted"); <!-- this line should never execute --> </action> <!-- foreach <objectid> <index.str> <body.str> foreach loop function which iterates the action across each of the objects--> <action name="foreach"> <!--objectid.str,index.str,body.str--> sub(%2,%1.count,1); push(action[_foreach_action].content); set(action[_foreach_action].content,"if(%2 GE 0,%3;dec(%2);_foreach_action(););"); _foreach_action(); pop(action[_foreach_action].content); </action> </krpano>
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:
Code
Display More<action name="scaler"> foreach(mappoints.stuff,i, txtadd(action[scaler].tmp,'txtadd(action[scaler].tmpname,"loc-",get(mappoints.stuff[',get(i),'].name));'); eval_str(get(action[scaler].tmp)); txtadd(action[scaler].tmp,' switch(plugin[',get(action[scaler].tmpname),'].destscale,1,0.3); tween(plugin[',get(action[scaler].tmpname),'].scale,$destscale); '); eval_str(get(action[scaler].tmp)); ); </action>
I'm almost embarrassed to post such ugly codeHope this was helpful
steve
-
Thanks Steve!
I was on the verge of just dropping krpano and doing something easier, like debugging obfuscated perl.
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
What's worse, seems you're rightSome other observations (this was/is a long night!):
Having node names start with numbers is a bad idea:
There is a problem here:
Codeforeach(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
-
I was on the verge of just dropping krpano and doing something easier, like debugging obfuscated perl.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!
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:
Code
Display More<action name="hide-this"> if(%1 == null, derefthis(%0,get(name)), set(plugin[%1].enabled,false); tween(plugin[%1].alpha,0,0.3,null,set(plugin[%1].visible,false)); tween(plugin[%1].textblur,20,0.3); tween(plugin[%1].blur,20,0.3); ); </action> <!-- derefthis(caller,original-caller) --> <action name="derefthis"> action(%1,%2); </action>
Now I can have one action for all plugins :)
-
OTOH I was happy with this little thing:Code
Display More<action name="hide-this"> if(%1 == null, derefthis(%0,get(name)), set(plugin[%1].enabled,false); tween(plugin[%1].alpha,0,0.3,null,set(plugin[%1].visible,false)); tween(plugin[%1].textblur,20,0.3); tween(plugin[%1].blur,20,0.3); ); </action> <!-- derefthis(caller,original-caller) --> <action name="derefthis"> action(%1,%2); </action>
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
- the access to an array element is possible either it's 'name' or by a numeric index (0 - array.count),
- '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 - when calling an action - the code of the action will be first parsed for the the %0 - %9 placeholders,
-
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-%99best 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!