common serialization problems…
It so happened that the two projects im working on these days, all of a sudden needed serialization. Both the cases had massive object graphs, and both the times we faced the same problem of entities involved not being serializable.
Proc or lambda is almost second nature to Ruby developers, probably because of all the awesomeness it has got(binding and stuff). Before i played this serialization piece, all my callbacks used to be blocks or procs or lambdas. But since proc is not serializable now they are all messages and receivers. For example…i had to move from….
1 |
@callback_on_completion && @callback_on_completion.call |
to….
1 2 |
@callback_on_completion.is_a?(Proc) && @callback_on_completion.call @callback_on_completion.is_a?(Symbol) && @callback_receiver.send(@callback_on_completion) |
all over the place….
This may not look like too much trouble….. but if one has to do it in multiple places doing things in multiple ways… it boils down to writing and fixing many more tests which just eats into development time.
Thats not all… if there are object singletons are used, and the object has to be serialized, its gonna fail, because the singleton is not serializable. We had to revert a checkin(which was supposedly a bug fix, and re-implement the whole thing, just because the first solution was dependent on some meta-programming happening on the object singleton).
LESSON(s) LERNT:
Its not a bad thing to use proc and lambda and singleton as such… but it should be done when absolutely needed and only when there is no serialization requirement waiting down the road. I used the message and receiver kind of thing for the event handlers(that used to be blocks a few days back), and it worked absolutely well and it is really neat.
WHAT IF IT CANNOT BE AVOIDED:
Well i had a scenario like that. The object used a Gosu::Window and a loaded a lot of assets(images, sound clips etc.) and non of them were serializable.
I used a lo-fi solution for it, which was to expose a method window=(gosu_window) and using that accessor to load the other assets(like image and sound clips). For example, a typical class now looks like this…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class Util::Animator def initialize strip_file_name, tile_width, tile_heights, options = {}, &block @tile_width, @tile_heights = tile_width, tile_heights @strip_file_name = strip_file_name options = {:play_both_ways => false, :chunk_slice_width => 1, :run_indefinitly => false}.merge(options) @play_both_ways = options[:play_both_ways] @callback_on_completion = block || options[:call_on_completion] @callback_receiver = options[:callback_receiver] @chunk_slice_width = options[:chunk_slice_width] @run_indefinitly = options[:run_indefinitly] end def window= window @slides = Gosu::Image::load_tiles(window, @strip_file_name, @tile_width, @tile_heights, true) create_animated_sequence @current_anim_sequence = [] end ... ... ... end |
I added serialization/de-serialization routines to the unserializables, so that it doesn’t error out, but note that they de-serialize to nil.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
module SerializationDefaulter def self.included(base) base.extend ClassMethods end def _dump depth return '' end module ClassMethods def _load serialized_window return nil end end end Gosu::Window.send(:include, SerializationDefaulter) Gosu::Image.send(:include, SerializationDefaulter) Gosu::Sample.send(:include, SerializationDefaulter) Gosu::Font.send(:include, SerializationDefaulter) |
This solved the problem!!! now i have an option to do something like this for instantiation of my objects…
1 2 3 4 5 6 7 8 9 |
module Buildable def build context, window, from = nil, caption = 'Bakery' instance = from ? Marshal.load(File.open(from, 'r').read) : new(context) instance.window= window window.caption = caption window.listner = instance instance end end |
So what it essentially does is, if from(which is a file name) is available, it picks up the serialized object and loads it… and if a file is not given, it instantiates a new one…
But what about the things that came back as nil when we loaded the dump????
Well… the next line(4) takes care of them…. It sets the window irrespective of wether it is a new object or a loaded one….
But what about the other items(like images)… didn’t they get loaded as nil???
Indeed… thats exactly what the Util::Animator window= method handles. It loads back all the images/soundclips/tiles/fonts… everything that needs a window to load itself.
Problem solved!!!
About this entry
You’re currently reading “common serialization problems…,” an entry on codehunk
- Published:
- August 27, 2008 / 12:40 am
- Category:
- hacking
No comments yet
Jump to comment form | comment rss [?] | trackback uri [?]