|
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Thu Oct 07, 2010 11:05 pm
[330B] Property change - new feature request |
Property change notification would allow for data-driven scripts as well as reducing the amount of time a script spends detecting changes in variables such as large database records. This feature would allow the script writer to create optimal database processing scripts as well as faster GMCP data processing. This features would not be restricted to these topics as their introduction would generate new scripting idioms.
With this end in mind I would like to propose these additions to zscript:
A) The %updtkey function.
This function would work exactly like the %addkey function but instead of returning the updated database record, it would return a stringlist of the keys that have changed values. This would be particularly useful in cases where the actual key/value pairs are not known beforehand. Here is a crude example of this:
Code: |
#ADDKEY $dbrec {a=0|b=1|c=3}
#ADDKEY $indbr {a=1|b=2|c=3}
;;
$updtlist = %updtkey($dbrec,$indbr}
|
After execution of the above script, the variables would have the following values:
Quote: |
$dbrec: {"a":1,"b":2,"c":3}
$updtlist: ["a","b"]
|
Of course, in this particular example we are aware of the contents of the the updating variable, whether it were multi-key or not. However, all of those who are currently processing inbound GMCP data would benefit tremendously from this feature:
Code: |
....
....
$chglist = %updtkey(@chardb,%gmcp.char.vitals}
;;
#FORALL $chglist {......}
....
....
|
In the above code, assuming this is being executed because the char.vitals trigger fired, the script writer would be immediately aware of which keys have changed and has no need to test each value to see if any processing needs to be done. This allow GMCP data management to be completely table-driven.
B) The #WATCH command.
The WATCH command is essentially a trigger with a list variable as the pattern:
Code: |
#WATCH list {commands}
|
The list parameter is a string list of variable references. When any of variables in the list changes, the trigger fires and the commands are executed. When the trigger fires the %watch predefined variable would contain a database record indicating the change.
Code: |
#VAR list {var1|var2|...|varN}
;;
// var1,var2,varN are variable references.
;;
#WATCH @list {#PRINT The %watch.%key variable has changed;#IF (%watch.%val = something) {....} {....}}
|
The above is not a very good example, and it is rather useless, but it demonstrates how the command would work.
To create the reference list we could use a new %watch function. This function would return the list in the format required by the #WATCH command:
Code: |
#WATCH %watch(var1,var2,...varN) {commands}
|
|
|
_________________ Sic itur ad astra. |
|
|
|
MattLofton GURU
Joined: 23 Dec 2000 Posts: 4834 Location: USA
|
Posted: Fri Oct 08, 2010 12:19 am |
For simple variables of a=b type, you can just create an Expression trigger. Expression triggers in CMud ONLY fire when the value of the variable changes to anything other than the previous value (ie, if @a = 7 and you again assign 7 to @a, this expression trigger would not fire). No need really for #WATCH or %watch(), at least as a new way to create more triggers. The logical next step would perhaps be to get @var.key and perhaps @var.key.key....key working with expression triggers, but honestly it would be ok if only the top-level keys were allowed.
Datarecords, assuming they even work with expression triggers, have a flaw in the expression logic wherein the trigger is executed multiple times according to the value of %numkeys(). In a variable with a hundred keys, that can cause some major slowdowns just because one key is getting updated and not necessarily the one you want/need to check for. |
|
_________________ EDIT: I didn't like my old signature |
|
|
|
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Fri Oct 08, 2010 5:52 am |
Yes, I see your point. #WATCH doesn't actually have to be a trigger, but in CMUD that's the only way to take an asynchronous exit (threads notwithstanding).
However, the implementation of %updtkey is straightforward and basically entails extending %addkey. Or rather using the same code as that function but returning a different result set. No flags need to be maintained since all the information would be generated during the processing of the database record.
I agree that in the simple case of "a=b" a pattern trigger is desirable, however, that is a rather trivial case. I as pointed out above, the power of %updtkey would be in its ability to generate a list of changed keys when the modifiers are unknown until execution time. The only time this function would be overkill if it were to be used to initialize a database record. In that instance it would return the equivalent of %dbkeys.
Programmatically all %updtkey would require would be to excute the same code as %addkey and push the name of the updated key into a stack and at the end popping the stack into a string list and returning that rather than the updated db record. The record passed in the function would be updated, so it could be most likely that it would take a reference as a parameter.
Code: |
$chglist = %updtkey(dbrec,$data)
//
//OR
//
$chglist = %updtkey(%ref(@dbrec),$data)
|
Where $data represents the same input one would use for #ADDKEY.
EDIT: As it turns out, initializing a db record with %updtkey wouldn't be overkill in the case where the keys of the new record are not known beforehand. |
|
_________________ Sic itur ad astra. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Thu Oct 14, 2010 5:35 pm |
For #WATCH, there is basically no way for me to hook into the json routines and fire any trigger when a low-level key value in the list or table changes. The routine that sets a value within a json table has no knowledge of CMUD triggers or anything high level like that. Trying to hook into this or write my own json routines would be a much larger project and could have serious speed impacts on tables/lists. Not something I'm planning to do anytime soon.
Since the beta is feature frozen right now, my suggestion for %updtkey is to just do something like this:
Code: |
#LOOP %gmcp.char.vitals {
if (%gmcp.char.vitals.%i <> @chardb.%i) {
do stuff...
}
} |
In other words, just loop through all of the keys and look for the values that have changed. This won't be any slower than what CMUD itself would do to implement a %updtkey function (CMUD would just loop through the list and look for changes anyway). |
|
|
|
|
|
|
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
|
|