Class methods returning C++ class references are not dealt with correctly?
From reading the list, I've gathered that apparently the best strategy of dealing with references is just to not to use them (convert to
Hi, I'm sorry if my question would appear to be trivial, but what am I supposed to do, if I want to wrap class methods, that return a reference to another class? pointers immediately), because of some scoping rules issues. It works for me for a simple case of POD types, like cdef extern from "test.h": int& foo() cdef int* x = &foo() but in a more complex case, Cython generates incorrect C++ code (first it declares a reference, then assigns to it, which, of course, doesn't even compile): cdef extern from "token.h": cppclass Token: Token(const Datum&) except + cdef extern from "tokenstack.h": cppclass TokenStack: Token& top() except + cdef Token* tok = &self.pEngine.OStack.top() <-> Token *__pyx_v_tok; Token &__pyx_t_5; __pyx_t_5 = __pyx_v_self->pEngine->OStack.top(); __pyx_v_tok = (&__pyx_t_5); I would expect to see this instead: Token *__pyx_v_tok = &__pyx_v_self->pEngine->OStack.top(); Am I doing something wrong? Is there any other way to achieve what I want, other than writing custom C macros? Thanks, -- Sincerely yours, Yury V. Zaytsev
On 28.02.2013 13:58, Yury V. Zaytsev wrote:
Hi,
I'm sorry if my question would appear to be trivial, but what am I supposed to do, if I want to wrap class methods, that return a reference to another class?
From reading the list, I've gathered that apparently the best strategy of dealing with references is just to not to use them (convert to pointers immediately), because of some scoping rules issues.
It works for me for a simple case of POD types, like
cdef extern from "test.h": int& foo()
cdef int* x = &foo()
but in a more complex case, Cython generates incorrect C++ code (first it declares a reference, then assigns to it, which, of course, doesn't even compile):
cdef extern from "token.h": cppclass Token: Token(const Datum&) except +
cdef extern from "tokenstack.h": cppclass TokenStack: Token& top() except +
cdef Token* tok = &self.pEngine.OStack.top()
<->
Token *__pyx_v_tok; Token &__pyx_t_5; __pyx_t_5 = __pyx_v_self->pEngine->OStack.top(); __pyx_v_tok = (&__pyx_t_5);
This is clearly a bug in Cython. The generated code should be: Token *__pyx_v_tok; Token &__pyx_t_5 = __pyx_v_self->pEngine->OStack.top(); __pyx_v_tok = (&__pyx_t_5); One cannot let a C++ reference dangle: Token &__pyx_t_5; // illegal C++ Sturla
On Thu, 2013-02-28 at 15:34 +0100, Sturla Molden wrote:
This is clearly a bug in Cython. One cannot let a C++ reference dangle.
Hi Sturla, Thanks for the confirmation! I had a closer look at it, and I think I know why this happens. My method call is actually wrapped in a try { ... } catch clause, because I declared it as being able to throw exceptions, so the reference can't be defined in this block, or it will not be accessible to the outside world. Apparently, Cython should rather do something like this instead: Token *__pyx_v_tok; Token *__pyx_t_5_p; try { Token &__pyx_t_5 = __pyx_v_self->pEngine->OStack.top(); __pyx_t_5_p = (&__pyx_t_5); } ... __pyx_v_tok = __pyx_t_5_p; I'm sorry, but I don't think that I can personally help fixing this, because even if I manage to come up with a patch to generate declarations inside try blocks with my non-existing knowledge of Cython internals, this simply not gonna work. I believe that some convention should be established regarding references handling, i.e. stating that Cython will generate correct code to convert them to pointers if such and such syntax is used... Hopefully, in the mean time, there is some other solution to the problem that I have overlooked. Z. -- Sincerely yours, Yury V. Zaytsev
On 28.02.2013 15:46, Yury V. Zaytsev wrote:
My method call is actually wrapped in a try { ... } catch clause, because I declared it as being able to throw exceptions, so the reference can't be defined in this block, or it will not be accessible to the outside world.
If Cython generates illegal C++ code (i.e. C++ that don't compile) it is a bug in Cython. There must be a general error in the handling of C++ references when they are declared without a target. Sturla
On Thu, Feb 28, 2013 at 4:58 AM, Yury V. Zaytsev <yury@shurup.com> wrote:
Hi,
I'm sorry if my question would appear to be trivial, but what am I supposed to do, if I want to wrap class methods, that return a reference to another class?
As a workaround you could use: cdef extern from "test.h": int* foo2ptr "&foo" () cdef int *x = foo2ptr() This could be extended to your other example as well. -Brad
Hi Brad, On Thu, 2013-02-28 at 08:01 -0800, Bradley M. Froehle wrote:
cdef extern from "test.h": int* foo2ptr "&foo" ()
cdef int *x = foo2ptr()
Thank you for this interesting suggestion, but I must be missing something, because when I do the following: cdef extern from "tokenstack.h": cppclass TokenStack: Token* top "Token&" () except + cdef Token* tok = self.pEngine.OStack.top() I end up with the following generated code, which, of course, doesn't compile: Token *__pyx_t_5; __pyx_t_5 = __pyx_v_self->pEngine->OStack.Token&(); whereas, I'd like to see generated this: Token *__pyx_t_5; __pyx_t_5 = __pyx_v_self->pEngine->OStack->top(); Any ideas? -- Sincerely yours, Yury V. Zaytsev
Hey Yury: Yes, you are right. I was thinking this was a function and not a method. As an even ickier workaround: #define TokenStack_top_p(token_stack) &token_stack->top() cdef extern from "............": Token* TokenStack_top_p(TokenStack*) except + cdef Token* tok = TokenStack_top_p(self.pEngine.OStack) -Brad On Thu, Feb 28, 2013 at 10:38 AM, Yury V. Zaytsev <yury@shurup.com> wrote:
Hi Brad,
On Thu, 2013-02-28 at 08:01 -0800, Bradley M. Froehle wrote:
cdef extern from "test.h": int* foo2ptr "&foo" ()
cdef int *x = foo2ptr()
Thank you for this interesting suggestion, but I must be missing something, because when I do the following:
cdef extern from "tokenstack.h": cppclass TokenStack: Token* top "Token&" () except +
cdef Token* tok = self.pEngine.OStack.top()
I end up with the following generated code, which, of course, doesn't compile:
Token *__pyx_t_5; __pyx_t_5 = __pyx_v_self->pEngine->OStack.Token&();
whereas, I'd like to see generated this:
Token *__pyx_t_5; __pyx_t_5 = __pyx_v_self->pEngine->OStack->top();
Any ideas?
-- Sincerely yours, Yury V. Zaytsev
_______________________________________________ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
participants (3)
-
Bradley M. Froehle -
Sturla Molden -
Yury V. Zaytsev