Objects – Full of sound and fury

All my professional career, “object oriented programming” has been a mantra and guidepost. Going all the way back to Pascal, through Smalltalk, Objective-C, C++, C#, Jave, etc. Encapsultation, inheritance, polymorphism, etc. It’s a religion.

If I go back further, to simula, or snobol, or some such, I’m sure I can find the roots of the thing. Would I rip it out? I don’t know. One thing has become abundantly clear to me though. In an attempt to “objectify” the world, my programming sometimes takes on characteristics, and twists, and constraints that I did not really intend, and don’t actually help my cause at all.

So, like many things, I’ve begun to simplify. Case in point:

local Tadpole_t = {}
Tadpole_t.Speak = function(atad)
  if atad and atad.name then
    print("My name is:", atad.name)
  else
    print("No Name")
  end
end

I have a function which prints out the “name” field of an object, if it exists. I so happened to put this function into a table called “Tadpole_t”, just because I want to group some other functions in this table as well. With this construct, I can easily do this:

-- First way, no real 'objects'
local pole1 = {name="William"}
Tadpole_t.Speak(pole1);
> My name is: William

Alrighty, no big deal, just a function that prints something out. Of course, there’s no structure here. I didn’t have to tie the ‘Speak’ function to a structure, or any other object hierarchy. It will work if the field ‘name’ exists, otherwise it won’t, and that’s that.

Taking another step, I want to create tables that have this field in them, and I want to ensure I do it the same way every time:

local Tadpole = function(name)
	local obj = {
		name = name,
	}

	return obj
end

This now allows me to do the following:

-- Second way, a constructed object
local pole2 = Tadpole("Albert")
Tadpole_t.Speak(pole2)
> My name is: Albert

Calling the “Speak” function the same as in the first case, only the little table that contained the ‘name’ field was constructed within a function. Some might call this a ‘constructor’ if you were following object oriented paradigms. But still, there’s not much ‘object oriented’ about this, other than some encapsulation. At this point, I realize that I have all the basics I need. Most of my ‘object oriented’ programming comes down to this simple construct. Creating something that has some well known fields in it, and calling some functions that expect those well known fields. I don’t need any further language constructs to achieve my goals, so anything else the language offers on top is gravy. And it’s just that, gravy, nothing more. So, in the following, there are more lines of code, but they’re just the gravy that goes with these core object oriented meat and potatoes:

local Tadpole_t = {}
local Tadpole_t.Speak = function(atad)
  if atad and atad.name then
    print("My name is:", atad.name)
  else
    print("No Name")
  end
end

local Tadpole_mt = {
  __index = Tadpole_t
}

local Tadpole = function(name)
  local obj = {
    name = name,
  }
  setmetatable(obj, Tadpole_mt)

  return obj
end

-- Third way, constructed object, with associated function
local pole3 = Tadpole("Adams")
pole3:Speak()
> My name is: Adams

The ‘setmetatable()’, is Lua’s way of allowing the syntax which is: pole3:Speak(). That is, taking an instance of a table, associating some functions with it, and allowing you to use this ‘:’ syntax to make a ‘method’ call. But, you’ll notice, the ‘Speak()’ function never changed its signature. It started with having a single parameter, and that single parameter remains in the end. We just added some syntactic sugar through the language compiler to make things look more object oriented.

There are various other ways to achieve this, and there are multiple frameworks to make Lua ‘object oriented’. I have found that sticking with the simple basics though, is actually the best way to achieve what I’m after. I start programming like a typical ‘C’ programmer, not relying on too many fancy constructs, nailing my basic fields, properties and functions. Then, I slowly add in object oriented conceptual helpers when/if needed. I don’t get too hung up on trying to model a perfect simulation of a real world activity. I recognize that I’m just trying to call some functions that so happen to want to see some fields with some given names, and specific properties.

The object purist in me screams out “yah but a ‘name’ must be a string!!”. Well, does it really need to be? Will my world fall apart if it isn’t? Will some bugs creap in because the “Speak()” function is called on something that’s not a Tadpole_t? Probably not, and this way my world stays much more maintainable.

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s