Ok, been thinking some more. To sum up, what we're after is some way of
having the following work (A is a class with a value field, printme is a
method somehow selected for inlining and optimization for Cython):
cdef A a = get_a()
a.printme()
a.printme()
turns into
cdef A a = get_a()
print a.value
print a.value
, while this:
cdef A(value=23) a = get_a()
a.printme()
a.printme()
would be turned into
cdef A a = get_a()
if a.value != 23: raise TypeError(...) # line (a)
print 23 # line (b)
print 23
(This is the final result, not saying it is a recipe for how it happens
magically).
So, what is happening is that we want to set up some assumptions about
an object (without actually changing the object); and have the code
after generated by making use of those assumptions.
I have some seperate proposals building further on Robert's ideas here.
1) An explicit method for the assumptions bit. I.e:
cdef class A:
cdef int value
cdef __assume__(self, int value):
if self.value != value: raise AssumptionError(...)
The argument list to this function is basically a more explicit
declaration of type arguments. The reason I want this, so explicitly
(rather than using a more general __coerce__ which must probably also be
added) is that it hints strongly to the writer of the class A to treat
self.value as "const". Once an assumption is made by having __assume__
called, you cannot "back out" and change self.value. This seem to make
it explicit that value should be treated as a const after construction;
and it leaves the contract for the name, number and types of "type
arguments" on the class creator side rather than the caller side.
In addition to just checking assumptions, this method can also put
general constraints on the arguments (i.e., "if value < 0: raise
ValueError(...)").
Important: This does *not* address how one can make optimizations later
on, line (b), it is simply a way to insert the assumption line, line
(a). Also, __assume__ can simply be called in the normal way.
2) With this in place, it seems ok to follow Robert's proposal and
automatically treat fields having the same name as type arguments as
known compile-time. The parameter list to __assume__ restricts which
fields can be used.
I am still thinking about something more explicit like
cdef class A:
cdef int value
cdef int not_possible_typearg
__typearguments__ = ["value", "compiletimeonlyarg"]
but it doesn't seem strictly necesarry as the argument list to
__assume__ can serve the same role; and in a possibly more dynamic way, ie
cdef A(constant_alpha=True, alpha=4) a = x # ok
print a.alpha # ok to optimize...
cdef A(constant_alpha=False, alpha=4) a = x # __assume__ might raise...
# .. run-time error because of invalid combination,
# .. so code below will never run, which is lucky because
# .. alpha is now for some reason changing constantly.
print a.alpha # Will be optimized but never run
3) I still want to throw __init__ into the mix. The main reason: For
type inference, it would be nice if
A = ndarray(shape=(4, 4), dtype=float64, buffer=arr)
would automatically (because type arguments are somehow interlinked with
constructor arguments) be type-inferred to
cdef ndarray(shape=(4,4), dtype=float64) A
A = ndarray(shape=(4,4), dtype=float64, buffer=arr)
If so, keeping () for the type argument syntax would also make more
sense and be less confusing.
Perhaps all that is needed is this rule at the type-inference stage:
* A call to a known constructor (of a type which is a candidate for
typing) obviously leads to typing it explicitly
* At the same time, any arguments passed to the constructor is checked
for a match with the __assume__ signature -- the arguments that
__assume__ can take are then put into the type arguments list.
(If so, we can pretty much ignore this for now, but we have a "defense"
for using the () syntax.)
Dag Sverre
--
Dag Sverre
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev