Thoughts on a Ctypes::Type object API
For the past few days I've been considering and experimenting with the design of simple Ctypes::Type objects. These are objects which, funnily enough, represent C data types for manipulation in Perl.
The reference implementation
Looking at the Python ctypes module, there were various things I didn't like. Python's simple types [0] can be summarized thusly:
>>> i = c_int(42) >>> print i c_long(42) >>> print i.value 42 >>> i.value = -99 >>> print i.value -99 >>>
Having to specify
i.value
seemed cumbersome for an object which essentially represents just that value and some rules for what kinds of values it can contain. So I started trying various things with tie
'ing and overload
ing. Indeed, I was about to start a fourth project branch on types [1] before reigning in and having another think about fundamental behaviour.Metaphor clash
The 'Metaphor Clash' section [2] of perldoc overload
made clear the difficulty I was having with my thinking. If you want to be able to say simply,
$int_obj = 42; # assign new value to Ctypes::Type::c_int object
and not have $int_obj smushed and replaced by a simple IV, you're forced to do something like,
$other_obj = $int_obj->copy();
on those occasions when that's the outcome you really want. That might not be regular for objects in Perl, but I think that this is more suitable in this domain, where as I mentioned before, objects are just there to represent special kinds of values. Particularly, it would let you do this:
$c_int = $c_long; # Put long value into integer type, with # appropriate checking on STORE
rather than having to say
$c_int->val = $c_long->val;
Normal usage
I think that once you've instantiated a Ctypes::Type object, what you're going to be doing 90% of the time is assigning values to it or assigning its value to other things. The times when you want to squash the object with a different object or value, instead of just creating a new one, will be rare, and there can be special methods for doing those things.
What do you think? Is this a reasonable generalisation to make? How would you like Type objects to work?
Other issues
There are a couple of other issues tangential to this which I'd like to flag up while we're at it...- The latter behaviour, while IMO preferable, will I think be harder to implement. I haven't yet found a way using only Perl to hide the process of
tie
'ing a variable from the user. This is horrible:
my $int = 5; # regular scalar c_int(\$int); # make it a Ctypes::Type
but it's one of the only ways to enable the assignment of new values to the object without using an accessor every time (the other way is returning a reference fromc_int()
and requiring users to say$$int
all the time). I think the desired effect would be possible, butc_int()
will have to be written in XS. That's fine, but I want to sound out opinions on whether I'm making the right choices on functionality first. - The latter behaviour, while IMO better than that in Python's ctypes, may represent a significant difference from the de facto 'conventional' way of doing things. This raises a bunch of issues to be addressed in a subsequent post.
Please do let me know what you think of the above proposals. I'm highly suggestible.
[0] http://docs.python.org/library/ctypes.html#fundamental-data-types
[1] http://gitorious.org/perl-ctypes/perl-ctypes
[2] http://perldoc.perl.org/overload.html#Metaphor-clash
Perl is a pass-by-reference language, even if the common idiom for unpacking
@_
has the effect of making it appear pass-by-value.So I really see no reason you couldn’t make that
However, why would you do it that way? Why not simply provide a constructor API?
my $int = c_int 5
would be the ideal, but I don't think there's a way I cantie
the object within the c_int() constructor and have $int end up tied?Ah yes, that issue again… you’re right.
At least you have the option of
c_int my $int = 5
.