Ctypes update: pretty objects

doubi on 2010-08-09T03:24:22

Since my last couple of posts, things have been done:

  • Complete revamping of call logic
  • Finished objects for basic C Types (int, double etc.)
  • A fairly sound cast() function for Ctypes
  • Array objects
Despite this, I don't think I'm going to get everything implemented for the GSoC deadline :-/ Still a long list of features I want to add. Particularly notable by their absence are Pointers, Structures, Unions, paramflags and support for special Win32 objects (COM stuff, HRESULT and friends).

Crap... when you list it like that, sounds pretty dire, don't it?

Don't beat me up just yet though. I'll definitely get Pointers done in the next 48 hours. Not sure how tricky Structs and Unions will be but they'll definitely be done by the deadline too. Anyway, instead of wasting more time worrying I want to talk a bit more about my favourite topic...

Type object API revisited

In response to my full post on the matter [0], Aristotle [1] pointed out that if tie'd behaviour was the objective we could have the rather nice

c_int my $intobj = 5;

This is cool, but I was scundered by the fact that you couldn't then call methods on your $intobj. Boo-hoo.

The solution was embarrassingly simple, actually. I didn't so much think of it as came across it naturally when implementing Array types. To make an $arrayobject act like an array, I overloaded '@{}' to return the tied member of its internal hash, so you use it as an array and as an object like so:

use Ctypes;
my $array = Array( 1, 2, 3, 4, 5 );
# makes array of smallest necessary type, c_short

print $array;    # Ctypes::Type::Array=HASH(0x8b2d550)

print @$array;   # 12345

my $int1 = c_int( $$array[0] );
# $int1->val = 3

my $int2 = c_int( $array->[1] );
# $int2->val = 2

my $oops = c_int( $array[2] );
# $oops = 0, $arr[x] is undef

print "Top index of \$array is $#$array\n";
# Top index of $array is 4

print $array->type->typecode;   # 's' for short

Some might call sigil soup on that, but I like it. It gives you the best of both tied variables and objects. When using the object to do regular array stuff, you can think of '$array', including the dollar, as the var's identifier, so you put another sigil in front depending on what you want from it (@$array for contents as a list, $$array[x] for returning individual values, etc). For object stuff, just momentarily remember that '$array' is an object in its own right and call methods on it.

The embarrassing thing is, I basically overlooked the fact that '${}' is also overloadable. So we could easily assign to simple Type objects like $$int = 10, which is an improvement of 2 characters on the current shortest option, $int->(10). Well, not counting the spaces...

But it's less about the character count than about looking at a piece of code and immediately seeing that the value 10 is being assigned to something, which is the semantic that operation is representing, rather than it appearing that some method is being called with 10 as an argument. I don't think the hyper-sigilism is too bad in exchange for that. It'll make Ctypes code 'distinctive' to look at :-)


As always, comments are strongly encouraged; on my pointer to array problem, the Type object API, or the project in general. Go on, take a shot...


[0] http://blogs.perl.org/users/doubi/2010/07/thoughts-on-ctypestype-object-api.html
[1] Aristotle: http://plasmasturm.org