[Cython] How does a fused function differ from an overloaded function?

mark florisson markflorisson88 at gmail.com
Sun Feb 10 16:11:57 CET 2013


On 9 February 2013 23:56, Stefan Behnel <stefan_ml at behnel.de> wrote:
> mark florisson, 10.02.2013 03:25:
>> On 9 February 2013 03:44, Stefan Behnel <stefan_ml at behnel.de> wrote:
>>> Hi,
>>>
>>> I noticed that Cython currently fails to do this:
>>>
>>>    cdef int (*int_abs)(int x)
>>>    cdef object py_abs
>>>    py_abs = int_abs = abs
>>>
>>> Here, abs() is an overloaded function with a couple of C signatures (fabs()
>>> and friends) and a Python signature (the builtin). While there is code in
>>> NameNode.coerce_to() that figures out that the RHS can be replaced by the
>>> Python builtin, the same is lacking for the general case of overloaded entries.
>>>
>>> While working on fixing this problem (and after turning ProxyNode into an
>>> actual node proxy when it comes to coercion), I thought it would be a good
>>> idea to make NameNode generally aware of alternative entries and just build
>>> a new NameNode with the right entry in its coerce_to() method. Then I
>>> noticed that the generic coerce_to() contains this code:
>>>
>>>     if src_type.is_fused or dst_type.is_fused:
>>>         # See if we are coercing a fused function to a pointer to a
>>>         # specialized function
>>>         if (src_type.is_cfunction and not dst_type.is_fused and
>>>                 dst_type.is_ptr and dst_type.base_type.is_cfunction):
>>>
>>>             dst_type = dst_type.base_type
>>>             for signature in src_type.get_all_specialized_function_types():
>>>                 if signature.same_as(dst_type):
>>>                     src.type = signature
>>>                     src.entry = src.type.entry
>>>                     src.entry.used = True
>>>                     return self
>>>
>>> This is essentially the same idea, just done a bit differently (with the
>>> drawback that it modifies the node in place, which coerce_to() must *never*
>>> do).
>>>
>>> So, two questions:
>>>
>>> 1) why is the above code in the generic coerce_to() method and not in
>>> NameNode? It doesn't seem to do anything sensible for most other nodes,
>>> potentially not even AttributeNode. And it might fail silently when working
>>> on things like CloneNode that don't care about entries. Are there other
>>> nodes where it does what it should?
>>
>> I think it works for names and attributes, it allows you to retrieve a
>> specialized version of the fused c(p)def functions and methods.
>
> That's what I figured. I might have to take a look at AttributeNode a bit
> more to see if it really does the right thing in all cases.
>
> I would like to avoid having this in the generic coerce_to() method because
> if it's anything but a NameNode or AttributeNode, it can only have one type
> (unless I'm missing something), so coercion to different signatures won't
> be possible anyway. And I wouldn't mind letting the above two nodes share a
> bit more code, in one way or another.
>
> I also think that the idea of having a ProxyNode for reuse was quite right.
> I've started playing with it a little to let it support coercion
> delegation, i.e. it would have it's own coerce_to() method that builds
> CloneNodes at need and coerces either directly its argument or the
> CloneNode to the target type, depending on is_simple() and maybe other
> criteria.
>
>
>>> 2) couldn't fused functions be mapped to a set of overloaded functions
>>> (read: entries) before hand, instead of special casing both in places like
>>> this?
>>
>> Quite possibly, although I'd have to dig in the codebase some more to
>> verify that. You can give it a try, it'd be nice to unify the
>> approaches under the same model.
>
> What I would like to see, eventually, is that NameNode basically just looks
> up its entry on type analysis (including all overloaded entries), and then
> whatever uses the node (to call or assign it) would pass in the right
> signature/type into its coerce_to() method, which would then select the
> right entry and return a new NameNode for it (or fail if the signature
> can't be matched to any entry).
>
> AttributeNode would essentially do the same thing, just return either an
> AttributeNode or a NameNode on type analysis and/or coercion, depending on
> what entry it finds (and if more than one).
>
> Does this sound like it could work for fused types?

It sounds this approach might be cleaner than catching this in a
global coercion, but on the other hand you want full generality. For
instance, there is also the cast syntax that can specialize a
function. Or I might have a pointer to a known fused function or
method, that I want to deference and specialize.

Maybe we need a nicer way to deal with and register coercions, and
with what an assignment expects and a value generates. A lot of
assignment code seems similar but slightly different in tricky ways.

> Stefan
>
> _______________________________________________
> cython-devel mailing list
> cython-devel at python.org
> http://mail.python.org/mailman/listinfo/cython-devel


More information about the cython-devel mailing list