Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
Class::ArrayObjects(3)User Contributed Perl DocumentatioClass::ArrayObjects(3)

       Class::ArrayObjects - utility class for array based objects

	 package Some::Class;
	 use Class::ArrayObjects define	=> {
					     fields  =>	[qw(_foo_ _bar_	BAZ)],


	 package Other::Class;
	 use base 'Some::Class';
	 use Class::ArrayObjects extend	=> {
					     class   =>	'Some::Class',
					     with    =>	[qw(_zorg_ _fnord_ BEZ)],
					     import  =>	1,

       This module is little more than a cute way of defining constant subs in
       your own	package. Constant subs are very	useful when dealing with array
       based objects because they allow	one to access array slots by name
       instead of by index.

   Why use arrays for objects instead of hashes	?
       There are two apparently	compelling reasons to use arrays for objects
       instead of hashes.

       First: speed. In	my benchmarks on a few boxes around here I've seen
       arrays be faster	by 30%.	I must admit that my benchmarks	weren't
       perfect as I wasn't all that interested in speed	per se,	only in
       knowing whether I was to	take a serious performance hit or not (I was
       nevertheless pleasantly surprised to note the opposite, it can't	hurt).

       Second: memory. Memory was much more important to me as I was targeting
       a mod_perl environment where every bit of memory	tends to count.
       Depending on how	they are used, arrays use from 30% up to 65% less
       space than hashes. As a rule of thumb the more keys you have, the more
       you may save.

       It must be said though that despite the fact that I happened to be
       looking for ways	to save	space, it's not	a reason to jump into array
       based objects and start converting every	single hash you	have to	an
       array. Yes, I did see some of my	processes lose ~3Mo of unshared	memory
       so there	are definitely cases when it's useful. Such cases are usually
       when you	have lots of objects and/or structures that are	fairly similar
       in nature (ie have the same keys) but contain different values. I don't
       know how	Perl works internally but it would seem	only logical that it
       has to store the	keys with every	hash, whereas using arrays there are
       no keys (which is why this package exists: to provide you with
       something that looks like keys into arrays).

       In addition to that, this package can be	seen as	twisting slightly the
       view on how to do OO in Perl, encouraging some limited encapsulation of
       fields and extension subclassing	rather than override subclassing (the
       latter really being a matter of taste).

   Why not pseudo-hashes ?
       Pseudo-hashes never appealed to me, they	always seemed to have been
       hacked on top of	Perl. They never left experimental status, which
       probably	says a lot already. A number of	things that work with hashes
       and arrays don't	work with them (and development	seems to have
       stopped). And overall, they usually end up not saving you any space
       anyway. Pseudo-hashes must die.

   Why Class::ArrayObjects ?
       But why then use	this class instead of the "enum" or "constant" modules
       ? Because it adds extra sugar (yum).

       Its main	advantage over "constant" (imho	of course) is that you don't
       have to define the value	of each	field. Less typing, more readability.

       "enum" also provides that plus but it enforces naming rules in a	way
       which I find limiting (it probably has very good	reasons	to do so, but
       I think that they don't apply in	the context of array based objects).
       This module only	complains if you try to	use a field name that isn't a
       valid Perl sub name. (Note: right now it	doesn't	even complain because
       I was convinced when I wrote it that Perl would.	But it turns out that
       you are perfectly allowed to define a sub with a	forbidden name.
       Whether this is a bug or	a feature, I don't know).

       And last	but not	least, it defines a way	to allow for inheritance while
       using array based objects. A major drawback of array based objects is
       that unlike with	hashes,	if your	base class adds	a field, you have to
       move all	your fields' indices up	by one.	You shouldn't have to know
       such things, or even to care about it.

       Here, instead of	using the "define" option (which creates fields	in a
       class), simply use the "extend" option. Tell it which class to extend
       (it needs to be already loaded, and must	use Class::ArrayObjects	to
       define its fields too) and which	fields to add.	Class::ArrayObjects
       takes care of counting from the right index in your subclass. It	can't
       do multiple inheritance,	and unless someone hacks it in somehow I doubt
       it ever will.

       You may use the "import"	option to require that your parents' fields be
       defined in your own package too,	so that	you can	access them. It	is off
       by default so that you can use fields with the same names as those of
       your superclasse(s) (which is a plus over hash based objects) and also
       to avoid	defining subs all over your package without you	knowing	about

       It may be worth noting that the added functionality doesn't get in the
       way, and	using this to define constants is just as fast as using
       "constant" or "enum".

USING Class::ArrayObjects
       There are two ways to use Class::ArrayObjects, either to	simply define
       fields to use in	your own objects, or to	extend fields defined in a
       superclass of your. In a	wild burst of creative naming I	thus spawned
       into existence two options named	respectively "define" and "extend".

       The way the two are used	is the same:

       use Class::ArrayObjects option-name => hashref of options

   The define option
	 package Some::Class;
	 use Class::ArrayObjects define	=> {
					     fields  =>	[qw(_foo_ _bar_	BAZ)],

       "define"	has only one option: "fields". It is an	arrayref of strings
       which are the names of the fields you wish to use. They can be
       anything, so long as they are valid Perl	sub names.

   The extend option
	 package Other::Class;
	 use base 'Some::Class';
	 use Class::ArrayObjects extend	=> {
					     class   =>	'Some::Class',
					     with    =>	[qw(_zorg_ _fnord_ BEZ)],
					     import  =>	1,

       "extend"	has three options:

       o   class

	   This	defines	the class to extend (it	must also use
	   Class::ArrayObjects and have	been loaded previously). If that class
	   is not specified, it	will look at @ISA. If @ISA contains only one
	   item	it will	use that one.

       o   with

	   This	is exactly equivalent to "fields" except that it reads better
	   to have extend class	Foo with x,y,z.

       o   import

	   Defaulting to false,	setting	it to any true value will make your
	   superclasses' fields	also defined in	your package. This can be
	   needed at times, though I wouldn't encourage	its use.

   After that ?
       After you've defined fields, all	you have to do is use them as indices
       to your arrays.

	 package Some::Class;
	 use Class::ArrayObjects define	=> {
					     fields  =>	[qw(_foo_ _bar_	BAZ)],

	 my @arry = qw(zorg stuff blurp);
	 print $arry[_bar_]; # stuff

       Any operation you can do	on arrays with numeric indices works exactly
       the same	way. The only difference is that you are using names, which
       are much	easier to remember. There is no	performance penalty for	this,
       Perl is smart enough to inline the return values	of constant subs so
       that when in the	above example you say _bar_ it really sees 1.

   A note to mod_perl users
       The contexts in which I use this	module are mostly mod_perl related.
       In fact,	one of the reasons I created it	was to allow for the space
       efficient representation	of many	objects. It may	be further
       optimizable, but	so far it has already seemed to	work well.

       You can preload this module without defining any	fields as follows:

	 use Class::ArrayObjects qw();

       In that case, "import()"	will not be called and nothing will happen
       other then the preloading of the	code. As a precaution, even if it were
       called it would return immediately.

       I do recommend that you preload all modules that	are based on
       Class::ArrayObjects so that the data it stores internally about which
       fields belong to	which classes (in order	to allow for extension)
       remains shared by all the processes.

       I don't know of any outstanding bugs presently but it is	not impossible
       that some may have filtered out.	I have been using this module in
       production for some time	now, and it appears to be behaving with

       Of course, you mustn't define a field in	your package with the same
       name as another sub.

       As a rule of thumb, I find that this kind of class works	better for
       extension subclasses than for override subclasses, but YMMV.

	- add an interface to allow people to mess with	the internals on
	- add serialisation helpers to allow one to persist an object based
	on Class::ArrayObjects and later retrieve it regardless	of whether
	the order of the fields	have changed or	not.

       Greg Bacon's for	his article Perl Heresies: Building Objects Out	of
       Arrays which I read ages	ago and	inspired this module, one of the first
       I put on	CPAN.

       Slaven Rezic for	the @ISA patch.

       Robin Berjon,

       Copyright (c) 2000-2002 Robin Berjon. All rights	reserved. This program
       is free software; you can redistribute it and/or	modify it under	the
       same terms as Perl itself.

       nothing that I can think	of...

perl v5.32.1			  2008-04-14		Class::ArrayObjects(3)


Want to link to this manual page? Use this URL:

home | help