Hi,

Am 06/04/2008 09:54 PM schrieb Stefan Behnel:
> Johannes Wienke wrote:
>> Am 06/04/2008 07:47 PM schrieb Stefan Behnel:
>>
>> To my mind only char pointers would need this extra behavior as they
>> have a somewhat special role in C because of the absence a string type.
> 
> Then why None and not ''? And why None and not a ValueError?

Because None has for python the same meaning as NULL in C. ValueError
would be another possibility. Nevertheless if NULL can be a legal value
for the rest of that function, this would be as awkward to handle as the
explicit check for NULL if I only want a safe print statement.

>> None is automatically converted to Python strings, so you can use it in
>> every string or print statement without troubles.
> 
> Not on my side of the cable:
> 
>     Python 2.5.1 (r251:54863, Mar  7 2008, 04:10:12)
>     [GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
>     Type "help", "copyright", "credits" or "license" for more information.
>     >>> "abc" + None
>     Traceback (most recent call last):
>       File "<stdin>", line 1, in <module>
>     TypeError: cannot concatenate 'str' and 'NoneType' objects

Maybe I wasn't precise enough. None can be displayed using str() and can
therefore be used without worries in format strings. Moreover a python
exception is a _much_ better error indicator than a segfault without any
stack trace.

> And the following will still crash, even under your proposal:
> 
>     cdef char* s = NULL
>     py_s = s
>     print PyString_GET_SIZE(py_s)

I've never used the python API, so I have no clue how it is done there.

> And would you also want this to work:
> 
>     cdef char* s = None

For my purpose that's not necessary but maybe someone else will need
this... Well, I don't know if that would be a good idea. Looks strange
to give an explicit C variable an explicit python value. But that's only
what I think at first sight.

>> don't want to waste my time with ugly C memory management stuff.
> 
> This is not about memory management at all. This is about making sure your
> code handles corner cases correctly. Where does the NULL pointer come from
> anyway? Is it maybe an error return of a function that you didn't catch? You
> wouldn't want Cython to find your off-by-one errors also, would you?

If I access memory that is not memory I own or that points to somewhere
undefined this is a kind of memory management, to my mind. Maybe that's
a strong personal bias as my preferred language is Java. But in pure
Python there are also rarely any cases where you have to worry about
directly working on the memory.

Of course I want to check for NULL values and I'm a fan of defensive
programming but life could be much easier if another source for
segfaults is removed. And that's absolutely in the spirit of defensive
programming (have a look at the chapter in Code Complete).

I could understand that this is a bad idea to implement if there are any
other reasons than speed. Is there any semantic problem that could arise
for current code? I can't think of anything.

>>> If you *really* want None, then you can use something like this:
>>>
>>>     cdef inline stringOrNone(char* value):
>>>          if value is NULL: return None
>>>          return value
>> That's exactly what I'm doing now but that's error-prone as you have to
>> do this manually and can forget it.
> 
> Why? Isn't it good practice to guard your code against anticipated invalid
> data? Don't you ask yourself from time to time when you write Python code:
> "can this variable be None?" So why not ask "can this pointer be NULL" in 
> Cython?

Of course this good practice and I totally agree that you have to guard
code from potential error values. But this is some extra work you have
to do as the programmer and programmers make mistakes and forget things
and so on... So it would be really defensive if the language helps
programmers to avoid such bugs. Especially because they result in ugly
segfaults. And as Cython is about annotating python with C features I
would claim that the main thinking is done in python and there it
wouldn't be such a problem to use None.

For example this works like a charm in python and is a typical logger
pattern:

def foo(maybeNone):
    logger.debug("Calling foo, argument: '%s'." % maybeNone)
    # other stuff

> I think it's an advantage that you get a straight crash when your code
> contains the obvious bug that you forgot to test a NULL pointer for a NULL
> value, instead of an automatic coercing to None, which might propagate through
> your application and induce hard to track down bugs elsewhere in your program.
> Usually, C value handling happens within a limited scope (e.g. a function),
> while Python values tend to cross API boundaries into user code.

But what is a straight crash useful for, if it gives you nearly no cue
where the error occurred? A python stack trace is so much more useful,
even if it is much longer. And maybe it's even more robust as the error
may somehow be corrected a few levels above the actually corrupt
function call.


Just as another thought I can give you some background why I have to
constantly log method calls:

For my project I provide an already existing API to old plugins written
in C. So I have simply no control about how they call my API. For some
of these plugins I even don't have the source code. The easiest way to
track the control flow is to log method calls that print out the
arguments the given to the function.

- Johanne

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to