Class::CompiledC
This document describes version 2.21 of Class::CompiledC, released Fri Oct 27 23:28:06 CEST 2006 @936 /Internet Time/
Class::CompiledC -- use C structs for your objects.
package Foo; use strict; use warnings;
use base qw/Class::CompiledC/;
sub type : Field(String); sub data : Field(Hashref); sub count : Field(Int); sub callback : Field(Coderef); sub size : Field(Float); sub dontcare : Field(Number); sub dumper : Field(Isa(Data::Dumper)); sub items : Field(Arrayref); sub notsure : Field(Object);
my $x;
$x = Foo->new(-type => "example", -data => {}, -count => 0, -callback => sub { print "j p " ^ " a h " ^ " " x 4 while 1}, -size => 138.4, -dontcare => 12, -dumper => Data::Dumper->new, -items => [qw/coffee cigarettes beer/], -notsure => SomeClass->new );
Note: Documentation is incomplete, partly outdated, of poor style and full of typos. I need a ghostwriter.
Class::CompiledC creates classes which are based on C structs, it does this by
generating C code and compiling the code when your module is compiled (1). You
can add constraints on the type of the data that can be stored in the instance
variables of your objects by specifiying a field type (i call instance
variables fields because it's shorter). A field without constraints are declared
by using the : Field attribute (2) on a subroutine stub (3) of the name you
would like to have for your field eg. sub Foo : Field; this would generate a
field called 'foo' and it's accesor method, also called 'foo' If you want to add
a constraint to the field just name the type as a parameter for the attribute eg
sub foo : Field(Ref).
(1) (actually, Class::CompiledC utilizes the Inline manpage to do the dirty work; the Inline manpage uses the Inline::C manpage to do it's job and the Inline::C manpage employes your C compiler to compile the code. This means you need Inline Inline::C and a working C compiler on the runtime machine.
(2) attributes perl6 calls them traits or properties; see the attributes manpage not
to confuse with instance variables (fields) which are sometimes also called
attributes; terms differ from language to language and perlmodules use all of
them with different meanings, very confusing
(3) sub foo; remember ? also called forward declaration see the perlsub manpage
for the truly insane.
TODO
The following Field types are currently supported by Class::CompiledC
sub Foo : Field(Any)
NOOP. Does nothing, is even optimized away at compile time. You can use it to explicitly declare that you don't care.
sub Foo : Field(Arrayref)
Ensures that the field can only hold a reference to an array. (beside the always legal undefined value).
sub Foo : Field(Coderef)
Ensures that the field can only hold a reference to some kind of subroutine. (beside the always legal undefined value).
sub Foo : Field(Float)
Ensures that the field can only hold a valid floating point value. (An int is also a valid floating point value, as is undef).
sub Foo : Field(Hashref)
Ensures that the field can only hold a reference to a hash. (beside the always legal undefined value).
sub Foo : Field(Int)
Ensures that the field can only hold a valid integer value. (beside the always legal undefined value).
sub Foo : Field(Isa(Some::Class))
Ensures that the field can only hold a reference to a object of the specified
class, or a subclass of it. (beside the always legal undefined value). (The
relationship is determined the same way as the UNIVERSAL-isa> method)
sub Foo : Field(Number)
At current this just an alias for the Float type, but that may change.
sub Foo : Field(Object)
Ensures that the field can only hold a reference to a object. (beside the always legal undefined value).
sub Foo : Field(Ref)
Ensures that the field can only hold a reference to something. (beside the always legal undefined value).
sub Foo : Field(Regexpref)
Ensures that the field can only hold a reference to a regular expression object. (beside the always legal undefined value).
sub Foo : Field(String)
Ensures that the field can only hold a string value. Even everything could theoretically expressed as a string, only true string values are legal. (beside the always legal undefined value).
Field types are case insensitve. If a type expects a parameter, as the Isa
type, then it should be enclosed in parenthises. Whitespace is always ingnored,
around Field types and parameters, if any. Note, however that the field type
Int, spelled in lowercase letters will be misparsed as the `int` operator, so be
careful.
Currently there are two categories of additional features: those going to stay, and those going to be relocated into distinct packages.
First the stuff that will stay:
Every subclass inherits this method. Its purpose is to ease the use of named parameters in constructors. It takes a list of key => value pairs. Foreach pair it calls a method named like the key with value as it only parameter (beside the object, of course), i.e:
$obj->parseArgs(foo => [], bar => 'bar is better than foo');
Would result in the following method calls:
$obj->foo([]); $obj->bar('bar is better than foo');
The method also strips a leading dash ('-') from the method name, in case you prefer named arguments starting with a dash, therefore the following calls are equivalent :
$obj->parseArgs(-foo => 123, -bar => 456); # dashed style
$obj->parseArgs(foo => 123, bar => 456); # dashless style
$obj->parseArgs(-foo => 123, bar => 456); # no style
Since this method needs key => value pairs it will croak if you supply it an odd number of arguments. actually it croaks on an even number of arguments, if you also count the object. but the check for oddnes is done after the object is shifted from the argument list
parseArgs returns the object.
Every subclass inherits this method, it is merely a wrapper around the real constructor (which is called 'create'). It first constructs the object (with the help of the real constructor) and then calls parseArgs on it. This means the following code is equivalent :
my $obj = class->new(-foo => 'bar');
#----
my $obj = class->create; $obj->parseArgs(-foo => 'bar');
Only shorter ;)
This method is created for each subclass. It returns a hashref with the field names and their types. A short example should clarify what I try to say:
package SomeClass; use base qw/Class::CompiledC/;
sub foo : Field(Int); sub bar : Filed(Hashref);
#### at same time in some other package:
use SomeClass; use Data::Dumper;
my $obj = Somelass->new;
print Dumper($obj->inspect);
### prints something like
$VAR1 = { 'foo' => 'Int', 'bar' => 'Hashref', }
Be aware that this purely informational. Even you can change the data behind
this reference, nothing will happen. The changes will not persist, if you call
inspect again, the output will be the same. Especially do not expect that you
can change a class on the fly with that hash, this won't work. You should also
know that two calls to inspect will result in two distinct hash references, so
don't try to compare those references. Even the hash those references refer to
is diffrent, if you really want to compare than you have to do a deep compare.
The C attribute allows you to write a subroutine in C, eg:
sub add : C(int, int a, int b) {q{ return a + b; }}
The return type and the parameters are specified in the attribute, and the function body is in the subroutine body. Therefore the resulting C code looks like:
int add(int a, int b) { return a + b; }
You may have noticed that the actual body of the C function is whatever the (Perl subroutine returned, so this code :
sub getCompileTime(int, ) { my $time = time; my $code = "return $time";
return $code;
}
will result in this C code :
int getCompileTime() { return 1162140297; }
The time value, is subject of change, of course. If you wonder what perl can do with c intergers, all (with a few exceptions) C code is subject to XS-fication by the Inline::C module, which handles this sort of crap behind the scenes. You should have a look at the Inline::C manpage for bugs and deficiencies, but do yourself and the author of Inline a favor and not report any bugs that might showup in conjunction with Class::CompiledC to the author of Inline, report them to me. I'm cheating with Inline, and most problems you might encounter wouldn't show up by using Inline correctly.
Be advised that you have full access to perls internals within your C code and to take any usage out of this feature you should read the following documents:
Perl XS tutorial
Perl XS application programming interface
Internal replacements for standard C library functions
Perl internal functions for those doing extensions
Perl calling conventions from C
XXX The stuff that will be outsourced is not yet documented.
Of course, you should also know how to code in C. One final notice: This feature has been proven as an endless source of fun and coredumps.
The methods listed here are not considered part of the public api, and should not be used in any way, unless you know better.
Class::CompiledC defines the following methods:
__scheduled SELF, PACKAGE Type: class method
the __scheduled method checks if package has already been scheduled for compilation. returns a a true value if so, a false value otherwise.
__scheduled SELF, PACKAGE Type: class method
the __schedule method schedules PACKAGE for compilation.
Note.: try not to schedule a package for compilation more than once,
you can test for a package beeing scheduled with the __scheduled method,
or you can use the __scheduleIfNeeded which ensures that a package doesn't
get scheduled multiple times.
__scheduleIfNeeded SELF, PACKAGE Type: class method
the __scheduleIfNeeded method schedules PACKAGE for compilation unless it
already has been scheduled. Uses __scheduled to determine 'scheduledness'
and __schedule to do the hard work.
__addCode SELF, PACKAGE, CODE, TYPE Type: class method
Add code CODE for compilation of type TYPE to PACKAGE.
Currently supported types are base (code for fields) and
ext (code for addional c functions). Before compilation
base and ext coe is merged, base first, so that ext code
can access functions and macros from the base code.
__compile SELF, PACKAGE Type: class method
Compiles the code for PACKAGE.
__traverseISA SELF, PACKAGE, HASHREF, [CODEREF] Type: class method
Recursivly traverses the @ISA array of PACKAGE,
and returns a list of fields declared in the inheritance
tree of PACKAGE. HASHREF which must be supplied (and will be modified)
is used to ensure that fields will only show up once.
CODEREF is a optional parameter, which, when supplied,must be a reference to
the method itself and is used for recursion. If CODEREF is not supplied,
__traverseISA determines it on it's own.
__addParentFields SELF, PACKAGE Type: class method
Adds the fields from SUPER classes to the list of fields.
__doIt SELF, PACKAGE Type: class method
Inherits parents fields, generates base code, generates ext code, and starts
compilation for package PACKAGE. This method is meant to be called from CHECK
block in the target package. The __schedule or more safely the
__scheduleIfNeeded method can arrange that for you.
__genExtFuncCode SELF, PACKAGE, NAME, RETVAL, ARGS, CODEREF Type: class method
Generates a single ext function, NAME in package PACKAGE with return type RETVAL
and parameters ARGS, with the body returned from CODEREF. Meant to be called by
the __genExtCode method.
__genExtCode SELF, PACKAGE Type: class method
Generates all ext functions in package PACKAGE. Utilizes the __genExtFuncCode
method to do the dirty work. You can define ext functions with the C
attribute.
__genBaseCode SELF, PACKAGE Type: class method
Generates the C code for all fields.
You can define fields with the Field attribute.
parseArgs SELF, LOTS_OF_STUFF Type: object method
Used for named parameters in constructors. Returns the object, for simplified use in constructors.
new SELF, PACKAGE, LOTS_OF_STUFF Type: class method
Highlevel Constructor, first calls the create constructor to allocate the C
structure, and then calls parseArgs to initialize the object.
The subroutines listed here are not considered part of the public api, and should not be used in any way, unless you know better.
Class::CompiledC defines the following subroutines
__circumPrint TEXT, LEFT, RIGHT Type: Subroutine. Export: on request. Prototype: $$$
Utitlity function, concatenates it's arguments, in the order
$_[1].$_[0].$_[1] and returns the resulting string. Does not print anything.
__include I<NOTHING> Type: Subroutine. Export: on request. Prototype: none
Takes $_ and returns a string in form \n#include $_\n. This subroutine is
used to generate C include directives, from the Include attribute. Note
that it doesn't add <> or "" around the include, you have to do this your
self.
__baseref REFERENCE, TYPE Type: Subroutine. Export: on request. Prototype: $$
Determines if REFERENCE is actually a reference and and is of type TYPE.
__hashref REFERENCE Type: Subroutine. Export: on request. Prototype: $
Determines if REFERENCE is actually a hash reference.
Utitlizes __baseref.
__arrayref REFERENCE Type: Subroutine. Export: on request. Prototype: $
Determines if REFERENCE is actually a array reference.
Utitlizes __baseref.
__coderef REFERENCE Type: Subroutine. Export: on request. Prototype: $
Determines if REFERENCE is actually a code reference.
Utitlizes __baseref.
__fetchSymbolName GLOBREF Type: Subroutine. Export: on request. Prototype: $
Returns the Symbol name from the glob reference GLOBREF. Croaks if GLOBREF acutally isn't a glob reference.
__promoteFieldTypeToMacro FIELDTYPE Type: Subroutine. Export: on request. Prototype: none
Takes a fieldtype specfication, and returns a C macro for doing the test.
Does not handle parametric types like isa. See __parseFieldType for that.
__parseFieldType FIELDTYPE Type: Subroutine. Export: on request. Prototype: none
Takes a fieldtype specfication, and returns a C macro for doing the test.
Handles all field types. Delegates most work to the __promoteFieldTypeToMacro
subroutine.
sub Foo : C(...) Include(<math.h>)
sub Foo : Field(...) Include("bar.h")
Type: Attribute Handler Export: no.
sub Foo : C(RETVAL, ARG0, ...)
Type: Attribute Handler Export: no.
sub Foo : Field(TYPE)
Type: Attribute Handler Export: no.
sub Foo : Alias(\&REALMETHOD)
Type: Attribute Handler Export: no.
sub Foo : Overload(OPERATOR)
Type: Attribute Handler Export: no.
sub Foo : Const(VALUE)
Type: Attribute Handler Export: no.
sub Foo : Abstract
Type: Attribute Handler Export: no.
sub Foo : Class(CLASS)
Type: Attribute Handler Export: no.
Class::CompiledC inherits the following methods from it's ancestors
Attribute::Handlers
import
_resolve_lastattr
DESTROY
_gen_handler_AH_
_apply_handler_AH_
Class::CompiledC does not export anything by default but has a number of subroutines to Export on request.
Class::CompiledC defines the following export tags:
The following subroutines are (im|ex)portable, either explicitly by name or as part of a tag.
__include
__arrayref
__coderef
__hashref
__fetchSymbolName
__baseref
__circumPrint
__parseFieldType
__promoteFieldTypeToMacro
TODO
no package supplied
this message is usually caused by an class method called as a subroutine. fatal error
no target package supplied
Some methods (and subroutines, btw) need a target package to operate on, it seems that the argument is missing, or has evaluated to false value, which very unlikely to be valid. fatal error
no code supplied
This message is is caused by the __addCode method, which renders useless without a supplied code argument. fatal error
no type supplied
This message is caused by the __addCode method, when called without a type
argument. The __addCode method can only operate with a valid type argument.
Currently valid types are base and ext but more may be added in future.
fatal error
bad type supplied
This message is caused by the __addCode method, when called with a invalid type
argument. Currently valid types are base and ext
but more may be added in future.
fatal error
fail0r: isa type needs a classname argument
This message is caused by the __parseFieldType subroutine. The __parseFieldType
subroutine (which gets called by the Field attribute handler) found isa as
type but without a classname. A is a check doesn't make sense without a
classname. If you just want to make sure that it is a object, you may use
Isa(Universal) or (generally faster and shorter) Object.
fatal error
fail0r: not a hash reference
This message is caused by the __traverseISA method, which needs a hashreference as third argument, for speed considerartions. fatal error
fail0r: f arg supplied but not a code ref
This message is caused by the __traverseISA method, which accepts a reference to itself, both for efficiency reasons and security from renamings. fatal error
no found hash supplied
This message is caused by the __traverseISA method, when called without the third argument. (Which must be a hashreference, and will be changed by the method) fatal error
no symbol supplied
This message can be issued from different sources, but most often by attribute handlers, which misses a reference to a typeglob. Don't call attribute handlers on your own. (unless you really know what you do) fatal error
no reference supplied
This message can be issued from different sources, but most often by attribute handlers, which misses a reference to whatever they decorate. Don't call a ttribute handlers on your own. (unless you really know what you do) fatal error
no attribute supplied
This message can be issued from different sources, but most often by attribute handlers, which misses the attribute they should handler. Don't call a ttribute handlers on your own. (unless you really know what you do) fatal error
no includes supplied
This message is caused by the Include attribute handler.
The Include handlers just couldn't figure out what to do.
Give him a hand and specify what should be included. fatal error
no return type and parameters specified
This message is specific to the C attribute handler subroutine.
To compile the code it needs to know the return type and the parameter list
of the C function to be compiled. fatal error
no name supplied
This message is caused by the __genExtFuncCode method when called without a fieldname. fatal error
no retval supplied
This message is caused by the __genExtFuncCode method when called without a return type argument. fatal error
no args supplied
This message is caused by the __genExtFuncCode method when called without a args argument. fatal error
There are undoubtedly serious bugs lurking somewhere.
I still find too much things that are done the fast way instead of the right way, this really bothers me.
A few things need to be outsourced right away. I just don't know where to put them. Especially the stuff not related to classes should be placed somewhere else. The utility __.* subs (not methods!) could be placed in a different package and locally (or maybe lexically?) imported, to avoid namespace pollution of subclasses.
Random thought: lexical importing ? what a cute idea! is this possible?
blackhat.blade The Hive
Copyright (c) 2005, 2006
blackhat.blade The Hive. All Rights Reserved.
This module is free software. It may be used, redistributed
and/or modified under the terms of the Artistic license.