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).
field type
: Field
sub Foo : Field;
sub foo : Field(Ref)
(1) (actually, Class::CompiledC utilizes Inline to do the dirty work; Inline uses Inline::C to do it's job and Inline::C 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 attributes 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
attributes
(3) sub foo; remember ? also called forward declaration see perlsub
forward declaration
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)
UNIVERSAL-
sub Foo : Field(Number)
At current this just an alias for the Float type, but that may change.
Float
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.
Isa
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.
parseArgs
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.
inspect
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 Inline::C 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.
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.
__scheduled
__scheduleIfNeeded
__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.
__schedule
__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.
base
ext
__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.
@ISA
__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
__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.
__genExtFuncCode
C
__genBaseCode SELF, PACKAGE Type: class method
Generates the C code for all fields. You can define fields with the Field attribute.
Field
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.
create
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.
$_[1].$_[0].$_[1]
__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.
$_
\n#include $_\n
Include
<
""
__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.
__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.
isa
__parseFieldType
__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.
__promoteFieldTypeToMacro
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
__circumPrint
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
Isa(Universal)
Object
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
blade@focusline.de
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.
To install Class::CompiledC, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Class::CompiledC
CPAN shell
perl -MCPAN -e shell install Class::CompiledC
For more information on module installation, please visit the detailed CPAN module installation guide.