Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #85858 > unrolled thread

What behavior would you expect?

Started byJason Friedman <jsf80238@gmail.com>
First post2015-02-18 21:44 -0700
Last post2015-02-19 23:18 -0800
Articles 12 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  What behavior would you expect? Jason Friedman <jsf80238@gmail.com> - 2015-02-18 21:44 -0700
    Re: What behavior would you expect? Denis McMahon <denismfmcmahon@gmail.com> - 2015-02-19 14:16 +0000
      Re: What behavior would you expect? Chris Angelico <rosuav@gmail.com> - 2015-02-20 02:08 +1100
        Re: What behavior would you expect? Denis McMahon <denismfmcmahon@gmail.com> - 2015-02-19 20:03 +0000
          Re: What behavior would you expect? Chris Angelico <rosuav@gmail.com> - 2015-02-20 07:11 +1100
            Re: What behavior would you expect? Dan Sommers <dan@tombstonezero.net> - 2015-02-20 04:54 +0000
              Re: What behavior would you expect? Chris Angelico <rosuav@gmail.com> - 2015-02-20 16:16 +1100
                Re: What behavior would you expect? Dan Sommers <dan@tombstonezero.net> - 2015-02-20 05:40 +0000
                  Re: What behavior would you expect? Jason Friedman <jsf80238@gmail.com> - 2015-02-19 22:49 -0700
                  Re: What behavior would you expect? Paul Rubin <no.email@nospam.invalid> - 2015-02-19 22:18 -0800
                    Re: What behavior would you expect? Chris Angelico <rosuav@gmail.com> - 2015-02-20 17:21 +1100
                      Re: What behavior would you expect? Paul Rubin <no.email@nospam.invalid> - 2015-02-19 23:18 -0800

#85858 — What behavior would you expect?

FromJason Friedman <jsf80238@gmail.com>
Date2015-02-18 21:44 -0700
SubjectWhat behavior would you expect?
Message-ID<mailman.18856.1424321059.18130.python-list@python.org>

[Multipart message — attachments visible in raw view] — view raw

I have need to search a directory and return the name of the most recent
file matching a given pattern.  Given a directory with these files and
timestamps,

q.pattern1.abc Feb 13
r.pattern1.cdf  Feb 12
s.pattern1.efg  Feb 10
t.pattern2.abc Feb 13
u.pattern2.xyz  Feb 14
v.pattern2.efg  Feb 10

calling my_function("/path/to/dir", "pattern1") will return q.pattern1.abc
and calling my_function("/path/to/dir", "pattern2") will return
u.pattern2.xyz.

My question is, what would be a reasonable behavior/result/return value if:
1. "/path/to/dir" does not exist or is not readable
2. no files match the given pattern

Also, what would be a reasonable name for such a function?

[toc] | [next] | [standalone]


#85904

FromDenis McMahon <denismfmcmahon@gmail.com>
Date2015-02-19 14:16 +0000
Message-ID<mc4r7v$cm7$2@dont-email.me>
In reply to#85858
On Wed, 18 Feb 2015 21:44:12 -0700, Jason Friedman wrote:

> My question is, what would be a reasonable behavior/result/return value
> if:

> 1. "/path/to/dir" does not exist or is not readable 

Normally I'd say raise an exception. Whether you choose to use an 
existing exception (will trying to read a non existent dir raise one 
anyway?) or define your own is up to you. This condition would probably 
indicate an error in the data received by the function - you should be 
given a readable directory.

If (and only if) being called with an invalid directory is potentially 
valid, then you could respond to (1) the same as to (2).

> 2. no files match the given pattern

Return either None, 0, False or an empty string.

In both cases, it is then a matter for the calling code to catch the 
exception or handle the return value appropriately.

-- 
Denis McMahon, denismfmcmahon@gmail.com

[toc] | [prev] | [next] | [standalone]


#85906

FromChris Angelico <rosuav@gmail.com>
Date2015-02-20 02:08 +1100
Message-ID<mailman.18884.1424358984.18130.python-list@python.org>
In reply to#85904
On Fri, Feb 20, 2015 at 1:16 AM, Denis McMahon <denismfmcmahon@gmail.com> wrote:
>> 2. no files match the given pattern
>
> Return either None, 0, False or an empty string.
>
> In both cases, it is then a matter for the calling code to catch the
> exception or handle the return value appropriately.

I'd avoid the empty string here, because "absence of file" should be
very different from "first file matching pattern". Imagine this naive
code:

fn = my_function("/path/to/dir", "pattern2")
move_to("/path/to/dir/" + fn, "/other/path")

In the failure case (nothing matches the pattern), what could happen?
Best is it raises an exception, which would come from the my_function
line. Next best, it returns None, 0, or False, and you get a TypeError
on the deletion, and can trace your way back up. Worst, it returns ""
and oops, you just moved the whole directory into the target, instead
of just one file.

Of course, non-naive code probably prefers a None/0/False return to a
raised exception, but in any case, the difference between those two
options is fairly small. But I'd avoid the potential confusion with
the empty string.

Anyway, that's just API bike-shedding :)

ChrisA

[toc] | [prev] | [next] | [standalone]


#85928

FromDenis McMahon <denismfmcmahon@gmail.com>
Date2015-02-19 20:03 +0000
Message-ID<mc5fiq$a3f$3@dont-email.me>
In reply to#85906
On Fri, 20 Feb 2015 02:08:49 +1100, Chris Angelico wrote:

> On Fri, Feb 20, 2015 at 1:16 AM, Denis McMahon
> <denismfmcmahon@gmail.com>
> wrote:
>>> 2. no files match the given pattern
>>
>> Return either None, 0, False or an empty string.
>>
>> In both cases, it is then a matter for the calling code to catch the
>> exception or handle the return value appropriately.
> 
> I'd avoid the empty string here, because "absence of file" should be
> very different from "first file matching pattern". Imagine this naive
> code:

If your function documentation states that a failure to match any 
existing file returns an empty string (and if that's the case, then the 
documentation should do), then whoever calls the function should check 
the return value isn't an empty string.

There's two conflicting "paradigms" as it were here.

On the one hand, the return type of a function (when it returns, rather 
than raising an exception) should be consistent to itself, even if using 
a language where types are not declared.

On the other hand, a failure condition should clearly be a failure 
condition, which for a language that supports untyped functions means 
that we have the luxury of being able to return None / Nul[l] / NaN / 
False / 0 etc instead of a string / object / array / list / dictionary / 
mapping etc instead of raising an exception for the failure, and so we 
can try and handle the failure at the calling level without worrying 
about trapping exceptions.

I guess at the end of the day the programmer has to consider and 
determine which is most appropriate to his application, given the case.

As an aside, it's always a good idea to check that what you get looks 
like what you expected, whether it comes from a function call or as a 
data packet over the internet, before you start using it to do other 
things. ;)

-- 
Denis McMahon, denismfmcmahon@gmail.com

[toc] | [prev] | [next] | [standalone]


#85929

FromChris Angelico <rosuav@gmail.com>
Date2015-02-20 07:11 +1100
Message-ID<mailman.18902.1424376675.18130.python-list@python.org>
In reply to#85928
On Fri, Feb 20, 2015 at 7:03 AM, Denis McMahon <denismfmcmahon@gmail.com> wrote:
> On the one hand, the return type of a function (when it returns, rather
> than raising an exception) should be consistent to itself, even if using
> a language where types are not declared.
>

Yes, so I'd advise against having a function sometimes return a string
and sometimes a dict. Sure. But None gets a bit of a special pass
here; in a lot of languages, what you'd have is a "nullable" type (eg
in C you might declare the return value as "pointer to char", and
either return a pointer to a string, or NULL), but in Python, you
return None for the special case. So in a sense, "str or None" is not
so inconsistent.

> I guess at the end of the day the programmer has to consider and
> determine which is most appropriate to his application, given the case.

Indeed. But knowing that your caller quite possibly won't check, what
would you do, to increase the chances of the unexpected being noticed?
Again, it comes down to expectations. If 25% of queries are going to
return "nothing found", then having that be the empty string is fine -
you can be pretty sure your users will test for it. But if that's an
extremely rare case, then it may be worth raising an exception
instead, so it's safe even if someone forgets to test for the unusual.

ChrisA

[toc] | [prev] | [next] | [standalone]


#85943

FromDan Sommers <dan@tombstonezero.net>
Date2015-02-20 04:54 +0000
Message-ID<mc6emp$j1q$1@dont-email.me>
In reply to#85929
On Fri, 20 Feb 2015 07:11:13 +1100, Chris Angelico wrote:

> On Fri, Feb 20, 2015 at 7:03 AM, Denis McMahon <denismfmcmahon@gmail.com> wrote:
>> On the one hand, the return type of a function (when it returns,
>> rather than raising an exception) should be consistent to itself,
>> even if using a language where types are not declared.
> 
> Yes, so I'd advise against having a function sometimes return a string
> and sometimes a dict. Sure. But None gets a bit of a special pass
> here; in a lot of languages, what you'd have is a "nullable" type (eg
> in C you might declare the return value as "pointer to char", and
> either return a pointer to a string, or NULL), but in Python, you
> return None for the special case. So in a sense, "str or None" is not
> so inconsistent.

I'm an old C and assembly language programmer, but the older I get, the
less I use null (in C or in Java), None (in Python), or equivalent in
other languages.  If a function can't perform its side effect (like
renaming a file), then raise an exception.  If a function called for its
value can't return that value, then raise an exception; if there are no
values to return, then return an empty collection.  How much code do we
write and read that checks for null (or None, or whatever), and how much
time do we spend writing it and reading it?

Readability counts.  Simple is better than complex.  Explicit is better
than implicit.  Errors should never pass silently.  In the face of
ambiguity, refuse the temptation to guess.  (Wow!  I knew I could turn
to the Zen for support, but I didn't realize just how much support I
would get!)

See also <http://en.wikipedia.org/wiki/Void_safety>.

Dan

[toc] | [prev] | [next] | [standalone]


#85945

FromChris Angelico <rosuav@gmail.com>
Date2015-02-20 16:16 +1100
Message-ID<mailman.18908.1424409419.18130.python-list@python.org>
In reply to#85943
On Fri, Feb 20, 2015 at 3:54 PM, Dan Sommers <dan@tombstonezero.net> wrote:
> if there are no
> values to return, then return an empty collection.

That one makes sense only if you were going to return a collection
anyway, though. If you were going to return a string, returning an
empty list on failure makes no sense. Hence the notion of returning a
"non-string".

ChrisA

[toc] | [prev] | [next] | [standalone]


#85948

FromDan Sommers <dan@tombstonezero.net>
Date2015-02-20 05:40 +0000
Message-ID<mc6hd4$j1q$2@dont-email.me>
In reply to#85945
On Fri, 20 Feb 2015 16:16:50 +1100, Chris Angelico wrote:

> On Fri, Feb 20, 2015 at 3:54 PM, Dan Sommers <dan@tombstonezero.net> wrote:
>> if there are no
>> values to return, then return an empty collection.
> 
> That one makes sense only if you were going to return a collection
> anyway, though. If you were going to return a string, returning an
> empty list on failure makes no sense. Hence the notion of returning a
> "non-string".

I think I came in a little late, and saw "2. no files match the given
pattern," in which case I'm sticking to my story and returning an empty
list.

The original problem was "to search a directory and return the name of
the most recent file matching a given pattern."  I'd still prefer an
exception to None, and we agree on that an empty string is bad because
it's not a non-string and it could be too easily mistaken for a
filename.

[toc] | [prev] | [next] | [standalone]


#85949

FromJason Friedman <jsf80238@gmail.com>
Date2015-02-19 22:49 -0700
Message-ID<mailman.18911.1424411363.18130.python-list@python.org>
In reply to#85948

[Multipart message — attachments visible in raw view] — view raw

I think I came in a little late, and saw "2. no files match the given
> pattern," in which case I'm sticking to my story and returning an empty
> list.
>
> The original problem was "to search a directory and return the name of
> the most recent file matching a given pattern."  I'd still prefer an
> exception to None, and we agree on that an empty string is bad because
> it's not a non-string and it could be too easily mistaken for a
> filename.
>
>
Agreed.

[toc] | [prev] | [next] | [standalone]


#85953

FromPaul Rubin <no.email@nospam.invalid>
Date2015-02-19 22:18 -0800
Message-ID<87r3tlds2l.fsf@jester.gateway.pace.com>
In reply to#85948
Dan Sommers <dan@tombstonezero.net> writes:
> I'd still prefer an exception to None, and we agree on that an empty
> string is bad because it's not a non-string and it could be too easily
> mistaken for a filename.

Empty string would be bad.  Sometimes I like to simulate an option type,
by returning the value as a 1-element list if there's a value, otherwise
as an empty list.  So you could say

  filename = get_filename(...)[0]

if you want an exception in the failure case, or you could do something
like

  fs = get_filename(...)
  if len(fs) == 0:  ... # didn't get a filename

[toc] | [prev] | [next] | [standalone]


#85954

FromChris Angelico <rosuav@gmail.com>
Date2015-02-20 17:21 +1100
Message-ID<mailman.18914.1424413711.18130.python-list@python.org>
In reply to#85953
On Fri, Feb 20, 2015 at 5:18 PM, Paul Rubin <no.email@nospam.invalid> wrote:
> Empty string would be bad.  Sometimes I like to simulate an option type,
> by returning the value as a 1-element list if there's a value, otherwise
> as an empty list.  So you could say
>
>   filename = get_filename(...)[0]
>
> if you want an exception in the failure case, or you could do something
> like
>
>   fs = get_filename(...)
>   if len(fs) == 0:  ... # didn't get a filename

Bikeshedding: That could be written as simply "if not fs". :)

ChrisA

[toc] | [prev] | [next] | [standalone]


#85955

FromPaul Rubin <no.email@nospam.invalid>
Date2015-02-19 23:18 -0800
Message-ID<87mw49dpar.fsf@jester.gateway.pace.com>
In reply to#85954
Chris Angelico <rosuav@gmail.com> writes:
>>   if len(fs) == 0:  ... # didn't get a filename
> Bikeshedding: That could be written as simply "if not fs". :)

Yeah, in that instance you could do that.  It's an unsafe practice when
None is used as the no-value marker, since the empty string is a
perfectly good string and also converts to boolean false.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web