Ruby/RGSSx questions that don't deserve their own thread

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
A Performance question:

I heard that eval can slow down the game if used unwise...

So, I have this little dilemma...

I got two ways to set up my method. One uses an eval method and it takes only 2 lines to do.

The other one takes 18 lines with a case statement but without any eval method.

The method will be called every single time the player attacks or does any battle actions and the battle system in question is an ABS, so the player will be mashing buttons left and right for sure to attack the enemies...

What should be better to use?
The other one, absolutely. `eval` is extremely slow. There seems to be a worrying misconception in this community that more lines of code = slower in all cases. This is very, very false. Often, the optimum solution will be one that requires a larger amount of code. True in all cases? No. But don't just assume that short code is better. If you're curious about a particular case, benchmark it! Plenty of tools out there for that--the SES Benchmarker (found in my sig, I believe?) will work, for one.

As for the other one, I haven't tested it, but I think that this should work:

def cooldown_bonus  ary = []  if @note =~ /Cooldown Bonus = <(\d+[ ].*(?:\s*,\s*\d+[ ].*)*)>/i    $1.split(", ").each do |info|      info =~ /(\d+) (.*)/i      ary << [$1.to_i, $2.downcase] # [value, stat]    end  end  return aryendEdit for explanation: I personally prefer using `[]` to `Array.new`--no real performance difference or anything, just syntax, but it looks a little cleaner. You don't need the `to_s` for $2, since it's already a string. `map` was just returning an Enumerator there, which you weren't using--best to just go with `each`. You didn't need the counter--just append to the array, hence `<<`. Similarly, it's fine to just put both values together in an array rather than pushing them individually. I might also consider moving the Cooldown Bonus Regex to a constant or something to save the time used to build it, but that's negligble unless you're doing it a truly enormous number of times in a row, which I doubt is the case.
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,599
Reaction score
6,552
First Language
Indonesian
Primarily Uses
RMVXA
Eval is slow indeed. But it wont affect so much if you only call them once / occasionally, not once / more per frame
 

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
Eval is slow indeed. But it wont affect so much if you only call them once / occasionally, not once / more per frame
Doesn't matter--using `eval` is a slippery slope. First you'll be all "Oh, it's just once, so it's fine", then it will be a quick solution for something complicated ("I'll go back and make it better later"), and eventually it's everywhere. Best to avoid it.
 
Last edited by a moderator:

Solistra

Veteran
Veteran
Joined
Aug 15, 2012
Messages
593
Reaction score
247
Primarily Uses
Eval is slow indeed. But it wont affect so much if you only call them once / occasionally, not once / more per frame
Part of the problem with using eval is that it's easy, and like you said, using it sparingly doesn't normally cause much of an issue -- but getting used to using eval will lead to its use in areas where it doesn't really belong or offer any real benefit (which is almost every circumstance that I've seen it used in by this community).


Over time, all of these uses of eval may lead to death by thousands of paper cuts -- but that's not the real problem. The real problem with it is that it's a massive crutch that also happens to be so insanely convenient that it gets used where it's completely unnecessary and harmful.


Avoid it if you ever want to actually learn how to write anything remotely performant.
 

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,003
First Language
Tagalog
Primarily Uses
RMVXA
It's widespread use is possibly because most writes for convenience, not performance. 
 

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
It's widespread use is possibly because most writes for convenience, not performance. 
The problem isn't just that it hurts performance, but that it prevents scripters from thinking outside of the box and discovering alternate ways to do things. If they rely on `eval` because it's easier than finding another way, that means that they're not trying to better themselves. Is there any greater sin*? I want to see people get better. I truly do. So it's distressing to me to see people fall back on something because it's 'easy'.

*Disclaimer: Enelvon does not believe in the metaphysical concept of sin. The word sin is used here to refer to a distressing failing, not an event that will tarnish the immortal soul that you may or may not have, depending on your beliefs, or an action that will diminish your karma and cause reincarnation as a lesser form of life.
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,599
Reaction score
6,552
First Language
Indonesian
Primarily Uses
RMVXA
eval is best for end user configuration. I won't ridiculously use hardcoded eval in my script. I just want to offer some freedom to my script users and I don't want to put uneccessary confusing script config. As long as it wont generate real issue, that would not be a problem (lag problem usually come from Graphical updates)
 

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
eval is best for end user configuration. I won't ridiculously use hardcoded eval in my script. I just want to offer some freedom to my script users and I don't want to put uneccessary confusing script config. As long as it wont generate real issue, that would not be a problem (lag problem usually come from Graphical updates)
Use Procs. Exactly the same thing, in that situation, but with better performance.
 

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
Just write them as procs initially. Faster, has syntax highlighting, etc, etc. You could even do something like this:

Code:
formula = proc do |v, s|  v[2] + 3end def eval_formula(formula, v=$game_variables, s=$game_switches, ... )  formula.call(v,s)end eval_formula(formula)
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,599
Reaction score
6,552
First Language
Indonesian
Primarily Uses
RMVXA
How do you offer them in end user config?
 

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
Just have your user write things as procs? It's honestly about the same as writing strings to be evaluated, with the exception of having syntax highlighting and enclosing things in `proc do ... end` or `proc { ... }` instead of quotes. If you want access to local variables and such, you can use `instance_exec` to call the proc--which essentially makes it the same as `eval`, minus the performance problems.
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,599
Reaction score
6,552
First Language
Indonesian
Primarily Uses
RMVXA
Suppose this is my script config. So, I just need to write like this?

module Theo Formula = proc { $game_variables[1] > 10 }endSeems a good idea.
 

Enelvon

Slumbering Goddess
Veteran
Joined
Nov 29, 2012
Messages
240
Reaction score
139
First Language
English
Primarily Uses
Suppose this is my script config. So, I just need to write like this?

module Theo Formula = proc { $game_variables[1] > 10 }endSeems a good idea.
Correct, that would work. Also, I'm not sure why I didn't think of it before, but you can check out my Enhanced Events script as an example of a more complicated way of doing things:

Condition Suite: config entirely through Procs

https://raw.githubusercontent.com/sesvxace/enhanced-events/master/lib/addons/condition-suite.rb

Main Script: the handling for said Procs

https://raw.githubusercontent.com/sesvxace/enhanced-events/master/lib/enhanced-events.rb
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,599
Reaction score
6,552
First Language
Indonesian
Primarily Uses
RMVXA
Interesting. That would be a huge optimization for my battle system then
 

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,003
First Language
Tagalog
Primarily Uses
RMVXA
That looks interesting...

but how about something like this?

#Notetag on object

<tag>

formula

<end_tag>

 class A  def a(object)    eval($1) if object.note =~ /<tag>(.*)<end_tag>/m  endendhow would the tag and the actual code look like if I convert that to using procs?Also, from what I've read from your link, a return call in the proc becomes the return call of the method that calls the proc. So I can't use procs in cases where I still need to process things afterwards, right?
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,599
Reaction score
6,552
First Language
Indonesian
Primarily Uses
RMVXA
@adiktuzmiko:

Nice question, I just wondering the same thing.

Btw, the new thing about the block is the symbol '&' used to call block. I know the '*' could be used as parameter. But the block is just new. It's nice to know some of code options
 

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,003
First Language
Tagalog
Primarily Uses
RMVXA
I'm wondering since my extension scripts uses eval to run things placed by the user into the notetags of objects in the database, so I'd like to know how to exactly use procs (or maybe lambdas) and how it might affect the degree of difficulty in setting up those for the users side.

they typically look something like

class RPG::BaseItem def get_formula if @formula.nil? @formula = self.note =~ /<tag_here>(.*)<end_tag_here>/m ? $1 : "" end return @formula endendclass Another def evaluator eval(actor.get_formula) actor.states.each do |state| eval(state.get_formula) end #and so on endendin which case the only thing that the user usually needs to do is to write down the<tag_here>

formula

<end_tag_here>

into the notetags and the script handles the rest, so it's typically easy for both the scripter and the actual user of the script.

As much as we would like to use the fastest methods available, we would also like to not make it so hard for the user to use in case of scripts made for the public. There wouldn't be much point in a very fast code which only a few could use due to it being not that user friendly. :3

So back to the question, how would that kind of eval using code look like if we do it via procs/lambdas?
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,599
Reaction score
6,552
First Language
Indonesian
Primarily Uses
RMVXA
Found and interesting optimization. I tried this

PROCTEST = proc { function_to_call }EVALTEST = "function_to_call"TIMES = 1000000class Something def initialize @proc = eval("proc { #{EVALTEST} }") end def function_to_call return 200 * 200 end def call_proc instance_exec(&PROCTEST) end def call_eval eval(EVALTEST) end def call_eval_proc @proc.call end ends = Something.newty = Time.nowTIMES.times { s.call_eval_proc }tx = Time.nowTIMES.times { 200 * 200 }t0 = Time.nowTIMES.times { s.function_to_call }t1 = Time.nowTIMES.times { s.call_eval }t2 = Time.nowTIMES.times { s.call_proc }t3 = Time.nowputs "Time for Eval \t\t: #{t2 - t1}"puts "Time for Proc \t\t: #{t3 - t2}"puts "Time for Eval + Proc \t: #{tx - ty}"puts "Time for Method call \t: #{t1 - t0}"puts "Time for Direct \t: #{t0 - tx}"I got this.



Sorry for the messed up script. But hope you get the idea.

So yeah, eval is extremely slow. Proc more faster. However, you need to use instance_exec in order to use the instance methods / variables. And there is no way you could put the string as input if you dediced to make it as constant.

Using @proc = eval("proc { #{string} }") is somehow a bit faster, yet you can use the instance methods / variables and string input (if you're using notetag to grab the script). Because the proc created using eval. However, Its initialization might took time. And one variable can only contains one formula.
 
Last edited by a moderator:

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Profile Posts

Day 9 of giveaways! 8 prizes today :D
He mad, but he cute :kaopride:

Our latest feature is an interview with... me?!

People4_2 (Capelet off and on) added!

Just beat the last of us 2 last night and starting jedi: fallen order right now, both use unreal engine & when I say i knew 80% of jedi's buttons right away because they were the same buttons as TLOU2 its ridiculous, even the same narrow hallway crawl and barely-made-it jump they do. Unreal Engine is just big budget RPG Maker the way they make games nearly identical at its core lol.

Forum statistics

Threads
106,038
Messages
1,018,467
Members
137,821
Latest member
Capterson
Top