NAME
Class::Holon - An experiment in redefining class declarations / object instantiation in perl.
SYNOPSIS
package Atom;
use Class::Holon
(
To => DescribeLevel,
Type => Hash,
Data => { protons=>0, neutrons=>0, electrons=>0 },
);
package main;
use Atom;
my $atom = Class::Holon::New('Atom');
DESCRIPTION
This module is an experiment in redefining class declarations and object instantiation in perl. The intent is to eventually encapsulate many of the common things that classes and objects find useful so that people do not have to reinvent the wheel to use them. I would also like for it to make certain capabilities available to programmers that are not available in native perl.
VOCABULARY
The term Holon
was blatantly stolen from Authur Koestler (1905-1983). I believe he coined the term in 1967, but I'm not certain. I was actually introduced to the term via a book written by Ken Wilber, but I digress.
First, some definitions:
HOLON DEFINITION
Holon
A holon is a node in a tree structure. Holon comes from the Greek holos meaning "whole" and on meaning "part" or particle. The key characteristics of a holon include that it asserts its individuality in order to maintain the set order in the tree structure, but it also submits to the demands of the whole tree structure (the system) in order to make the system viable. Holons are self-contained, autonomous pieces which follow a prescribed set of rules. The holon has a "self-assertiveness tendency" (wholeness) as well as an "integrative tendency" (part).This duality is similar to the particle/wave duality of light. (Koestler)
Once you have some Holons, you can put them in a structure called a holarchy.
HOLARCHY DEFINITION
Holarchy
A holarchy is a hierarchy of holons. Entire organs such as the kidneys, heart, and brain are capable of continuing their functions, as quasi-independent wholes, when isolated from the organism and suplied with the proper nutrients.
Characteristics of Holarchies:
Bi-directionality: Each holon can receive signals as well as send signals. The "flow" in a holarchy is both up and down.
Level behaviour: The holon at one level is not necessarily the "sum" of its subordinates. The characteristics of holons at one level are not representative of the characteristics of the level above or below them. The further down the holarchy, the more mechanized, stereotyped, and predictable the behavior. Higher level holons have more flexibility and function a more abstract state.
Flexibility: Holarchies are not rigid structures; they allow modification and adaptability. A holon can be part of multiple holarchies.
Open-ended: The top and the bottom of holarchies are not absolute. A holarchy can be augmented or interwoven with another holarchy.
HOLONS IN PERL
You can Describe a holon level.
use Class::Holon ( To => DescribeLevel, ... );
You can Specify a specific type of holon level.
use Class::Holon ( To => SpecifyLevel, ... );
You can Instantiate new holons based on their description / specification.
my $instance = Class::Holon::New( ... );
Describe and Specify defines what a holon looks like. Once a holon is defined, you can Instantiate them.
DESCRIBING A LEVEL
A perl package namespace is used to give a holon level its Name. Each package can call use Class::Holon (...)
once and only once to describe or specify a level.
If you find you have defined a holon that has a Name
attribute, then you should rethink your entire approach.
The perl package that calls use Class::Holon
determines the holon name.
So, say you want to define an "Atom" holon. First, get into package Atom. Then call use Class::Holon ();
with the appropriate attributes.
package Atom;
use Class::Holon
(
To => DescribeLevel,
Type => Hash,
Data => { protons=>0, neutrons=>0, electrons=>0 },
);
1; # thats it!
Or say you want to define a "Movable" holon, which keeps track of x,y,z coordinates of something.
package Movable;
use Class::Holon
(
To => DescribeLevel,
Type => Hash,
Data => { posx=>0, posy=>0, posz=>0 },
);
Or, say you want to define a "Dogtag" holon.
package Dogtag;
use Class::Holon
(
To => DescribeLevel,
Type => Hash,
Data => { Name=>'', Rank=>'', SerialNumber=>0 },
);
Or, say you want to define a "Bucket" holon that stores an array of scalars.
package Bucket;
use Class::Holon
(
To => DescribeLevel,
Type => Array,
Data => [],
);
Last, but not least, say you want to define a "Helicopter" holon. And like a helicopter, it's fast and small, but somewhat difficult to control.
package Helicopter;
use Class::Holon
(
To => DescribeLevel,
Type => GetSet,
Data => { Speed=>0, Altitude=>0 },
);
I'll go into more detail about the "GetSet" type later.
To
has two possible valid values, DescribeLevel
and SpecifyLevel
.
Type
has three possible valid values, Hash
, Array
, and GetSet
.
Data
will define the attributes, and possibly, their initial value.
Data
is where the attributes for the holon are defined. Note that Dogtag
has a Name attribute. This is OK in this case, since the Name of the holon is Dogtag
. The Name
attribute in this case refers the name of the person associated with each Dogtag
instance.
If your Data
has defined a Name
attribute, just make sure you're defining your holons properly.
VARIATIONS ON DATA
The Data
entry has a number of different flavors.
If Type
is a Hash
or GetSet
, then Data
can indicate the attribute names using an array reference.
Type => Hash,
Type => GetSet,
Data => [ attribute1, attribute2, attribute3, ... ],
If Type
is a Hash
or GetSet
, then Data
can use a reference a hash, where the keys indicate the attribute names, and the Data indicates its initial value.
Type => Hash,
Type => GetSet,
Data => {
attribute1 => initial_value1,
attribute2 => initial_value2,
...
},
Note, that if ANY attribute has an initial value, then they ALL must have an initial value. If you care about some initial values, but dont care about others, just use undef
for the ones you don't care about.
If Type
is an Array
, then Data
can ONLY be a reference to an array. The contents of the array indicate the initial values of an array instance, rather than the attribute names.
Type => Array,
Data => [ init_value_index_0, init_value_index_1, ... ],
Holons of type Array
and Hash
do not need to indicate Data
. The instances are references to normal arrays/hashes, therefore, they can autovivify as usual.
Holons of type GetSet
must define its Data
attributes so that use Class::Holon
can create the necessary methods in the proper package.
Note, if the initial value is a subroutine reference, the subroutine will be executed upon an object's instantiation.
package Frankenstein;
use Class::Holon ( To => DescribeLevel, Type => Hash,
Data => { Yell => sub { print "It's ALIVE!!"; } },
);
package main;
use Frankenstein; # no output here.
my $monster = Class::Holon::New('Frankenstein'); # It's ALIVE!!
&{$monster->{Yell}}(); # It's ALIVE!!
CREATING AN INSTANCE OF A HOLON
Once you've described a holon level, you can create instances of that level. The description of the level does NOT need to define a constructor. You have already defined everything perl needs to know in the use Class::Holon(...)
call.
package main;
use Atom;
my $atom_instance = Class::Holon::New('Atom');
Note that package main
did not have to say use Class::Holon
. This is because when main calls use Atom
, package Atom will call use Class::Holon
, and use Class::Holon
will pull the Class::Holon.pm
perl package into the mix. You only have to use
whatever holons you are using directly. Everything else is handled under the hood by the Holon module.
Class::Holon::New takes one parameter, the name of the level to create. This coincides with the name of the perl package that called use Class::Holon (...);
In this case, Class::Holon::New('Atom') will return an instance of whatever holon was described in package Atom;
.
The instance is in the form of a reference to what ever Type was defined for that holon. In this case, it is a reference to a hash.
The instance is a reference, and whatever it is pointing to (the referent) will be blessed into the package of the holon level. In this case, it is blessed into the Atom
package.
The instance will be initialized to any values given in Data
. In this case, $instance will refer to a hash containing the keys Name
, Rank
, and SerialNumber
.
If an initial value is given to use Class::Holon
in the form of a code reference, then that code reference will be executed at instantiation. See above for more info on
use Class::Holon ( Data => ... )
GETTING MORE SPECIFIC DESCRIPTIONS
Let's assume we've been tasked with writing some perl code that will allow us to model chemical experiments. (I'm not a chemist, but I play on TV.)
The Atom holon seems to be a good start. However, since we're talking about chemical experiments and not physics, its probably safe to assume that our application will not need to split atoms. Therefore, we could describe specific atoms.
When you Specify a holon level, you are taking a description and making it more specific.
The names of the attributes remain the same. But the values can be different.
In perl, the keys of the Data
hash are the same, but the values can be different.
In the Atom example, it might look like this:
package Atom::Hydrogen;
use Class::Holon (
To => SpecifyLevel,
Data => { protons=>1, neutrons=>0, electrons=>1 },
);
package Atom::Oxygen;
use Class::Holon (
To => SpecifyLevel,
Data => { protons=>8, neutrons=>8, electrons=>8 },
);
Note, we are no longer defining Type
. Instead, we use the same Type
that was given in Atom
.
Also note that we are defining different Values for Data
. The Attributes MUST match the attributes used to define Atom
.
This may or may not have a use in your application. If a subroutine is called on Atom, and a large case statement is needed to determine how to handle the Atom based on which atom it is, then it may be advantageous to give the Atom a qualifying name so that the proper subroutine can be called more directly. (this would be the approach for using multimethods, but we're getting ahead of ourselves.)
THE GETSET TYPE
The holon type GetSet
is a little different than the others. The data in the holon is stored in an inaccessible array. The only means to access the data is via method calls. The names of the methods are the names of the Data
attributes, but with a suffix to indicate what action to perform. These methods are imported in the package when you call use Class::Holon
.
For instance:
package Helicopter;
use Class::Holon (
To => SpecifyLevel,
Type => GetSet,
Data => { Speed=>0, Altitude=>0 },
);
package main;
my $jetranger = Class::Holon::New('Helicopter');
$jetranger->SpeedSet(110);
my $altitude = $jetrange->AltitudeGet;
The type GetSet
hides the attribute implementation from the user. The array data contained in each object is not accessible except through the methods.
The method names are based off of the attribute name. The intention is to have the methods act like hash keys to make them easy to use, but for the object to have the speed and size as close to an array as possible.
Given an attribute name in the Data
Description
, the following methods are available to call on an object.
attributeGet return the value of the attribute
attributeSet store a new value in the attribute
attributeInc increment the value of the attribute by 1.
attributeDec decrement the value of the attribute by 1.
attributeAdd Add a value to the attribute
attributeSub Subtract a value from the attribute
attributeMul Multiply the attribute by some value
attributeDiv Divide the attribute by some value
attributeNeg Negate the attribute (multiply by -1)
attributeMod Take the modulus of the attribute and put in attribute
This means that in the above example, after calling use Class::Holon
, package Helicopter would contain subroutines such as:
SpeedGet
SpeedSet
AltitudeGet
AltitudeSet
Note, Get
and Set
may change to Rd
and Wr
Get and Set are too similar for my comfort.
THE NEXT LEVEL UP
DEBUG: introduce MovableAtom module.
Documentation ran out of steam at this point. skipping to ending boiler plate.
BUGS
none known so far.
QUOTES
True creativity often starts where language ends - Authur Koestler
DSLIP
DSLIP = ADPHP
AUTHOR
Greg London http://www.greglondon.com
COPYRIGHT NOTICE
Copyright (c) 2001 Greg London. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.