Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The Samurai Principle

3 views
Skip to first unread message

Phlip

unread,
Sep 6, 2010, 11:48:08 PM9/6/10
to
Pythonistas:

The "Samurai Principle" says to return victorious, or not at all. This
is why django.db wisely throws an exception, instead of simply
returning None, if it encounters a "record not found".

I illustrated the value of that concept, here:

http://c2.com/cgi/wiki?SamuraiPrinciple

Albert Hopkins

unread,
Sep 7, 2010, 7:14:00 AM9/7/10
to pytho...@python.org
On Mon, 2010-09-06 at 20:48 -0700, Phlip wrote:
> Pythonistas:
>
> The "Samurai Principle" says to return victorious, or not at all. This
> is why django.db wisely throws an exception, instead of simply
> returning None, if it encounters a "record not found".

How does that compare to, say, the "Kamikaze Principle"? ;)

-a


Phlip

unread,
Sep 7, 2010, 9:40:16 AM9/7/10
to
> How does that compare to, say, the "Kamikaze Principle"? ;)

Return victorious AND not at all!

(All return values are packed up and thrown...;)

Bruno Desthuilliers

unread,
Sep 7, 2010, 9:56:42 AM9/7/10
to
Phlip a écrit :

>> How does that compare to, say, the "Kamikaze Principle"? ;)
>
> Return victorious AND not at all!
>
> (All return values are packed up and thrown...;)

... and then it raises a SystemError !-)

geremy condra

unread,
Sep 7, 2010, 10:23:04 AM9/7/10
to pytho...@python.org

general protection fault

Geremy Condra

Phlip

unread,
Sep 7, 2010, 12:02:49 PM9/7/10
to
Back to the topic, I tend to do this:

for record in Model.objects.filter(pk=42):
return record

return sentinel

Having lots of short methods helps, because return provides both
control-flow and a result value. But it abuses 'for' to mean 'if'. I
feel _reeeeally_ guilty about that!

But I miss this, from (cough) RoR:

record = Model.find(42) || sentinel

Django should provide this:

record = Model.objects.get(pk=42, _if_does_not_exist=sentinel)

sentinel could be a lambda that concocts a new record (where such a
record should not be created with get_or_create()). That would be
efficient when you don't spend time constructing it just so the happy-
path of .get() can throw it away.

Or sentinel could be None, or a NullObject that efficiently behaves
like a record but provides stubbed-out behaviors.

My committees will be submitting these proposals to the Django
committees shortly... C-:

--
Phlip

Bruno Desthuilliers

unread,
Sep 7, 2010, 1:12:02 PM9/7/10
to
Phlip a écrit :

> Back to the topic, I tend to do this:
>
> for record in Model.objects.filter(pk=42):
> return record
>
> return sentinel

WTF alert here...

> Having lots of short methods helps, because return provides both
> control-flow and a result value. But it abuses 'for' to mean 'if'. I
> feel _reeeeally_ guilty about that!

> But I miss this, from (cough) RoR:
>
> record = Model.find(42) || sentinel
>
> Django should provide this:
>
> record = Model.objects.get(pk=42, _if_does_not_exist=sentinel)

queryset.get can be used with multiple conditions - it's not necessarily
restricted to pk lookups. However you name your "_if_does_not_exist"
kwarg, it will be difficult to garantee that there will never be no
nameclash with any possible valid model lookup argument...

But if you feel like you found the correct name, you can of course
monkeypatch queryset !-)

Phlip

unread,
Sep 7, 2010, 1:20:35 PM9/7/10
to
On Sep 7, 10:12 am, Bruno Desthuilliers <bruno.

42.desthuilli...@websiteburo.invalid> wrote:
> Phlip a écrit :
>
> > Back to the topic, I tend to do this:
>
> >   for record in Model.objects.filter(pk=42):
> >      return record
>
> >   return sentinel
>
> WTF alert here...

I don't see how anyone could WTF that. Are you pretending to be a newb
who doesn't understanding it? F'em.

> > Having lots of short methods helps, because return provides both
> > control-flow and a result value. But it abuses 'for' to mean 'if'. I
> > feel _reeeeally_ guilty about that!
> > But I miss this, from (cough) RoR:
>
> >   record = Model.find(42) || sentinel
>
> > Django should provide this:
>
> >   record = Model.objects.get(pk=42, _if_does_not_exist=sentinel)
>
> queryset.get can be used with multiple conditions - it's not necessarily
>   restricted to pk lookups. However you name your "_if_does_not_exist"
> kwarg, it will be difficult to garantee that there will never be no
> nameclash with any possible valid model lookup argument...

it can also be another method - .if_does_not_exist(sentinel). With a
less sucky name.

I would guess that Django provides some basic rules for avoiding name
collisions. Nobody should call a field "pk__in", but if they do, they
are screwed! But that's not important right now.

> But if you feel like you found the correct name, you can of course
> monkeypatch queryset !-)

K now I gotta learn to add a new method to an existing class!

Ian Kelly

unread,
Sep 7, 2010, 1:36:29 PM9/7/10
to Python
On Tue, Sep 7, 2010 at 10:02 AM, Phlip <phli...@gmail.com> wrote:
> Back to the topic, I tend to do this:
>
>  for record in Model.objects.filter(pk=42):
>     return record
>
>  return sentinel

How is that any better than just catching the exception?

try:
return Model.objects.get(pk=42)
except Model.DoesNotExist:
return sentinel

The flow of control is much clearer this way.

Cheers,
Ian

Phlip

unread,
Sep 7, 2010, 1:52:44 PM9/7/10
to
On Sep 7, 10:36 am, Ian Kelly <ian.g.ke...@gmail.com> wrote:

> On Tue, Sep 7, 2010 at 10:02 AM, Phlip <phlip2...@gmail.com> wrote:
> > Back to the topic, I tend to do this:
>
> >  for record in Model.objects.filter(pk=42):
> >     return record
>
> >  return sentinel
>
> How is that any better than just catching the exception?
>
> try:
>     return Model.objects.get(pk=42)
> except Model.DoesNotExist:
>     return sentinel
>
> The flow of control is much clearer this way.

It reminds me of Visual Basic.

And no it's not "much clearer". Exceptions are for catastrophic errors
that the caller should care not to handle. A "record not found" is not
a catastrophe. Read my original post.

AAAND you need to test that the DoesNotExist occurs for the exact
reason you expect. Your except is not complete. Making it complete is
very hard, and will break as soon as the model changes.

Ian Kelly

unread,
Sep 7, 2010, 2:21:16 PM9/7/10
to Python
On Tue, Sep 7, 2010 at 11:52 AM, Phlip <phli...@gmail.com> wrote:
> And no it's not "much clearer".

It's clearer because it does exactly what it says it does, unlike your
approach that masquerades as a loop.

> Exceptions are for catastrophic errors

No, they're for flagging "exceptional" states. /Errors/ are for
catastrophic errors. The fact that errors are a subset of exceptions
is just for convenience in handling.

> AAAND you need to test that the DoesNotExist occurs for the exact
> reason you expect.

I'm not following you here. The only possible reason the exception
can occur is if no matching row exists. If there were some other
reason for raising an exception, then a different exception would be
raised.

> Your except is not complete. Making it complete is
> very hard, and will break as soon as the model changes.

Still not following you. What is it missing, and how will it break?

Tim Chase

unread,
Sep 7, 2010, 2:36:08 PM9/7/10
to Phlip, pytho...@python.org
On 09/07/10 12:52, Phlip wrote:
>> try:
>> return Model.objects.get(pk=42)
>> except Model.DoesNotExist:
>> return sentinel
>>
>> The flow of control is much clearer this way.
>
> It reminds me of Visual Basic.
>
> And no it's not "much clearer". Exceptions are for catastrophic errors
> that the caller should care not to handle. A "record not found" is not
> a catastrophe.

Exceptions are not limited to catastrophic errors, simply
exceptional (not the common) cases. E.g. iterators raising
StopException when exhausted.

>>> i = iter(range(2))
>>> i.next()
0
>>> i.next()
1
>>> i.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

>>> i = iter(range(2))
>>> for v in i:
... print v
...
0
1

Running out of things to iterate over is pretty non-catastrophic
in my book. :)

Using exceptions as in the grandparent's post seem perfectly fine
to me. The other option would be to LBYL:

items = list(MyModel.objects.filter(...))
if len(items) == 1:
do_something(items[0])
else:
what_the(...)

-tkc


Phlip

unread,
Sep 7, 2010, 2:53:37 PM9/7/10
to
On Sep 7, 11:36 am, Tim Chase <python.l...@tim.thechases.com> wrote:

> > And no it's not "much clearer". Exceptions are for catastrophic errors
> > that the caller should care not to handle. A "record not found" is not
> > a catastrophe.
>
> Exceptions are not limited to catastrophic errors, simply
> exceptional (not the common) cases.  E.g. iterators raising
> StopException when exhausted.

Exceptions are not "because we should only return one type of thing".
They are for situations which the caller should care not to handle.
Exceptions are for propagating. A "record not found" is an exemplary
example of a situation the caller _should_ handle.

>    items = list(MyModel.objects.filter(...))
>    if len(items) == 1:
>      do_something(items[0])
>    else:
>      what_the(...)

Both your version and mine read an entire cursor. But mine only rezzed
the first object, whereas yours rezzed every object in the cursor,
just to throw most of them away!

Tim Chase

unread,
Sep 7, 2010, 3:45:04 PM9/7/10
to Phlip, pytho...@python.org
On 09/07/10 13:53, Phlip wrote:
> On Sep 7, 11:36 am, Tim Chase<python.l...@tim.thechases.com> wrote:
>
>>> And no it's not "much clearer". Exceptions are for catastrophic errors
>>> that the caller should care not to handle. A "record not found" is not
>>> a catastrophe.
>>
>> Exceptions are not limited to catastrophic errors, simply
>> exceptional (not the common) cases. E.g. iterators raising
>> StopException when exhausted.
>
> Exceptions are not "because we should only return one type of thing".
> They are for situations which the caller should care not to handle.
> Exceptions are for propagating. A "record not found" is an exemplary
> example of a situation the caller _should_ handle.

Um...first you state "Exceptions are for catastrophic errors that
the caller should not care to handle. A 'record not found' is not
a catastrophe" and then you contradictingly go on to state "A

'record not found' is an exemplary example of a situation the

caller _should_ handle". I'm not sure I follow your logic here.
Exceptions allow both (1) the ability to handle the exceptional
condition locally if you want to (including suppressing it) and
(2) propagate the exception if you want to make the caller handle it.

And if you really want, you can just subclass QuerySet to provide
your own get_or_none() method to return your sentinel.

>> items = list(MyModel.objects.filter(...))
>> if len(items) == 1:
>> do_something(items[0])
>> else:
>> what_the(...)
>
> Both your version and mine read an entire cursor. But mine only rezzed
> the first object, whereas yours rezzed every object in the cursor,
> just to throw most of them away!

If a .get() returns more than one object (non-unique criteria are
used), what _should_ it return? Agreed, if it pulls back a
bajillion records, that's bad, so if you're concerned your
conditions might do that despite the expectation they bring back
1-and-only-1 (.get() currently raises an exception if it brings
back more than one result db/models/query.py around line 342
where MultipleObjectsReturned is raised), then I'd just slice them:

items = list(MyModel.objects.filter(...)[:1])
if items:


do_something(items[0])
else:
what_the(...)

-tkc

Bruno Desthuilliers

unread,
Sep 7, 2010, 4:06:37 PM9/7/10
to
Phlip a écrit :

> On Sep 7, 10:12 am, Bruno Desthuilliers <bruno.
> 42.desthuilli...@websiteburo.invalid> wrote:
>> Phlip a écrit :
>>
>>> Back to the topic, I tend to do this:
>>> for record in Model.objects.filter(pk=42):
>>> return record
>>> return sentinel
>> WTF alert here...
>
> I don't see how anyone could WTF that. Are you pretending to be a newb
> who doesn't understanding it? F'em.

F'... newbies is definitly not the pythonic mindset. Python's mindset is
about doing the most obvious thing, no trying to be smart. The obvious
code here is:

try:
return Model.objects.get(pk=42)
except Model.DoesNotExist:
return sentinel

so yes, your above snippet is bordering on WTF since it's not immediatly
obvious - it takes at least one more second for me to parse, and I'm
definitly not a Python nor Django newbie. That's something I'd
immediatly rewrite if I had to work on this code.

> I would guess that Django provides some basic rules for avoiding name
> collisions.

yes : common sense.

> Nobody should call a field "pk__in"

Nope, but "default" - which would be the obvious keyword here - is also
a perfectly legitimate field name.

>> But if you feel like you found the correct name, you can of course
>> monkeypatch queryset !-)
>

> Know I gotta learn to add a new method to an existing class!

It's as straightforward as possible once you know Python's object model:

def somefunc(self, whatever):
self.do_something_with(whatever)

import somemodule
somemodule.SomeClass.mymethod = somefunc

Bruno Desthuilliers

unread,
Sep 7, 2010, 4:15:42 PM9/7/10
to
Phlip a écrit :

> On Sep 7, 10:36 am, Ian Kelly <ian.g.ke...@gmail.com> wrote:
>> On Tue, Sep 7, 2010 at 10:02 AM, Phlip <phlip2...@gmail.com> wrote:
>>> Back to the topic, I tend to do this:
>>> for record in Model.objects.filter(pk=42):
>>> return record
>>> return sentinel
>> How is that any better than just catching the exception?
>>
>> try:
>> return Model.objects.get(pk=42)
>> except Model.DoesNotExist:
>> return sentinel
>>
>> The flow of control is much clearer this way.
>
> It reminds me of Visual Basic.

Strange enough, your own code snippet reminds me of what I used to find
when fixing VB programs some ten years ago.

> And no it's not "much clearer".

It is for any Python programmer - it's even TheOneObviousWay.

> Exceptions are for catastrophic errors

Chapter and verse, please ?

Exceptions are for exceptional situations. When you call queryset.get,
you do expect to have one single instance matching the lookup - specialy
when doing a pk lookup.


> AAAND you need to test that the DoesNotExist occurs for the exact
> reason you expect.

Bullshit. The only reason you'd get this exception is because there's no
record matching your where clause.

> Your except is not complete.

Why so ?

> Making it complete is
> very hard, and will break as soon as the model changes.

Why so ?

Phlip

unread,
Sep 7, 2010, 6:20:27 PM9/7/10
to
On Sep 7, 1:06 pm, Bruno Desthuilliers
<bdesth.quelquech...@free.quelquepart.fr> wrote:

> try:
>    return Model.objects.get(pk=42)
> except Model.DoesNotExist:
>    return sentinel

Visual Basic Classic had a Collection Class, which worked essentially
like a real language's Hash, Map, or Dict.

Except - it had no operation to test membership. It also could not
enumerate by key and value (which would be 'for k,v in dict.items()').
To test for membership, you _had_ to catch an exception - using VB's
tragically clumsy exception model.

Hours of fun. That leads us to this topic:

http://www.google.com/search?q=don't+use+exceptions+for+normal+control+flow

Benjamin Kaplan

unread,
Sep 7, 2010, 7:38:13 PM9/7/10
to pytho...@python.org
> --


An experienced C programmer can program C in any language, but that
doesn't mean it's a good idea to.

When you're using a language, you should use the style that the
language emphasizes. While you shouldn't use exceptions for control
flow in C++, Java, or C#, there's nothing wrong with using them as
such in Python.

Message has been deleted

Lawrence D'Oliveiro

unread,
Sep 7, 2010, 9:23:22 PM9/7/10
to
In message
<74587da9-8861-4400...@l38g2000pro.googlegroups.com>, Phlip
wrote:

> Pythonistas:
>
> The "Samurai Principle" says to return victorious, or not at all. This
> is why django.db wisely throws an exception, instead of simply
> returning None, if it encounters a "record not found".

Does catching the exception not defeat the “Samurai Principle”?

Gregory Ewing

unread,
Sep 7, 2010, 11:31:11 PM9/7/10
to
Lawrence D'Oliveiro wrote:

> Does catching the exception not defeat the “Samurai Principle”?

Not if it lets you turn defeat into victory. Or
redefine victory so that it includes defeat.
Or something.

--
Greg

Phlip

unread,
Sep 7, 2010, 11:35:45 PM9/7/10
to
On Sep 7, 6:23 pm, Lawrence D'Oliveiro <l...@geek-
central.gen.new_zealand> wrote:

> Does catching the exception not defeat the “Samurai Principle”?

Read my comic:

http://c2.com/cgi/wiki?SamuraiPrinciple

Exceptions are very dangerous by themselves, because if you don't trap
them just right they can cause side-effects. They are worse than GOTO.

Phlip

unread,
Sep 7, 2010, 11:38:14 PM9/7/10
to
On Sep 7, 5:51 pm, Terry Reedy <tjre...@udel.edu> wrote:

> On 9/7/2010 2:53 PM, Phlip wrote:
>
> > They are for situations which the caller should care not to handle.
>
> Python is simply not designed that way. Exception raising and catching
> is a common flow-control method in Python. If you cannot stand that,
> Python is not for you.

While I'm at it, I'm going to log into comp.lang.java.misc and explain
to everyone why static typing is overkill, and implementation
inheritance is good for you.

Everyone gets defensive about the design flaws in their own language.
But the django.db situation is not even a design flaw; just a
misinterpretation of the Samurai Principle. int('yo') shall throw an
exception, but a missing record could be the result you were looking
for, so it's not exceptional.

Phlip

unread,
Sep 7, 2010, 11:44:14 PM9/7/10
to
On Sep 7, 4:38 pm, Benjamin Kaplan <benjamin.kap...@case.edu> wrote:

> When you're using a language, you should use the style that the
> language emphasizes.

You mean like this?

uri = reverse('my_uri_name', kwargs=dict(pk=record.pk))

That 'kwargs' there is ... a lapse of judgement. It is exposing a
technical detail (the "keyword arguments") instead of naming the
variable after its intent. It should be 'params=', at least, to match
the URI standards.

I'm just sayin'...

Ben Finney

unread,
Sep 8, 2010, 12:08:04 AM9/8/10
to
Phlip <phli...@gmail.com> writes:

> On Sep 7, 4:38 pm, Benjamin Kaplan <benjamin.kap...@case.edu> wrote:
>
> > When you're using a language, you should use the style that the
> > language emphasizes.
>
> You mean like this?
>
> uri = reverse('my_uri_name', kwargs=dict(pk=record.pk))

Do you think that style is emphasised by Python? What gives you that
impression?

--
\ “Program testing can be a very effective way to show the |
`\ presence of bugs, but is hopelessly inadequate for showing |
_o__) their absence.” —Edsger W. Dijkstra |
Ben Finney

Ian Kelly

unread,
Sep 8, 2010, 2:32:48 AM9/8/10
to Python
On Tue, Sep 7, 2010 at 9:35 PM, Phlip <phli...@gmail.com> wrote:
> Exceptions are very dangerous by themselves, because if you don't trap
> them just right they can cause side-effects.

And returning None on failure is dangerous, because if the programmer
does not take care to handle that case, the program may attempt to
regard it as actual data. This in turn results in hard-to-track bugs
elsewhere in the program, a fate much worse than an unhandled
exception. It's better to fail noisily than to fail silently.

> They are worse than GOTO.

This assertion is questionable at best. Exceptions are structured;
goto is unstructured, giving you much more rope to hang yourself with.

Ian Kelly

unread,
Sep 8, 2010, 2:57:52 AM9/8/10
to Python
On Tue, Sep 7, 2010 at 9:38 PM, Phlip <phli...@gmail.com> wrote:
> Everyone gets defensive about the design flaws in their own language.
> But the django.db situation is not even a design flaw; just a
> misinterpretation of the Samurai Principle. int('yo') shall throw an
> exception, but a missing record could be the result you were looking
> for, so it's not exceptional.

I consider it exceptional because it breaks the rule that
Model.objects.get(...) returns an instance of Model. If it can also
return None, then this needs to be checked for every time the method
is called, because None does not implement the Model interface and
will break if you try to use it like that. You're still doing
exception handling; you're just doing it with an if instead of a
try-except. I prefer to do exception handling in a block clearly
marked as an exception handler.

Out of curiosity, would you also regard the case where two matching
records are found instead of one as not exceptional? After all, it
could be the result you were looking for. What should QuerySet.get
return in that case, if it doesn't raise an exception?

Steven D'Aprano

unread,
Sep 8, 2010, 10:21:11 AM9/8/10
to
On Tue, 07 Sep 2010 20:35:45 -0700, Phlip wrote:

> Exceptions are very dangerous by themselves, because if you don't trap
> them just right they can cause side-effects.

Huh?

If you don't trap them just right, the cause a stack trace, which is a
side-effect I suppose. But it's an *intended* side-effect, since the
alternative would be a core dump (or worse, an incorrect program that
*doesn't* crash). This is a good thing!


--
Steven

Steven D'Aprano

unread,
Sep 8, 2010, 10:26:34 AM9/8/10
to

I think you've misunderstood the meaning of "exception" if you think
that. It doesn't mean "error". Nor does it mean "rare". (Although, given
that exceptions in Python are expensive, one would hope they're not *too*
common.)

The unexceptional case of looking up a record is to find it. That, after
all, is the purpose of the lookup function -- to find the given record.
That's what it is designed to do, and anything else is considered
exceptional.

Whether the lookup function returns a special "not found" result, or
raises an exception, or sets some magic global error code somewhere, it's
still an exceptional case.


--
Steven

Grant Edwards

unread,
Sep 8, 2010, 10:44:12 AM9/8/10
to
On 2010-09-08, Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> wrote:
> On Tue, 07 Sep 2010 20:35:45 -0700, Phlip wrote:
>
>> Exceptions are very dangerous by themselves, because if you don't trap
>> them just right they can cause side-effects.
>
> Huh?
>
> If you don't trap them just right, they cause a stack trace,

Not always. That is the effect of not trapping them at all.
However, you can trap them incorrectly -- which can result in
hard-to-track down problems.

The main example of this is a "bare except" clause that not only
catches and handles the "expected" exception but also catches (and
mishandles/ignores) an unexpected one.

> which is a side-effect I suppose. But it's an *intended* side-effect,
> since the alternative would be a core dump (or worse, an incorrect
> program that *doesn't* crash). This is a good thing!

--
Grant Edwards grant.b.edwards Yow! -- I have seen the
at FUN --
gmail.com

Steven D'Aprano

unread,
Sep 8, 2010, 11:13:25 AM9/8/10
to
On Wed, 08 Sep 2010 14:44:12 +0000, Grant Edwards wrote:

> On 2010-09-08, Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au>
> wrote:
>> On Tue, 07 Sep 2010 20:35:45 -0700, Phlip wrote:
>>
>>> Exceptions are very dangerous by themselves, because if you don't trap
>>> them just right they can cause side-effects.
>>
>> Huh?
>>
>> If you don't trap them just right, they cause a stack trace,
>
> Not always. That is the effect of not trapping them at all. However,
> you can trap them incorrectly -- which can result in hard-to-track down
> problems.
>
> The main example of this is a "bare except" clause that not only catches
> and handles the "expected" exception but also catches (and
> mishandles/ignores) an unexpected one.

Ah, fair enough. That would be a false positive error -- catching too
much rather than too little.

Still, that's no better, or worse, than misinterpreting special error
codes that are returned by functions. The main error mode there is
catching too little -- people neglect to check the error code, and
therefore have buggy code:

p = some_string.find('#')
print some_string[:p]

And who hasn't done this more than once?

re.search(pattern, some_string).group()

--
Steven

Grant Edwards

unread,
Sep 8, 2010, 1:44:01 PM9/8/10
to
On 2010-09-08, Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> wrote:
> On Wed, 08 Sep 2010 14:44:12 +0000, Grant Edwards wrote:
>>
>>> If you don't trap them just right, they cause a stack trace,
>>
>> Not always. That is the effect of not trapping them at all. However,
>> you can trap them incorrectly -- which can result in hard-to-track down
>> problems.
>>
>> The main example of this is a "bare except" clause that not only catches
>> and handles the "expected" exception but also catches (and
>> mishandles/ignores) an unexpected one.
>
> Ah, fair enough. That would be a false positive error -- catching too
> much rather than too little.
>
> Still, that's no better, or worse, than misinterpreting special error
> codes that are returned by functions.

No, I didn't mean to imply that was the case. I agree with your
conclusion. I find it much easier to screw things up using the
"exceptional return value" method than the "exception raise" method.

--
Grant Edwards grant.b.edwards Yow! Psychoanalysis??
at I thought this was a nude
gmail.com rap session!!!

Paul Rubin

unread,
Sep 8, 2010, 6:52:47 PM9/8/10
to
Grant Edwards <inv...@invalid.invalid> writes:
> I find it much easier to screw things up using the
> "exceptional return value" method than the "exception raise" method.

That may be partly due to Python's not-so-good facilities for
implementing the "exceptional return value" method. To be fair, plenty
of other languages have similar shortcomings and it's mostly in more
recent languages that the problem has really been recognized, and
addressed with features like option types.

Lawrence D'Oliveiro

unread,
Sep 10, 2010, 6:17:21 PM9/10/10
to
In message <mailman.567.12839275...@python.org>, Ian Kelly
wrote:

> And returning None on failure is dangerous, because if the programmer
> does not take care to handle that case, the program may attempt to
> regard it as actual data.

But None *is* actual data.

Robert Kern

unread,
Sep 10, 2010, 6:38:45 PM9/10/10
to pytho...@python.org

And that is exactly the reason why the Samurai Principle says to not return None
when the function fails to do what it intended to do.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Steven D'Aprano

unread,
Sep 10, 2010, 8:16:08 PM9/10/10
to

Of course it is. Which makes it hard to distinguish None used as data
from None used as a signal for an exceptional case.

--
Steven

Lawrence D'Oliveiro

unread,
Sep 11, 2010, 8:08:26 PM9/11/10
to
In message <mailman.654.12841583...@python.org>, Robert
Kern wrote:

> On 9/10/10 5:17 PM, Lawrence D'Oliveiro wrote:
>
>> In message<mailman.567.12839275...@python.org>, Ian
>> Kelly wrote:
>>
>>> And returning None on failure is dangerous, because if the programmer
>>> does not take care to handle that case, the program may attempt to
>>> regard it as actual data.
>>
>> But None *is* actual data.
>
> And that is exactly the reason why the Samurai Principle says to not
> return None when the function fails to do what it intended to do.

How can the function “fail” when it returns what it is specified to return?

Robert Kern

unread,
Sep 12, 2010, 1:20:46 AM9/12/10
to pytho...@python.org
On 9/11/10 7:08 PM, Lawrence D'Oliveiro wrote:
> In message<mailman.654.12841583...@python.org>, Robert

The Samurai Principle is about what specifications and guarantees a programmer
should make about his functions. It gives advice for programmers on how to
specify their functions in the face of failure conditions the function itself
sees. For example, a function that is supposed to fetch a record from a database
given a key, a failure condition would be that the key does not exist in the
database. Or the connection times out, or anything else that prevents the
function from retrieving a correct record for the key. The Principle says that a
programmer should specify his function such that it raises an exception to
signify this failure rather than to return None.

Of course, a programmer may make his functions' contracts as loose as he
pleases, and thus returning None may be "correct" in the sense that it satisfies
those contracts. The Principle simply advises that making such contracts is not
a good idea.

Steven D'Aprano

unread,
Sep 12, 2010, 3:55:01 AM9/12/10
to
On Sun, 12 Sep 2010 12:08:26 +1200, Lawrence D'Oliveiro wrote:

>> And that is exactly the reason why the Samurai Principle says to not
>> return None when the function fails to do what it intended to do.
>
> How can the function “fail” when it returns what it is specified to
> return?


Are you trolling?

On the unlikely event that you're not, if you have a function called
"len", the *intent* of the function is to return the length of its
argument. That's why it's called "len" rather than "raise_exception" or
"return_none", say.

The use of the term "fail" is entirely unexceptional here. It is normal
English to say such things as "the function re.match() returns None if
the regular expression fails to match" or "if we fail to acquire a lock,
raise an Exception".


--
Steven

0 new messages