SES Core v2.1 Update
by Enelvon
Wait, Enelvon is posting something? What? Quick, look outside! Are there (meteors/zombies/fire giants/insert preferred sign of the apocalypse here)?
Well, no, probably not. If you see any, it’s a localized apocalypse, since none of that is going on here. If you’re experiencing a localized apocalypse, you have my condolences. Those can get pretty nasty – make sure you take an umbrella with you if you go out.
All joking aside, I do have a couple of plans for the rest of this week, so you will probably see a few things being released or updated by Sunday. This particular update is for the SES Core, so it’s probably going to be the most critical of the things that I toss out.
So what does this update do?
This update isn’t for stability and includes no bugfixes. Updating your projects with it is not critical at this time, though I urge you to do so anyway – future scripts and script updates from SES will make heavy use of the feature that I implemented.
To put it simply, this update improves the note and comment scanning methods used by SES scripts. If you want to know the details, keep reading. If not, you can grab the update from the repository here.
Great, a pair of methods were improved. That’s incredibly vague – details, please!
I’m glad you asked. First of all, you need to understand that Ruby’s eval method is… bad. In most cases it’s a crutch for those who are either a) extremely lazy or b) lack the ability to properly execute an idea. It can lead to unexpected behavior and is difficult to debug – error messages from eval will just point to the place that the eval was called without giving any further details about what went wrong. It does have a few ‘acceptable’ uses, however – things like the item and skill damage formulas or dynamic in-text script parsing, both of which would be difficult to accomplish in a flexible way without the use of eval.
With that out of the way… The SES Core used eval to handle the results of note and comment scanning. This was due to reason a) from above – laziness, pure and simple. I’m not going to bother defending it. This update can still handle evaluated Strings for note and comment parsing for the sake of remaining compatible with old scripts, but it now allows the use of Procs and Lambdas as well. This is much safer and faster than the previous method.
How does that work?
Procs and Lambdas are both objects that contain a block of code that will be evaluated when they are called, much like methods. Unlike methods, Procs and Lambdas are not bound to a particular context. If called normally, they will execute in the context they were created in. If called with instance_exec, however, they will execute in the local scope.
The SES Core uses instance_exec to ensure that everything is executed in the correct scope. It also passes the contents of the $~ array as parameters for the block. $~ is an array that contains the results of the last Regular Expression match. When one uses $1, $2, $3, and so on, the values that are obtained are the same as those that would appear if $~[1], $~[2], or $~[3] were called. $~[0] contains the full String match, just like calling $&. Everything from the $~ array except for $~[0] can be accessed by name within the block, which makes it easy to tell what’s going on when reading the code of a block.
I still have questions!
Feel free to ask them. I can be reached here on this block or at via PM at this forum. My username there is, of course, Enelvon. I cannot promise that you will receive a prompt answer to your queries, as I tend to be rather busy, but I will do my best.
My main comment is that you can make eval give you more information on any issue with the code put into it. I’ve done so in my Script Error Info script. You need to give eval a binding, which, as I uderstand, gives it information about the current scope. I also usually give it a name and line 1 starting point. To give eval more information for when it gets an error:
eval(script, binding, “Name”, 1)
binding is a very specific object for Ruby, but it’ll give you one. ‘binding’ is a method in Ruby’s kernel, so the above code would run fine, provided ‘script’ was a valid text string. Any issues will be reported more logically. For an example, please refer to my Script Error Info script:
http://adrarian.wordpress.com/2013/08/21/script-box-error-message-fix/
Most of the script is getting the event type (common, parallel, etc), script box number, etc.
Yes, you *can*. I was providing a simple explanation – how many of the scripters who rely heavily on eval are actually aware of the fact that it can provide extra information, or of how to do it? In almost every case, eval is nothing but a crutch. I *could* have gone into more detail about the sort of unexpected behavior it can cause, but felt that it would be a waste of time as few people would actually read it. I settled for “eval bad.”
In addition to what Enelvon said, I’d like to also state that bindings aren’t entirely reliable, either — the returned value of them also changes based on the current scope.
Also, using blocks of Ruby code via instance_exec completely obliterates the need to provide such (inherently unreliable) debugging information via eval — the reason you do that is because eval doesn’t provide that information by default, while instance_exec provides a clean trail through the backtrace.
And finally, none of this actually applies to our own reasoning for opting to use Proc objects: we decided to do so almost entirely for the purposes of speed. Using eval causes an automatic rebuilding of the Ruby abstract syntax tree due to its nature — Proc objects do not do this.
In fact, for our purposes, the only reason we would use eval is if we had some code that needed to be serialized, and that seems highly unlikely. Even then, we preserved the old functionality for backwards-compatibility and, you know, just in case we need to use it.
So I fail to see your point.