[Pyrex] Why were .pxd files invented?

Leif Strand leif at geodynamics.org
Sat Mar 31 00:25:57 UTC 2007


Hi,

I've been working with Pyrex for some time now (even hacking the Pyrex 
source), but only just yesterday starting using .pxd files in a big way: 
to share extension types between modules -- as documented here:

"Sharing Extension Types"
http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/version/Doc/sharing.html#SharingExtensionTypes

Already, I'm annoyed by .pxd files :-) First, I noticed a lot of 
redundancy between my .pxd files and my .pyx files (I'm defining many 
cdef functions). Then the thought occurred to me: "these .pxd files 
could be generated from the corresponding .pyx files". Then my next 
thought was, "Why generate anything? Pyrex's 'cimport' statement should 
read the .pyx files directly."

I can't figure out why .pxd files were invented. They obviously mimic 
the old C convention of splitting code into interface and implementation 
parts (.h and .c files). But C only does it that way for historical 
reasons: the preprocessor is completely disconnected from the compiler 
(and therefore the language). The preprocessor completely flattens 
whatever structure was defined by the #include directives, handing the 
result to the compiler as one big blob. So the C compiler has absolutely 
no context to work with; if it sees

   void foo() { ... }

it must assume it is a definition of 'foo', and therefore generate code 
for it.

But Pyrex has no historical baggage. So when it sees

    cimport Shrubbing

why not search for the Shrubbing.pyx file, parse it, and process it in 
"cimport mode" or "cimport context", in which it filters-out 
declarations that aren't relevant in that context? For example:

#--snip--

cdef class Shrubbery:

    cdef int width
    cdef int length

    def __new__(self, int w, int l):
        self.width = w
        self.length = l

    def trim(self):
        self.width = self.width - 1

    cdef void water(self):
        self.width = self.width + 1

#--snip--

In the context of a 'cimport' statement, Pyrex could ignore the 'def' 
methods and simply pick-out the 'cdef' attributes and methods that would 
be ordinarily placed in a .pxd file: 'width', 'length', and 'water'.

C/C++ programmers are bound to object that combining interface and 
implementation is bad. But the right way to do this is to introduce 
"interface" and "implementation" concepts into the language itself 
(defined in a single file, like Pascal units) -- not force the 
programmer to maintain two separate files. In any case, .pxd files 
weren't designed to give you an interface/implementation concept to 
begin with: all 'cdef' stuff is public (cdef declarations must appear in 
the "interface"), you can't have "private" cdef attributes or methods. 
(So perhaps I'm confusing the issue by even bringing it up.)

I always hated keeping my .h files in-sync when working in C/C++; I hate 
to see that old crufty way of doing things jump the gap into a fresh, 
new language like Pyrex...

--Leif




More information about the Pyrex mailing list