[Cc'ing elsewhere for more feedback. Also top-posting for initial
impressions before the discussion.]

Here's some proposed function pointer syntaxes; which are the most
obvious to understand/read/remember? Can you figure them out?

    cdef float (*F)(float)
    cdef float (*G)(float (*)(float), float, float)
    cdef float ((*H)(char*))(float (*)(float), float, float)

vs

    cdef float -> float F
    cdef (float -> float, float, float) -> float G
    cdef (char*) -> (float -> float, float, float) -> float H

vs

    cdef lambda float: float F
    cdef lambda (lambda float: float), float, float: float G
    cdef lambda (char*): lambda: (lambda float: float), float, float: float H


If you want a hint, the last is something that returns numerical
integration algorithm given a string name. Yes, you could use
typedefs, but you shouldn't have to. especially for the first.


On Thu, Nov 6, 2014 at 9:59 AM, Stefan Behnel <stefan...@behnel.de> wrote:
> Robert Bradshaw schrieb am 06.11.2014 um 18:15:
>> On Thu, Nov 6, 2014 at 12:29 AM, Stefan Behnel wrote:
>>> Robert Bradshaw schrieb am 06.11.2014 um 08:34:
>>>> I'd like to propose a more pythonic way to declare function pointer
>>>> types, namelye
>>>>
>>>>     type0 (*[ident])(type1, type2, type3)
>>>>
>>>> would instead become
>>>>
>>>>     (type1, type2, type3) -> type0 [ident]
>>>
>>> Not convinced. Looks quite magic, very different from the C that people
>>> would know, and takes a while reading from left to right until you see the
>>> "->" which is essentially the only indication of what is happening here.
>>
>> I suppose it depends on whether one knows just C, is familiar with a
>> wide variety of other (more functional) languages. I think it's a lot
>> easier for people to read who only know Python, or just a smattering
>> of C.
>
> The thing is, in order to use Cython, you currently only need to understand
> Python, some C/C++ and a minor bit of special Cython syntax. The more new
> syntax we add outside of Python/C/C++, the higher the entry bar is raised
> for both the "mostly Python" and "I know C" users.

True. However, " -> return_annotation" is still Python syntax.

>>> Also, "->" has a widely known meaning in C/C++ which makes the above very
>>> confusing. I think in C when thinking about function pointers, and there is
>>> no "def ..." keyword indication here that would switch me back to Python
>>> (as for signature annotations).
>>>
>>> I do see the problem of "where did I have to put that '*' again in the C
>>> declaration?", but this looks like it will produce more confusion than it
>>> avoids.
>>
>> Hmm, I hadn't thought of that meaning of ->. I don't think it would be
>> as confusing in context, which will be immediately following cdef or
>> in a function argument, e.g. one would write
>>
>>     cdef (float -> float, float, float) -> float integrator =
>> get_integrator(...)
>
> My brain can't even parse that. Does it join as
>
>     (float -> (float, float, float))
>
> or
>
>     ((float -> float), float, float)
>
> ?

The comma token remains lower precedence than about everything else.
It's just like a parameter list

    cdef integrate(float -> float f, float a, float b):
         ...

f is something that takes floats to floats.

> A ctypedef would definitely help here.
>
>
>> which doesn't to me look like member access, and is much clear than
>>
>>     cdef float (*integrator)(float (*)(float), float, float) =
>> get_integrator(...)
>
> Apart from the (*), at least this makes it clear what gets passed into what.
>
>
>> This becomes especially clear for return types, e.g.
>>
>>     cdef ((float -> float, float, float) -> float)
>> get_integrator(char* algorithm):
>>         if algorithm == ...
>>
>> vs
>>
>>     cdef float (*get_integrator(char* algorithm))(float (*)(float),
>> float, float):
>>         if algorithm == ...
>
> Same thing as above. The nesting is clearer in the latter.

Clearly we think differently... I can pick apart the latter
definition, but I have to admit it took a lot longer to type than the
former, and I still see "cdef float blah(...., float, float): ..."
when in fact I'm declaring something that takes a char* (or should
that read, "takes something that dereferences to a char" :-)).

I am curious, when you read "cdef int * p" do you parse this as "cdef
(int*) p" or "cdef int (*p)" 'cause for me no matter how well I know
it's the latter, I think the former (i.e. I think "I'm declaring a
variable of type p that's of int pointer type.")

>>> Many (or most?) function pointer type declarations will come from some C
>>> library's header file, so it means making it more difficult for users to
>>> copy over the declaration.
>>
>> I really hope, in the long run, people won't have to manually do these
>> declarations.
>
> They'll definitely stay. At least as an advanced feature and for the simple
> (entry) cases, they provide both an easily understandable mapping and a
> handy way to tune the declarations to make their usage friendlier in Cython
> code.

I should have said they'll be less common, at least for the "copy
header file" in which I'd rather point to the header file and list
members to declare. For advance use (e.g. you want to mis-declare
types) we'd still need this.

>> As well as making things easier to read, part of the motivation is to
>> come up with a syntax for declaring this type without having to add
>> the notion of declarators (empty or not) to the grammar. Essentially
>> everyone thinks "cdef type var" even though that's not currently the
>> true grammar.
>
> True. But why not require at least a ctypedef for these things? Ad-hoc
> declaration of C function types is just bound to get in the way of 
> readability.

Not being able to declare this without a ctypedef would be a weakness
in the language, especially as ctypedefs can't be declared locally.
Also, it just defers the ugliness to elsewhere, e.g.

    ctypedef float (*FloatFunc)(float)
    ctypedef float (*IntegrateFunc)(FloatFunc, float, float)

The reason ctypedefs help, and are so commonly used for with function
pointers, is because the existing syntax is just so horrendously bad.
If there's a clear way to declare a function taking a single float and
returning a single float, no typedef needed.

>> Another option that just occurred to me would be the syntax "lambda
>> type1, type2, type3: type0" so for this example one would have
>>
>>     cdef lambda (lambda float: float), float, float: float integrator
>> = get_integrator(...)
>>
>> doesn't read as nice to me, but thought I'd throw it out there.
>
> It's funny that lambda uses the same expression separator as the signature
> annotations in Py3. Hadn't even noticed that before.
>
> Looks a bit funny at first sight, but definitely clearer than any of the 
> above.
>
> Stefan
>
> _______________________________________________
> cython-devel mailing list
> cython-de...@python.org
> https://mail.python.org/mailman/listinfo/cython-devel

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at http://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.

Reply via email to