Can An Object Grow?

21 commentsWritten on August 17th, 2010 by
Categories: Code Quality

As you probably know, i'm currently learning Ruby. And as you may or may not know, Ruby is a very dynamic language. And one of the things that i found immensely interesting about it is the ability to add methods to existing classes or to existing objects, which isn't the same as adding a method to a class in Ruby btw. And it sorta got me thinking about how the whole static vs dynamic thing can be applied to how we are often taught about objects and classes.

Chances are that when you learned about OO, you were introduced to the concept of objects using real world items. For instance, a door could be an object. It has certain attributes, and it has certain operations that can be invoked on it. But once a door has been produced, it will never gain new capabilities. It won't learn anything new. If anything, the attributes and operations that it was created with will only deteriorate over time.

Then again, some of us will undoubtedly have heard that a person is an example of an object too. A Person is an instance of the Human class. There is a huge difference between a Person instance and a Door instance. While the Door will never change (except for possible deterioration), a Person will change during its lifetime. It will gain new capabilities depending on what the Person instance goes through during its lifetime. It will also lose capabilities. It will gain new attributes, and some of them will no longer apply to that Person instance after a while. Its relationships can vary wildly from each Person to the next. A Person instance is highly dynamic throughout its lifetime, while a Door will always be the same.

The weird thing is... a lot of us use OO to model or mimic real world behavior. But real world behavior is pretty dynamic. Not for everything, but it definitely is for some things. And all this time, a large majority of us has been trying to model or mimic that behavior with static languages. In a static language, a Person instance would never be able to grow. You could define multiple types of Persons, but hey, a lot of people generally don't like to be put in groups based on attributes or capabilities and you'll always run into problems when doing so.

I'm not trying to convince anyone about anything specific in this post. But i am trying to get you think about what i'm saying. I do believe that objects can 'grow' in some or maybe even a lot of cases. And i think a lot of us can agree that static languages aren't exactly a great solution to dealing with this problem (though i prefer the term 'reality' instead). Dynamic languages on the other hand can offer better ways to deal with this, but then again you do have to keep in mind that they come with some downsides as well. In software development, there are very, very few win-win situations. Everything is a trade-off. For everything that you know and love, there will be an alternative that is more suitable in some cases, and less suitable in others.

So now i'd like to ask you the following 2 questions: 1) do you think that objects can 'grow'? 2) can developers grow? and how does that answer correspond to your answer to the first question?

  • Chris Waters

    When you’re programming in a component-based system, objects grow by definition. In such a system, an ‘object’ can be represented by a collection of components, where each component type defines a behavior or state. You could, per your example, ‘teach’ a Person something by assigning them an instance of a particular component; removing a component applies to losing capabilities.

    As for the #2, I’m pretty sure they can, especially if they do like you say and *know* their alternatives. Today’s paradigm may be damn awesome, but in the end they’re all geared towards solving a particular problem; knowing *what* that problem is can take you a long way.

  • http://davybrion.com Davy Brion

    @Chris

    “You could, per your example, ‘teach’ a Person something by assigning them an instance of a particular component; removing a component applies to losing capabilities.”

    That does require a recompile + a new deploy though. What if you do stuff like that on the fly? Not saying it’s easy, but it is possible…

  • VirtualStaticVoid

    I made a similar journey into Ruby from C#. Each language has it’s pros and cons; I think of it like another tool in my toolbox ~ I’ll bring it out for the job most suited.

    In answer to your questions, yes, objects can “grow”. I found having this ability to add functionality dynamically (mixin’s etc) in Ruby truely liberating. Interestingly enough, concepts like AOP, IoC and Dependancy Injection kindof fall away in Ruby. Just look at the ActiveRecord implementation in Rails as an example. Pure magic without any hacks!

    And yes, so too can developers grow. I think of the mental transformations I made in my approach to software problems from a procedural style (Cobol), to object oriented (Java/C#) and now to dynamic composition (Ruby).

  • http://davybrion.com Davy Brion

    “I found having this ability to add functionality dynamically (mixin’s etc) in Ruby truely liberating. Interestingly enough, concepts like AOP, IoC and Dependancy Injection kindof fall away in Ruby. ”

    while i don’t have any real world experience with Ruby yet, i’ve been thinking the same thing. I could be wrong, but a lot of the goals/benefits of the practices/patterns you’ve mentioned can be handled quite simply without resorting to those practices/patterns. The one thing i’m not sure of yet is this: with IoC, you also define the lifecycle of dependencies. While i know you can largely avoid the need to do DI in Ruby, i’m not yet sure how to deal with the fact that you might not want to know about the lifecycle of a component you depend on.

  • Chris Waters

    @Davy

    Actually, I was referring to a completely dynamic component system :D

    You wouldn’t have to recompile to add the components; the system would be built around adding/removing them at runtime.

    The most common place I’ve seen this approach is in real-time systems, where you want to operate on all instances of a component at once (instead of bouncing around between types).

  • http://davybrion.com Davy Brion

    @Chris

    ahh ok, forget i said anything :)

  • Chris Waters

    Here’s a description of such a system; though not too many examples (but there’s code!): A Dynamic Component Architecture for High Performance Gameplay

  • Scott Lowe

    Yes they can grow like real world objects! I like to think of mixins a bit like breeding new varieties of fruit or plants that have special new features, like say a super sweet tomato. Which of course does happen in real life :o )

    But perhaps we should consider the object lifetime itself as an significant context to your question. Many objects only exist for a few milliseconds, which of course is less like real world objects, so in that context the notion of extensive dynamic growth might be less useful. Sure some objects can be kept around in memory for hours, but you lose them eventually (only to be reloaded later from their persistence store).

    As VirtualStaticVoid pointed out, ActiveRecord objects grow… they start life with a small number of attributes and methods and dynamically gain their model specific members at runtime following a quick database inspection; however this only happens the once, and we seem to be discussing the idea of growth that is more continuous and beyond a simple onetime addition (?)

    Of course we can get away with this kind of dynamism in ActiveRecord because the domain is narrow and we can rely upon convention over configuration from the calling code. But if objects grew over an extended period of time, and could gain a considerably wider variety of powers and behaviours, I wonder if this would become a problem of explosive complexity i.e. if our object can potentially do a vast array of things, we may have to write more code to prod the object to ask it what it can do. Will increasing dynamic complexity in the observed object (that which is not defined in the class at write-time) require increasingly unmanageable complexity in its observers?

    Sooo…. I’m thinking that this might only be useful where growth is much more um… fractal (?), and by that I mean if growth could be in some sense unpredictable, but the actual growth itself would have to be composed of a much smaller subset of predictable component parts.

  • Chris

    Expanding on your human example, yes humans gain/lose abilities over time, but remember the old adage, “It’s not what you know, it’s who you know” :)

    I see benefits in systems that allow objects to send messages out, like Obj-C with it’s forwarding system that is built into the Root.

    Ruby is one of those languages that is on my list of things to learn ;)

  • http://publicvoidlife.blogspot.com/ copenhas

    When I started learning Python I had similar thoughts and I think there are very interesting implications when you embrace a dynamic mentality. Somethings that were hard in static land are now easy to do and flow well. Also there are things in dynamic land that you couldn’t cleanly duplicate in static.

    An idea I like to use as an example is being able to have a piece of code that can on the fly track down all class objects (I mean the actual runtime objects that represents a class) go through their methods and pump them through a higher order function to tack on extra functionality (logging, auditing, whatever). You could replace the classes’ methods with the new ones, take advantage of them, then go through and swap them back. This can happen at runtime and modifying a class object effects all instance objects of that class.

    Another interesting idea is that IronPython also has some kind of __clrtype__ hook for helping control what the CLR type of your Python object looks like. I haven’t looked very deeply into it thought, but my first impression is that it could be very cool indeed since you’ll need to interact with the CLR at some point.

    http://ironpython.codeplex.com/wikipage?title=Samples
    scroll down to the ClrType sample description

  • http://bjarte.com Bjarte

    I like to think (some) of the difference between C# and Ruby as class oriented programming vs. object oriented programming. In C# you need a class to create an object. The class is the blueprint. In Ruby, you can, if you want to create a plain object and build it up as you go (Actually it has a meta-class and so on, but you don’t think about it).

    The dynamic nature of Ruby is truly a cool thing, but it can become scary and sometimes unmaintainable as objects ‘grow’. I have seen projects taking this too far. As with all weapons, you need to be careful :)

    And yeah, I think developers (and people in general) can grow. It’s a matter of the right environment and mindset

    P.S JavaScript is great for growing objects ;)

  • http://www.timvw.be timvw

    Although instances of classes are usually mutable, their type remains static.
    (As a human my skills will evolve (has-a/can do), but i will never become a fish (is-a))

    The hard problem with change is keeping track of those changes (version control).
    I still have to see a language/runtime that has it built in at the core.

  • http://bejitt.com/ Chris Waters

    I second the JavaScript for growing objects as well and, if I remember correctly, Lua is just about the same. IIRC (bad memory here, hi) these languages implement ‘objects’ as a Map, so adding (or removing..!) methods/properties could be done at runtime.

  • svb

    Dynamically altering objects certainly looks pretty cool and is probably also useful, but, just like with everything else, I would certainly have a good look at the problem first before throwing something like this at it :)

    To illustrate: the fact that a Person object can lose or gain behavior and attributes during its life-time could also indicate that the behavior and attributes aren’t intrinsic to the Person object after all and that it can be modeled a different way. A Person might for instance gain the ability to write or the ability to speak. The speaking capability might be modeled as a Speaker object and the writing capability might become a Writer object. These are just roles of a Person object that expand the basic capabilities of a Person. With each role a Person will gain new abilities, but not every Person will have all roles and once a role is acquired a Person can lose it again. This is just one way (not the way) to solve the problem you are describing, although it may all depend on the context of course :)

  • http://davybrion.com Davy Brion

    @Svb

    True, you can’t just go around and adding behavior all over the place without properly structuring that behavoir :) . Otherwhise, the Person class would by default already by huge for all of the basic tasks that it needs to support.

    For people who can’t write, the Writer object would always be null and then you could wonder: should it even be there? Perhaps writing is a bad example since most people can do that, but if a large group of people couldn’t write, you could make a claim that the Person class shouldn’t contain anything with regards to Writing, at least not by default.

    But once a person learns how to write, you could dynamically add a Writer instance to it, and then add some methods which delegate to the Writer instance so this particular Person object now passes the “can this thing write?” test that certain methods might perform.

  • svb

    @Davy Brion

    You are right: it feels a bit “strange” that Person can have a Writer object while there are a lot of Persons who are unable to write. But you could also ask yourself the question: is there a reason why a Person should even be aware that he can write? Sometimes this might be the case, but certainly not always.

    A less abstract example: a Person who works for a company. When a Person is assigned to a project, he fulfills the role of a Team Member. Because Team Member is a role for Person, a Team Member needs to know which Person he belongs to. But should the opposite also be true? In the context of a project probably not: in this context only the role Team Member is relevant (but you will make use of Person through this role). The same goes for HRM: in the context of HRM you will make use of Person through its role Employee. A Person object can be used in a lot of different contexts through his roles, but this does not mean that a Person actually needs to be aware of all the different contexts in which he is used.

    In this regard, both speaking and writing could also be considered two different contexts. But now we are probably straying away from the original topic of the post :)

  • http://davybrion.com Davy Brion

    @Svb

    Team Member and Employee seem like separate entities that have a reference to a Person. They are indeed roles and are probably just as important in the system (if not more) than the Person entity. Something like that will always be explicitely modeled because of their value to the system. They might be the reason there is a system in the first place.

    But writing and speaking aren’t really roles… they are capabilities that can be shared by all Persons, but also by some Devices for instance… or maybe even Aliens.

  • Daniel

    Hi Davy!

    If you are interested in a more elaborate discussion of the subject, please take a look at the following article, which I think discusses the problems you mentioned in an in-depth manner. Though it’s not a fresh one, it still has relevance:

    Hope you’ll like it.

  • Peter

    In statically-typed languages, objects can and do grow. Imagine calling Head.Remove(Hair hair) in a loop. It is the class, not the object (instance) that is seen as immutable. But that is by design choice. Classes are just defined by their membership (properties, including behavior) and names of classes are shorthand for the contents. The var keyword and anonymous types in C# help to illustrate that the name of a class is more of a convenient identifier than a necessary imprimatur.

  • GunShoe

    And because of your earlier post Davy. I am now ready to purchase my first own Ruby book (as a language reference).

  • Dennis