|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Tue Feb 26, 2008 4:12 pm
[2.21] Incorrect context (or symbol lookup) in event handlers (found in 2.18) |
Per Zugg in one of the infamous scoping threads:
Zugg wrote: |
Quote: |
#var "//"%window/varname foo |
I really frown on doing anything like that. If you need to create variables within the window, it's better to use an OnLoad event in your package. The context for OnLoad is the window being loaded, so you can easily create variables there. |
The, ahem, context of this discussion was me wanting to be sure of creating a new variable inside my main character window, rather than somewhere else (e.g. inside the package where my script is defined). However, the procedure described by Zugg does not appear to work in 2.18, and it looks like a bug rather than a design decision.
Procedure
Before the first run at this bug, you'll need to create a package OnLoadTestPkg, with the following contents (I'll assume that anyone who cares about this bug doesn't need explicit instructions on how to create a package from XML - please correct me if I'm wrong):
Code: |
<?xml version="1.0" encoding="ISO-8859-1" ?>
<cmud>
<module name="OnLoadTestPkg" global="true">
<uid>{B3FCA8B7-901F-42EC-B919-700E5358AAAB}</uid>
<event event="onLoad" priority="10">
<value>#say OnLoad called in window %window
#say winVar: @winVar
#var onLoadVar %window</value>
</event>
</module>
</cmud>
|
Close down CMUD after doing this, to assure a 'normal' startup.
- Start CMUD.
- Hit ESC to exit the Session Window.
- Create winVar inside the untitled window by typing, at the command-line:
Code: |
#var winVar winVarVal |
Hit Ctrl-G to open the Package Editor. Note that the winVar variable is located inside the untitled window.
Choose File->Open, and select the OnLoadTestPkg created before. This should fire the onLoad event in each window.
You will see following in the untitled window:
Code: |
OnLoad called in window untitled
winVar:
|
In the package editor, you can verify that (a) the winVar variable still exists in the untitled window (with value 'winVarVal') and (b) the onLoadVar variable has been created inside the OnLoadTestPkg (with value 'untitled'!), NOT in the untitled window.
I expected the handler to execute in the context of the window where the event is raised - the untitled window in this case. In fact, you will note that the #say command issued inside the onLoad handler correctly puts output in the untitled window, and that the %window variable is correctly set to 'untitled' inside the handler. However, the #var command SHOULD create new vars inside the window, but instead creates them in the package where the handler is called, contrary to Zugg's description at the top of this post. Also, the value of @winVar should be accessible inside the event handler, and it's not.
This appears to be a general issue with context in event handlers - I first encountered it when trying to access/create variables in my main session window from within an onPrompt handler (my triggers #raise onPrompt when a prompt is detected). |
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you!
Last edited by JQuilici on Sat Mar 29, 2008 2:49 pm; edited 5 times in total |
|
|
|
Tech GURU
Joined: 18 Oct 2000 Posts: 2733 Location: Atlanta, USA
|
Posted: Wed Feb 27, 2008 6:16 am |
Confirmed.
|
|
_________________ Asati di tempari! |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Thu Feb 28, 2008 2:48 pm |
Further info:
I attempted several workarounds for this problem (which I will dutifully remove when the basic mechanism is working). In the process, I discovered additional anomalies.
Procedure
Same as in the original post, except that I have altered the body of the onLoad handler to the following:
Code: |
#say OnLoad called in window %window
#say winVar: @winVar
#say char: %char
#var onLoadVar %window
#var %concat("//",%window,"/onLoadVar2") %window
#execwin %window {#var onLoadVar3 %window}
#var |
After I load the module, the untitled window reads:
Code: |
OnLoad called in window untitled
winVar:
char:
Variables:
onLoadVar (Auto) untitled
onLoadVar2 (Auto) untitled
|
Note that the %char variable is not defined (or has a null value) within the event handler, though the %window variable is (and has the correct value).
In addition, use of the package editor will confirm that onLoadVar was created in the OnLoadTestPkg (as in the original post), but both onLoadVar2 and OnLoadVar3 were created in the untitled window (yay workarounds!). However, the value of onLoadVar2 is visible from within the event handler, but onLoadVar3 is not, even though they are defined in the same package, module (window), and class! Typing '#var' at the command line after this whole procedure, on the other hand, will show all three onLoadVar variables as well as winVar.
Summary of related bugs:
- '#var name val' within an event handler will create a new variable in the package containing the event handler (per original post).
- '#var %concat("//",%window,"/name") val' within an event handler will create a new variable in the session window, and the value will be accessible within the event handler.
- '#execwin %window {#var name val}' within an event handler will create a new variable in the session window, and the value will NOT be accessible within the event handler.
- The %char predefined variable has no value within the event handler, though the %window predefined variable does.
(Note: Just to be clear, I am not advocating the use of either workaround method in the long term. This is intended simply to throw additional light on the underlying problem, and to allow me to progress in my script development while this bug remains.) |
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Thu Feb 28, 2008 2:56 pm |
Thread title updated to reflect that this appears to be more than just an incorrect context - there are some weird symbol-lookup behaviors (e.g. onLoadVar2 vs onLoadVar3 in the previous post).
|
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
Tech GURU
Joined: 18 Oct 2000 Posts: 2733 Location: Atlanta, USA
|
Posted: Sat Mar 01, 2008 4:49 pm |
Confirmed for all except number 4. Remember in a blank session, there is no value for %char. I tried it in a name session, and assigned a name for the session character and got a value. Here's my output.
Code: |
OnLoad called in window B2
winVar:
char: Boo
Variables:
onLoadVar (Auto) B2
onLoadVar2 (Auto) B2 |
|
|
_________________ Asati di tempari! |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Sun Mar 02, 2008 4:32 pm |
Duh. *slaps forehead*
Thanks, Tech. I needed that. |
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Mar 03, 2008 5:35 pm |
I have added this thread to the bug list.
|
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Mon Mar 03, 2008 9:52 pm |
I have developed a much cleaner workaround for this bug, which I will use until it is fixed.
I have a single onLoad handler in my package. It does nothing except '#say onLoadWorkaround'. Then I have triggers in various places that match 'onLoadWorkaround, and do the stuff that I would otherwise have used onLoad handlers for. Since the context for the triggers is correct, this works like a charm. It also gives me a reminder, every time I load the session, that I still have the workaround in place.
A silent version of the same workaround can be created using #fire rather than #say. I will likely use this for my onPrompt handlers in the meantime. |
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Mon Mar 10, 2008 8:00 pm |
Oddly, it appears that MXP triggers may suffer from this problem, too. I am working on a test case, in the hopes that this might make it into the release this week.
|
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Sun Mar 16, 2008 5:48 pm |
Still present in 2.20. Title updated.
|
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Mar 17, 2008 5:40 pm |
Yes, this is still on the bug list and was not fixed in 2.20, sorry. Just didn't have time to fix everything.
|
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Mon Mar 17, 2008 7:29 pm |
No worries - it didn't sound related to the fixes for 2.20. Just keeping the buglist current.
|
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Sat Mar 29, 2008 2:49 pm |
From the 2.21 Version History:
Quote: |
Fixed the "context" for executing the OnLoad event in external modules to be the current session window |
However, the procedure from the OP still fails in 2.21, with the same symptoms.
I also noted that the fix description refers to an external module (the original procedure used a global one). If I move my onLoad handler to an external module, it does not appear to fire at all.
EDIT: Here is my revised test procedure:
First, create a package OnLoadTest, with the following contents:
Code: |
<?xml version="1.0" encoding="ISO-8859-1" ?>
<cmud>
<module name="OnLoadGlob" global="true">
<uid>{B3FCA8B7-901F-42EC-B919-700E5358AAAB}</uid>
<event event="onLoad" priority="10">
<value>#say OnLoad ~(global) called in window %window
#say winVar: @winVar
#var onLoadVarG %window</value>
</event>
</module>
<module name="OnLoadExt" external="true">
<uid>{39CB3CAE-31B9-4A58-B5E6-BBE168013BA7}</uid>
<event event="onLoad" priority="10">
<value>#say OnLoad ~(external) called in window %window
#say winVar: @winVar
#var onLoadVarE %window</value>
</event>
</module>
<module name="OnLoadLoc">
<uid>{B3FCA8B7-901F-42EC-B919-700E5358AAAB}</uid>
<event event="onLoad" priority="10">
<value>#say OnLoad ~(local) called in window %window
#say winVar: @winVar
#var onLoadVarL %window</value>
</event>
</module>
<module name="OnLoadTest" global="true">
<uid>{4E46646F-E8AA-4A38-B6A7-AD2A3BFDB574}</uid>
<event event="onLoad" priority="10">
<value>#say OnLoad ~(default) called in window %window
#say winVar: @winVar
#var onLoadVarD %window</value>
</event>
</module>
</cmud> |
- Run CMUD
- Create a new session ("LoadTest') and load it in offline mode
- Type '#var winVar v1' at the command line
- Quit CMUD
- Run CMUD
- Edit your new session to add the 'OnLoadTest' package
- Open your session in offline mode
- You will see:
Code: |
OnLoad (local) called in window LoadTest
winVar:
|
Very weird. The local one should NOT fire, but the others SHOULD. Regardless, it should be able to see winVar, and it can't. You can also verify that the OnLoadVarL was created inside the OnLoadLoc module - it should have been in the LoadTest window.
Now, type '#raise onLoad' at the command-line.
This time, you will see:
Code: |
OnLoad (default) called in window LoadTest
winVar:
OnLoad (global) called in window LoadTest
winVar:
OnLoad (external) called in window LoadTest
winVar: |
So the right ones fired this time. However, they still can't see the winVar variable, and they still create their vars in their own modules rather than the session window.
No idea what's going on internally, but it doesn't look right. |
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you!
Last edited by JQuilici on Sat Mar 29, 2008 3:19 pm; edited 1 time in total |
|
|
|
Larkin Wizard
Joined: 25 Mar 2003 Posts: 1113 Location: USA
|
Posted: Sat Mar 29, 2008 2:55 pm |
I think it may be a general event context problem, though. I have trouble raising events in certain ways from one module to another. I haven't been able to pare it down to a small, reproducible example that I could post.
Basically, I have buttons that I want to update on a certain event. There's an alias that toggles a setting and then raises the event. The event handler in the GUI package tries to change the color and/or text of a button, but I get an exception about not having permission or some such thing. If I am able to make it happen with a test case, I'll be sure to post it up here. |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Sat Mar 29, 2008 3:22 pm |
True. I don't think this is confined to onLoad handlers, though the fact that I get different results from '#raise onLoad' on the command-line and the event thrown by actually loading the package is problematic.
I'll put together a test case that uses only user-defined events, too. Might help to track this down. |
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Sat Mar 29, 2008 5:48 pm |
The fix in 2.21 will only occur when OnLoad is fired internally from CMUD when a module is loaded. Using #RAISE OnLoad will not change the context.
I think it would help if you could put together a simpler test case that I can use for this. All I did in 2.21 was change the context of the OnLoad event called when a module was loaded to the current MUD window's context for Global or Published modules. |
|
|
|
JQuilici Adept
Joined: 21 Sep 2005 Posts: 250 Location: Austin, TX
|
Posted: Mon Mar 31, 2008 3:24 pm |
Ok...putting aside any other events (since you haven't addressed them yet), here is a procedure to demonstrate the problem with onLoad. This is actually longer than the procedure in the OP, but it shows the two basic issues.
NOTE: I was mistaken, before. The failure mode in 2.21 is different than it was in 2.20.
- Start CMUD
- Create a new session 'LoadTest' and load it in offline mode
- Type the following at the command line:
Press Ctrl-G to open the Package Editor (PE)
Choose File->New Package. Name the package Handler
In the Handler package, create a new onLoad Event, with the following script:
Code: |
#say onLoad - %window - @winVar
#var handlerVar v2 |
Quit CMUD
Start CMUD
Load the LoadTest Session in offline mode
In the main window, you will see absolutely nothing. It appears that the onLoad Handler did not fire at all. (In 2.20, the handler would fire, but appeared to have the wrong context - see the original post)
Press Ctrl-G to open the PE
Select the Handler module (in the Handler package) and switch it from Global to Local only.
Quit CMUD
Start CMUD
Open the LoadTest session in offline mode.
This time, you will see in the main window:
Code: |
onLoad - LoadTest - |
Note that the handler fires (!?!), and it knows the window name, but cannot see the winVar variable inside that window.
Press Ctrl-G to open the PE. You will see that the handlerVar variable was created inside the Handler module, not the window.
To be clear, my expectations are:
- Every event handler is executed with a window as its context. Because it executes in the context of that window, it should be able to access settings in the window, and new settings should be created in the window by default. For the onLoad handler, it would be the window that is 'seeing' the package load (the main session window in this case). For user-defined events, it would be whatever window is executing the script that #RAISEs the event, etc.
- An onLoad handler in package A/module A1 would be invoked for a window in package B if module A1 is Global or External, but not if it is Local.
If those expectations are wrong, please let me know. The current behavior (as shown above) appears to be at odds with both.
The failure is different than in 2.20, in that the handler will not fire at all unless the module containing it is marked Local - so, oddly, it looks like the change for onLoad with Global/External modules just made the event not fire. However, the issues with variables (can't see window variables, and new vars are not created in the window) are the same when it DOES fire.
I suspect that the variable problem is also present for other events as well, which is the bug that I was originally reporting in this thread (I just happened to use the onLoad event to do it). I will try to come up with a shorter procedure to demonstrate it using a user-defined event, so that there is not so much quitting and restarting of CMUD. |
|
_________________ Come visit Mozart Mud...and tell an imm that Aerith sent you! |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Apr 01, 2008 6:28 pm |
I was able to reproduce all of your issues with your excellent procedure. I think I agree with you about how this *should* work, and it does appear that the change I made in 2.21 made it worse (I think the change in context is preventing the IsInScope from returning true, so the event doesn't fire).
Anyway, I've got your procedure on the bug list in more detail now, so I should be able to work on this and get it working better. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Thu Apr 03, 2008 8:08 pm |
OK, I have fixed this for v2.22, but not quite how you wanted.
In v2.22, your first example (where Handler is set as Global) works as you expect. It displays:
onLoad - LoadTest - v1
and it properly creates the @handlerVar in the current Window (LoadTest) in the same place that the @winVar is. So I think this is what you wanted.
However, I did *not* change the behavior when Handler is set to Local. When the Handler module is Local, it still gets "loaded" when the session is loaded. So, the onLoad event within the Handler module should still be executed. After all, the module just got "loaded" into the session, and regardless of whether it is Local or Global or External it should still call it's onLoad event to allow the module to initialize itself.
But in the case where Handler is local, the onLoad event does not get executed within any window context. Since Handler is local, it can't see anything outside of it's own package, which means it cannot see or access the window. So in this case, it displays:
onLoad - LoadTest -
as before. The %window object is global and still indicates which window currently has focus. But it cannot access the @winVar within the window, as expected. And the @handlerVar still gets created within the Handler module, because that is the context the onLoad event is being executed in for Local modules.
I think this is actually exactly what you would want as a package developer. It allows you to create a Local module within your package, and use the onLoad event to initialize variables within your local module. You can also create a Global module in your package, and the onLoad event within this module will create instance variables within the current window when it is loaded.
Along with the first change, I have done this fix so that #RAISE will properly use the window running the script as the context for the event. But if you manually tried to #RAISE onLoad, then the onLoad event within the Local Module of your package will not get called (because the window using #RAISE cannot see that module). The OnLoad event within a Local Module only gets executed when a session gets loaded by CMUD itself.
Let me know if you think this should still work differently. |
|
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|