From: Hugh Sasse Staff Elec Eng Date: 2004-11-23T00:05:31+09:00 Subject: Blocks, serailizing, and "configure, don't integrate" I seem to have run into a conceptual barrier, and it has caused me to rethink over ideas I've had about procs and blocks in the past.... I'm trying to build a gui based system -- the application doesn't matter for this discussion -- and I'd like to use Tk because it is more dynamic that the C++ based kits. So I think about the ideas in The Pragmatic Programmer about Providing Options, and Configure, Don't Integrate, and it seems a good idea to make some of the windows pickup their controls from a file. That's all well and good, and things like Marshal or Yaml handle those details nicely. But my widgets have callbacks, and in Ruby/Tk those are proc objects which can't be marshalled. Ok, I can save the block as a string and load it back in and do eval on it, or instance eval or some such, but then the block doesn't get checked for correctness very early because it is no longer code. Also this opens the whole thing up for abuse: the usual "deliver us from eval" issues of importing code from files and trusting it. I'm going to be encouraging people to tweak these configuration files, so I'd be inviting them to insert code, which is bad. I accept that having the ruby code on the machine is a weakness anyway, but most users won't poke around in that. I could introduce a mini language, so that my procs defined elsewhere get picked up, but that feels like an abstraction too far, if I try to make it flexible enough to be useful it will be too big to manage. I think, anyway. Is there another way to meet these conflicting goals of flexibility and some security? The second part of this is: I find myself wanting blocks to be real objects before they become procs. I'm trying to think this out but it feels like grasping wet soap -- I can't quite get a hold on the idea. I'm thinking something like this: We can't marshal procs because they carry external state. We can't marshal blocks or lambdas for the same reason. When you marshal an object you give it enough information to be re-constructed, possibly minus a few features (things that don't get dumped). Can we marshal a proto-block, that when loaded in a context causes a block to come into being in that context, without opening ourselves up to a full eval? Then we could do something like Block.new(Marshal.load(...)) to get a block, to pass to proc or whatever. Possibilities that this would have include warnings on the code within the block before/after it is serialized/restored, and formatting as some AST so it is less prone to casual hacking when serialized [caveats about security through obscurity apply]. I'm thinking that simplifying this would enable greater utility, as is true for all abstractions, as well as aid debugging. This is probably hard for me to think about clearly because there's a big flaw in it.... Thank you, Hugh