[VX Ace] How can I make saved games record variables containing procs?

Status
Not open for further replies.

Balrogic

Veteran
Veteran
Joined
Dec 19, 2014
Messages
40
Reaction score
17
First Language
English
Primarily Uses
I was working on a script and noticed an instance variable was refusing to save properly. In the course of debugging I made a quick hack to attempt storing the information in switches. The results were disasterous. Instead of the game quietly saving and refusing to include the all-important data for my script it began to buzz ominously and even deletes any existing save it fails to save over.

Warning: Only try the replication step on a project that doesn't contain any valuable saves or you could damage your save data.

Replication is fairly simple. Put the following in a script call, activate the event then attempt to save your game.
 

$game_switches[1] = Proc.new {puts "*groan* This just broke my game!"}$game_switches[1].callI was wondering if anyone had any brilliant ideas on how to bludgeon VX Ace into submission and therefore force the program to behave itself by saving data containing procs. I wouldn't be adverse to a monkey patch so long as it works, either. Inability to fully utilize procs is going to limit the flexibility of any games or scripts I make.
 

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
38,310
Reaction score
11,912
First Language
English
Primarily Uses
RMMV
I thought there was a thread around here on something very similar. Maybe search through the topics in this forum? Tsukihime may have started it.
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
4,637
Reaction score
5,278
First Language
Indonesian
Primarily Uses
RMVXA
The question is why you need Proc as save contents?

Can you just seek for other alternatives?
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,071
First Language
English
I would probably leave procs alone and just make sure only data flows in and out of save files.


The procs could be created immediately before saving or after loading which would do something with the data.
 
Last edited by a moderator:

Balrogic

Veteran
Veteran
Joined
Dec 19, 2014
Messages
40
Reaction score
17
First Language
English
Primarily Uses
I thought there was a thread around here on something very similar. Maybe search through the topics in this forum? Tsukihime may have started it.
The only two posts that come up on a search for the terms proc and save are both in this thread. Google already came up blank while I was troubleshooting.

The question is why you need Proc as save contents?

Can you just seek for other alternatives?
I need procs as save contents because I don't want to have to manually define 300,000,000 methods for every little thing, I just want to slap a minimal amount of code down and access the relevant blocks in the simplest fashion possible. While I can probably figure out how to store arrays of data and run them through a method to produce the same effect it's far more complicated, less flexible and just plain irritating. I don't want to have to track event numbers, condition branches, event pages or anything else of the sort.

Edit: Now can we please skip the battery of "just don't do that" posts everyone always gets in this forum? I'd love to actually learn something in here.
 
Last edited by a moderator:

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
38,310
Reaction score
11,912
First Language
English
Primarily Uses
RMMV
Instead of assuming people don't want to help you ("everyone always gets in this forum"? Really?), consider that maybe "just don't do that" is what people have come up with after spending countless hours trying unsuccessfully to do what you're trying to do? Maybe you're just not going to get the answer you want ;)
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
4,637
Reaction score
5,278
First Language
Indonesian
Primarily Uses
RMVXA
Edit: Now can we please skip the battery of "just don't do that" posts everyone always gets in this forum? I'd love to actually learn something in here.
Then I would be interested on how people use the Proc as save contents as well.

AFAIK, it similar as why Fiber couldnt be saved as save contents. Look at how Game_Interpreter did that.

It contains Fiber that couldnt be saved and it used custom marshal_dump and marshal_load method instead

I will keep eye on this topic then
 

♥SOURCE♥

Too sexy for your party.
Member
Joined
Mar 14, 2012
Messages
693
Reaction score
410
Primarily Uses
It's pretty straightforward:

module DataManager class << self def save_game_without_rescue(index) # Remove proc from your stuff. $game_map.stuff_with_proc.default = nil # You should probably alias this method instead, but this is just # an example. File.open(make_filename(index), "wb") do |file| $game_system.on_before_save Marshal.dump(make_save_header, file) Marshal.dump(make_save_contents, file) @last_savefile_index = index end # Add proc back to your stuff after saving. $game_map.stuff_with_proc.default_proc = proc { |h, k| h[k] = [] } true end def extract_save_contents(contents) # Same as above, you should probably alias it instead. $game_system = contents[:system] $game_timer = contents[:timer] $game_message = contents[:message] $game_switches = contents[:switches] $game_variables = contents[:variables] $game_self_switches = contents[:self_switches] $game_actors = contents[:actors] $game_party = contents[:party] $game_troop = contents[:troop] $game_map = contents[:map] $game_player = contents[:player] # Reset back the proc after loading. return unless $game_map.stuff_with_proc $game_map.stuff_with_proc.default_proc = proc { |h, k| h[k] = [] } end end endI'm about to fall asleep now but let me know if you have any question. :)
 

FenixFyreX

Fire Deity
Veteran
Joined
Mar 1, 2012
Messages
434
Reaction score
308
First Language
English
Primarily Uses
Sure, you can learn something. Try reading the default Ruby documentation and using google, eh? Before you 'throw your weight' around, make sure it isn't looming over a cliff first; it's in your best intrest, my friend.

I've tackled this issue before; I came to the relization that without editing the source of Ruby itself, there is no real way to manage what I, and now what you, want.

Procs simply are not serializable. You cannot and will not be able to save procs dynamically in a file; you can, however, create a wrapper for the proc, like so:

class SerializableProc def initialize(code) # where code is a string @code = code @proc = eval("proc { #{code} }") end def marshal_dump [@code] end def marshal_load(array) @code = array[0] @proc = eval("proc { #{@code} }") end # ensure all handling gets passed to the actual proc def method_missing(*argv, &argb) @proc.send(*argv, &argb) endendalias ruby_proc procdef proc(*argv,&argb) return SerializableProc.new(argv[0]) if argv[0].is_a?(String) ruby_proc(*argv, &argb)end# Use Casemy_proc = proc '|x| puts x' # => SerializableProc instancedat = Marshal.dump(my_proc)my_proc = Marshal.load(dat)my_proc.call(20)#=> 20This allows recreation of a proc automatically, and you don't have to manually manage recreation yourself. However, it's waaaaay less dynamic and even more less ideal if your procs are complex to any degree. Not to mention the backtraces you'll get when something goes wrong, let me tell you...I think the others are right; we don't always get the answer we seek, but perhaps learning something about what you're trying to do isn't the same as knowing how to do exactly what you want?

Also, perhaps giving an idea of what you're trying to do, we may be able to more accurately find you a better solution to your problem? As far as I can tell, your issue isn't that Procs aren't serializable; it's something else within your code, but until you let us in on that, we can help no more than what we in this topic have :)
 
Last edited by a moderator:

Balrogic

Veteran
Veteran
Joined
Dec 19, 2014
Messages
40
Reaction score
17
First Language
English
Primarily Uses
Sure, you can learn something. Try reading the default Ruby documentation and using google, eh? Before you 'throw your weight' around, make sure it isn't looming over a cliff first; it's in your best intrest, my friend.

I've tackled this issue before; I came to the relization that without editing the source of Ruby itself, there is no real way to manage what I, and now what you, want.

Procs simply are not serializable. You cannot and will not be able to save procs dynamically in a file; you can, however, create a wrapper for the proc, like so:

class SerializableProc def initialize(code) # where code is a string @code = code @proc = eval("proc { #{code} }") end def marshal_dump [@code] end def marshal_load(array) @code = array[0] @proc = eval("proc { #{@code} }") end # ensure all handling gets passed to the actual proc def method_missing(*argv, &argb) @proc.send(*argv, &argb) endendalias ruby_proc procdef proc(*argv,&argb) return SerializableProc.new(argv[0]) if argv[0].is_a?(String) ruby_proc(*argv, &argb)end# Use Casemy_proc = proc '|x| puts x' # => SerializableProc instancedat = Marshal.dump(my_proc)my_proc = Marshal.load(dat)my_proc.call(20)#=> 20This allows recreation of a proc automatically, and you don't have to manually manage recreation yourself. However, it's waaaaay less dynamic and even more less ideal if your procs are complex to any degree. Not to mention the backtraces you'll get when something goes wrong, let me tell you...I think the others are right; we don't always get the answer we seek, but perhaps learning something about what you're trying to do isn't the same as knowing how to do exactly what you want?

Also, perhaps giving an idea of what you're trying to do, we may be able to more accurately find you a better solution to your problem? As far as I can tell, your issue isn't that Procs aren't serializable; it's something else within your code, but until you let us in on that, we can help no more than what we in this topic have :)
What about the possibilities of storing the proc contents as a string the whole time then writing a string class to_proc method that will take the contents of the string and treat it as a Proc.new = string, minus the surrounding quotes? Is that feasible without rooting around in the source code? That gets around the difficulties of re-creation by never bothering to save it as a proc in the first place. I had already attempted coercing symbols into procs without much success and had already planned on studying into the :symbol.to_proc method a bit more to see if my problem was just user error. Considering that this would be used in a one-user program I'm not terribly concerned if it's a few microseconds slower than a properly created proc. It's not like I'd have to call it 40,000 times before the next frame update in 0.16 seconds.

I'm not *trying* to be a $#&^ in here and I don't expect people to just write me a bunch of code, either. I just thought this was an interesting problem and I'm trying to get some bearings on how to actually solve it rather than just working circles around it. I already fixed the script that was giving me issues and pushed the update. I'm mainly concerned with having to curtail proc usage and constantly beat around the bush.

Edit: Messing around with that code in Interactive Ruby, I think I'm getting a good idea of how that works. Really appreciate the help on that. I'm going to work on a variant that won't need to run through the saves as a proc, see if I can make it somewhat painless for those times when a proc absolutely must do for whatever reason. I do see what you mean, though. It's pretty weird and clunky just trying to work this out. I think I could make it work using temporary instance variables within modules since those don't seem to break saves, trying to decide if it's still worthwhile with all the extra hoops. Not giving up just yet, though. I'm too stubborn for my own good, I won't learn unless I run this all the way into the ground.

It's pretty straightforward:

module DataManager class << self def save_game_without_rescue(index) # Remove proc from your stuff. $game_map.stuff_with_proc.default = nil # You should probably alias this method instead, but this is just # an example. File.open(make_filename(index), "wb") do |file| $game_system.on_before_save Marshal.dump(make_save_header, file) Marshal.dump(make_save_contents, file) @last_savefile_index = index end # Add proc back to your stuff after saving. $game_map.stuff_with_proc.default_proc = proc { |h, k| h[k] = [] } true end def extract_save_contents(contents) # Same as above, you should probably alias it instead. $game_system = contents[:system] $game_timer = contents[:timer] $game_message = contents[:message] $game_switches = contents[:switches] $game_variables = contents[:variables] $game_self_switches = contents[:self_switches] $game_actors = contents[:actors] $game_party = contents[:party] $game_troop = contents[:troop] $game_map = contents[:map] $game_player = contents[:player] # Reset back the proc after loading. return unless $game_map.stuff_with_proc $game_map.stuff_with_proc.default_proc = proc { |h, k| h[k] = [] } end end endI'm about to fall asleep now but let me know if you have any question. :)
I don't fully understand how the code you posted works. Am I correct to assume the stuff_with_proc is essentially a bar(foo) type placeholder and I would then need to work out the best way to detect all the relevant procs by object type, store and then replace them? I've been looking up the default_proc method on ruby-doc.org and will definitely play around with that in a bit.
 
Last edited by a moderator:

♥SOURCE♥

Too sexy for your party.
Member
Joined
Mar 14, 2012
Messages
693
Reaction score
410
Primarily Uses
If you're going for the route presented in the other solution, take a look at this first: http://rubyquiz.com/quiz38.html

I don't fully understand how the code you posted works. Am I correct to assume the stuff_with_proc is essentially a bar(foo) type placeholder and I would then need to work out the best way to detect all the relevant procs by object type, store and then replace them? I've been looking up the default_proc method on ruby-doc.org and will definitely play around with that in a bit.
It was an example to show the basic idea, which by the way works for objects with default procs. Here's how you would apply the same concept to make your original example work:

module DataManager class << self alias_method:)prefix_original_save_game_without_rescue, :save_game_without_rescue) def save_game_without_rescue(index) # Get the proc from your stuff. proc_thing = $game_switches[1] # Remove proc from your stuff. $game_switches[1] = false # Original method. prefix_original_save_game_without_rescue(index) # Add proc back to your stuff after saving. $game_switches[1] = proc_thing true end alias_method:)prefix_original_extract_save_contents, :extract_save_contents) def extract_save_contents(contents) # Original method. prefix_original_extract_save_contents(contents) # Reset back the proc after loading. $game_switches[1] = Proc.new {puts "*groan* This just broke my game!"} end end endIt's easier, more performance friendly and intuitive since you keep the proc working like a proc. :)
 
Last edited by a moderator:

Balrogic

Veteran
Veteran
Joined
Dec 19, 2014
Messages
40
Reaction score
17
First Language
English
Primarily Uses
I definitely like your loading methods, SOURCE. It's great stuff. I noticed the difficulty in storing instance variables within the serialized proc quiz, which is fairly interesting. I'm going to have to give that topic a lot of thought and study... Definitely need to learn about Marshall and brush up on my Regex. (Bleh. Regex.) I should probably do some in-depth research on how Ruby handles return addresses within methods and whether or not there's a practical way to coerce the interpreter into evaluating a proc reconstruction in the context of the original calling method. I'm in way over my head with the topic, which is what makes it so interesting. So much to learn!

Primarily, I was thinking of using procs to store handling methods with variable settings that are either randomized or reactive to the player's actions without having to bother myself with devising clever database schemes for storing and correctly retrieving the pertinent data. Just slap it in a proc based on initial conditions and it sticks until I want it otherwise. It's incredibly problematic for a randomized approach if a player can just save/load their game until they get a random value they like. So far I've got something like this, based on the proc serialization without having to bother saving the data as a proc in the first place.

module Test def self.call_proc(code) proc = eval("proc { #{code} }") proc.call endend# Then the test's script call.$proctest = 'puts "Things are looking up."puts "It is not blowing up in face."puts "Apostrophes are the enemy."puts "I can not use them with this"puts "approach to procs."'Test::call_proc($proctest)The information about save implementation will come in very handy if I manage to come up with any new tricks. I had some initial thoughts about a custom proc method that would Proc.new = an argument at index 0 in a new array while storing the code as a string at index 1 for reconstruction but that's going to need an additional mechanism to ensure original evaluation context for full function.
 

Evgenij

Veteran
Veteran
Joined
Aug 28, 2013
Messages
349
Reaction score
100
First Language
German
Primarily Uses
N/A
Your example does make no sense to me.

Why call the string throught 

Test::call_proc($proctest) when you just could do 

Code:
eval($proctest)
 

Balrogic

Veteran
Veteran
Joined
Dec 19, 2014
Messages
40
Reaction score
17
First Language
English
Primarily Uses
Well, the main reason I'm not doing it that way is because I got sidetracked by all the proc type stuff and didn't think of just doing that. Functionally, it really shouldn't make a difference. It's not as though any of the methods brought up on proc serialization are capable of binding to local variables within a method and if I want to check whether or not a variable is set for use I can use a true/false check. I suppose I can't iterate through an array with a brute force method to check if it finds a proc then call it and return, not that I'd code that way in the first place. Even if I wanted to, I wouldn't have to. RM only runs into the save problem when you stick a proc somewhere that gets serialized in a save file. There aren't any problems if you set procs into local and instance variables that don't save. Just using eval is more than good enough for executing methods or snippets of code I need to set up and save for later.

I'm pretty happy with the outcome of the thread, in spite of feeling somewhat foolish. I've gained a much stronger understanding of procs and a little bit of understanding about how persistence between sessions is handled by Ruby programs. As such, I'd like to thank everyone that's helped out in here. I appreciate it. It isn't enough to know what doesn't work, I want to know *why* it doesn't work.
 

Heretic86

Veteran
Veteran
Joined
Nov 30, 2014
Messages
240
Reaction score
164
First Language
Engrish
Primarily Uses
If you need a Proc, then store it in Game Temp, not in a Variable.  Not difficult to script for this.

class Game_Temp

  attr_accessor :my_proc # Allow $game_temp.my_proc

  alias my_proc_initialize initialize unless $@

  def initialize

    # Call original or other aliases

    my_proc_initialize

    # Placeholder for Proc

    @my_proc = nil

  end

end

If you want the Proc to work with save games, it may be easiest to recreate the process in the Scene_Load class, also with an alias.

class Scene_Load

  alias proc_read_save_data read_save_data unless $@

  def read_save_data(file)

    # Call original or other alias with Argument

    proc_read_save_data(file)

    # Check conditions for creating the Process

    if (whatever your condition is, maybe a Game Switch)

      # Recreate your process as a New Process

      $game_temp.my_proc = (process stuff)

    end

  end

end

Best of both worlds, you get a proc that doesnt crash save games.  Just keep your proc out of anything that gets Marshal Dump, like Game System, Variables, etc.
 

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,642
Reaction score
2,972
First Language
Tagalog
Primarily Uses
so basically we can't save procs directly so what we will save and load are things that we could use to trigger/recreate/whatever the procs? :)
 

Heretic86

Veteran
Veteran
Joined
Nov 30, 2014
Messages
240
Reaction score
164
First Language
Engrish
Primarily Uses
As far as I understand, yes, cant Marshal Dump a proc.  That or something like Thread.new.  Similar to trying to save a Fork (programming thing for branched threads on certain types of web servers).  Same thing with RPG::Cache.  You can save property values of a sprite, but saving the sprite itself (image) would bloat every save game.  When we load a save game, the Sprite Images are recreated in the cache.
 

Balrogic

Veteran
Veteran
Joined
Dec 19, 2014
Messages
40
Reaction score
17
First Language
English
Primarily Uses
After cramming my head full of this stuff and taking a nap (studying is *so* awful sometimes) to process it all, I did have a thought.

If I jam a proc into a nested module as an instance variable with something like...

@proc[3] = Proc.new { local_var_werewolves += rand(6) + 1 some_method(arg, etc) eval($game_switches[1][47]) # Because you can set switches to arrays and store data that will save. RPG::SE.new("Wolf", 15, 90).play }Then this shouldn't cause me problems on saving/loading so long as I don't make RM *try* to save it through modification of the DataManager. Which I tried at one point, resulting in this very thread. Because the proc is explicitly created either as the script loads or upon execution of a method it's always going to be there when you need it. The eval approach can expand on that by storing random seeded or context sensitive information you want to persist between saves. That's why I'm so happy about the thread's outcome. I can't force RM to save the procs but it turns out I really don't need RM to do that and now I know how to accomplish what I wanted without running into problems. (Which isn't werewolves, I just posted that as a random example.)
 
Last edited by a moderator:

Zeriab

Huggins!
Veteran
Joined
Mar 20, 2012
Messages
1,200
Reaction score
1,256
First Language
English
Primarily Uses
RMXP
Instead of going with Procs consider simply saving code as a string and evaluating that as needed. Maybe that will save you a lot of hassle.

Do note that loading and evaluating code from a save file is a potential script injection scenario. Then again, I expect that already to be true with the call script command as it was in RGSS1.

*hugs*

 - Zeriab
 

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,464
Reaction score
545
First Language
Chinese
Primarily Uses
N/A
Summary:

Saving proc indirectly is possible and 1 way of doing so is to save the script code used by the proc in string form, then clear the proc right before saving and restore it right after saving and loading.

While proc generally costs more memory, it generally outperforms eval in terms of time. In situations where codes must run as quickly as possible, I'd prefer using proc over eval if both can be used.

eval:

The simpler but also slower in general. If the script codes are complicated and to be executed per frame(such as atb scripts), using eval can cause a significant fps drop unless the machine is powerful.

proc/lamnbda:

More complicated but also faster in general. It generally costs more memory though, as the proc/lambda variable should be kept until it no longer needs to be used, and it seems to me that its size can be quite notable, especially if the script codes are complicated(I'm not sure about this though).

As proc/lambda can't be serialized, users have to either store the variables using other methods(I don't know any about them if there's any), or clear them and save the script codes in string form instead. Of course they'll have to be restored after loading as well.

For example, the below methods clears the proc variables right before saving and restores them right after saving and loading:

alias save_game_without_rescue_ecatb save_game_without_rescue def save_game_without_rescue(index) # Added to clear actors' ecatb proc instance variables before saving clear_ecatb_procs # save_game_without_rescue(index) # Added to restores actor's ecatb proc instance variables after saving update_ecatb_configs # end # save_game_without_rescue alias extract_save_contents_ecatb extract_save_contents def extract_save_contents(contents) extract_save_contents_ecatb(contents) # Added to restores ecatb proc instance variables after loading update_ecatb_configs BattleManager.update_ecatb_configs # end # extract_save_contents  def clear_ecatb_procs    #    $game_party.members.each { |member| member.clear_ecatb_procs }    #  end # clear_ecatb_procs
Code:
  def update_ecatb_configs    DoubleX_RMVXA::ECATB::GAME_BATTLER.each { |proc, test|      proc = proc.id2name      update_ecatb_config(proc)      check_ecatb_config(proc, test)    }    update_ecatb_def_configs    update_ecatb_note_configs  end # update_ecatb_configs  def update_ecatb_config(proc)    eval(%Q(@#{proc} = eval("proc { " + $game_system.#{proc} + " }")))  end # update_ecatb_config
Code:
  def clear_ecatb_procs    #    @ecatb_def = @ecatb_item = nil    DoubleX_RMVXA::ECATB::GAME_BATTLER.each_key { |proc|      eval("@#{proc.id2name} = nil")    }    #  end # clear_ecatb_procs
Where the custom codes used by those procs are stored as strings under class Game_System:

# Stores all configurations DoubleX_RMVXA::ECATB::CONFIG.each { |configs| configs.each_key { |config| eval("attr_accessor :#{config.id2name}") } } #
Code:
  def init_ecatb_configs    # Initializes the configuration settings    DoubleX_RMVXA::ECATB::CONFIG.each { |configs|      configs.each { |config, val| eval("@#{config.id2name} = #{val}") }    }    #  end # init_ecatb_configs
Users can change $game_system.proc and call update_ecatb_config(proc) to change both the custom code string and its proc variable, effectively changing the script content on the fly without sacrificing too much performance.

The below method, which is called every frame, shows at least 1 reason why the procs are used instead of eval:

def ecatb_update? # Checks if the clock can be updated and the wait condition isn't met return false if scene_changing? || !SceneManager.scene_is?(Scene_Battle) !$game_message.visible && !@ecatb_wait_cond.call # end # ecatb_update?
Where the default value of @ecatb_wait_cond is this:

      :ecatb_wait_cond => %Q(%Q(#{WC1} || #{WC2} && (#{WC3} || #{WC4} ||                                #{WC5} || #{WC6} || #{WC7} || #{WC8} ||                                #{WC9} || #{WC10} || #{WCC1}))),
Code:
    # Checks if the atb clock is forced to stop    WC1 = %Q(@ecatb_force_clock == :stop)    # Checks if the atb clock isn't forced to run    WC2 = %Q(@ecatb_force_clock != :run)    # Checks if an action is executing    WC3 = %Q(!BattleManager.ecatb_can_esc)    # Checks if the cancel window is active    WC4 = %Q(@ecatb_cancel_actor_window.active)    # Checks if the party command window is active    WC5 = %Q(@party_command_window.active)    # Checks if the actor target window is active    WC6 = %Q(@actor_window.active)    # Checks if the enemy target window is active    WC7 = %Q(@enemy_window.active)    # Checks if the skill window is active    WC8 = %Q(@skill_window.active)    # Checks if the item window is active    WC9 = %Q(@item_window.active)    # Checks if the actor command window is active    WC10 = %Q(@actor_command_window.active)    # Checks if the combat log window is visible    WCC1 = %Q(update_msg_open_ecatb_compatibility)
Using eval instead of proc/lambda or instance_eval(or something like that) could and would probably cause a significant fps drop unless the machine is powerful(and in this case, it's not the only thing being run every frame).

The below is my informal benchmark for eval, proc, lambda and instance_eval(I counted the seconds with the aid of a clock):

class Test  def make_def(method)    instance_eval(method)  endendblock = "nil"test = Test.newtest.make_def(%Q(  def new_def    #{block}  end))#~ p("instance_eval")#~ 100_000_000.times { test.new_def }#~ p("instance_eval")#~ # Roughly 20 seconds#~ test = eval("lambda { #{block} }")#~ p("lambda")#~ 100_000_000.times { test.call }#~ p("lambda")#~ # Roughly 36 seconds#~ test = eval("proc { #{block} }")#~ p("proc")#~ 100_000_000.times { test.call }#~ p("proc")#~ # Roughly 36 seconds#~ p("eval")#~ 10_000_000.times { eval(block) }#~ p("eval")#~ # Roughly 63 seconds
The script code string is "nil"

instance_eval, lambda and proc are run 100,000,000 times with result roughly being 20, 36 and 36 seconds respectively, while eval are run 10,000,000 times with result roughly being 63 seconds.

It'd probably need roughly 630 seconds to run the above eval 100,000,000 times.

Another example:

class Test def make_def(method) instance_eval(method) endendblock = "rand > rand || rand < rand ? [rand,rand].min : [rand,rand].max"test = Test.newtest.make_def(%Q( def new_def #{block} end))#~ p("instance_eval")#~ 10_000_000.times { test.new_def }#~ p("instance_eval")#~ # Roughly 18 seconds#~ test = eval("lambda { #{block} }")#~ p("lambda")#~ 10_000_000.times { test.call }#~ p("lambda")#~ # Roughly 21 seconds#~ test = eval("proc { #{block} }")#~ p("proc")#~ 10_000_000.times { test.call }#~ p("proc")#~ # Roughly 21 seconds#~ p("eval")#~ 1_000_000.times { eval(block) }#~ p("eval")#~ # Roughly 19 seconds
The script code string is "rand > rand || rand < rand ? [rand,rand].min : [rand,rand].max"

instance_eval, lambda and proc are run 10,000,000 times with result roughly being 18, 21 and 21 seconds respectively, while eval are run 10,000,000 times with result roughly being 63 seconds.

It'd probably need roughly 190 seconds to run the above eval 10,000,000 times.

Of course such script code string is a bit exaggerated, but these 2 test results may suggest that the more complicated the script code is, the less the perfromance difference between eval, proc/lambda and instance_eval. According to test 2 test results, eval is much, much slower than proc/lambda and instance_eval, the speed of proc and lambda are almost the same, and they're significantly slower than instance_eval.

Check Tsukihime's post for eval vs lambda for more info(including formal benchmark) about eval vs lambda:

http://forums.rpgmakerweb.com/index.php?/topic/31474-formula-optimization-speed-up-your-formula-eval-code/?hl=%2Beval+%2Blambda
 
Last edited by a moderator:
Status
Not open for further replies.

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

Latest Threads

Latest Posts

Latest Profile Posts

Finally the new pc is working!! But it seems a lost my license to Windows 10 because of the hardware changing :(
Tune in next time for our newest Episode: "PC issues return! Palm uses every swear in the lexicon!"
gotta update my game project thread page later
So trying out Ultra Mode 7 was a bad idea. How do I not include this in my game? XD
Stumbled upon an RPG Maker game on Steam called 'Boobs vs Zombies' while looking for a zombie themed fantasy RTS. lol

Forum statistics

Threads
93,558
Messages
913,453
Members
123,094
Latest member
HimitsuYuki
Top