From: alexg@... (Alex Gutteridge) Date: 2004-06-04T17:28:42+09:00 Subject: Re: Extending Objects Without Inheritance Joel VanderWerf wrote in message news:<40BF7269.3050807@path.berkeley.edu>... > Alex Gutteridge wrote: > > Hi, > > > > I'm no great OO expert (or Ruby expert) so maybe the answer to this is > > obvious or maybe it's impossible. > > > > I currently have a bunch of classes which I use to parse a data file. > > Essentially there are fve layers of containers: > > > > PDB -> Model -> Chain -> Residue -> Atom > > > > A PDB object contains one or more Model objects each of which contain > > one or more Chain objects each of which contain... etc down to Atoms. > > Note that Model doesn't inherit from PDB or Chain from Model - each > > class is just a container for the next one down. > > > > The problem I have is that sometimes I have extra data associated with > > the Atom and/or Residue objects. This extra data always comes later > > (from a different data file) and usually won't be present. when I need > > to, I'd like to add this data to the (already created data structure) > > with the minimum amount of work/fuss. > > > > As far as I can see I have the following options: > > > > 1. Modify the Atom and Residue classes to include the extra data, set > > to nil originally and then filled in when needed. I'd rather not do > > this because the code is part of a bigger project which I don't have > > direct control over, and it seems rather inelegant to have these extra > > fields which hardly ever get used. > > Probably the caffeine hasn't hit me yet, but I'll suggest this anyway: > why not define the extra accessors you might need and assign to them > only when needed? No extra memory is used until you assign, as the > following shows: > > class Atom > attr_accessor :x, :y, :extra1, :extra2 > def initialize x, y > @x, @y = x, y > end > end > > atom = Atom.new(1,2) > > p atom > p atom.instance_variables > > atom.extra1 = "extra stuff" > > p atom > p atom.instance_variables > > __END__ > > Output: > > # > ["@y", "@x"] > # > ["@y", "@x", "@extra1"] Yes, this works as well, I obviously hadn't realised quite how dynamic Ruby's OO system is. My code essentially looks like this now: class Atom attr_accessor :id def initialize id @id = id end end atom = Atom.new('foo') puts atom.id class Atom attr_accessor :extra end atom.extra = 'bar' puts atom.extra __END__ Output: foo bar Though the second class definition for Atom is in a different file. If I understand correctly, when this second definition is pulled in, every Atom object is magically extended to include accessors for the @extra variable. This allows me to extend Atom objects without fiddling with the original Atom definition (which is part of a larger project and can't be easily editted). This almost seems too simple to be true!