Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Implicit conversion to boolean in if and while statements

Reply
Thread Tools

Implicit conversion to boolean in if and while statements

 
 
rusi
Guest
Posts: n/a
 
      07-17-2012
On Jul 15, 9:50*pm, Rick Johnson <(E-Mail Removed)> wrote:
> On Sunday, July 15, 2012 11:19:16 AM UTC-5, Ian wrote:
> > On Sun, Jul 15, 2012 at 4:56 AM, Steven D'Aprano
> > <(E-Mail Removed)> wrote:
> > > (For the record, I can only think of one trap for the unwary: time
> > > objects are false at *exactly* midnight.)

>
> > Ugh, that's irritating. *I can't think of any scenario where I would
> > ever want the semantics "if timeval (is not midnight):". *This
> > reinforces the point that if you only want to test whether you have
> > None, you should use "is not None" rather than relying on __bool__.

>
> I think this issue is not so much a "bool test" vs "type test", but more an ambiguous syntax
> issue.


If you know some English, its clear that if and while create bool
contexts.
[If you know English but have not studied logic the 'if/while' make
sense whereas 'bool' is gobbledygook]

The issue is not where the cast goes to -- this clearly is bool
But where the cast comes from -- which requires tracing program-paths
 
Reply With Quote
 
 
 
 
Andrew Berg
Guest
Posts: n/a
 
      07-17-2012
On 7/16/2012 7:43 PM, Steven D'Aprano wrote:
> The existence of a jar or no jar is irrelevant to the question of how
> many jellybeans there are. They are two different things, and therefore
> need two different values. There are many ways to implement this.

I have a better real example, but I opted not to use it before since it
requires some explanation - IRC messages.
A client-to-server message has the basic form of b'COMMAND arguments
:message' (e.g. b'PRIVMSG #channel :hi guys!'). Some commands have no
message part because there is no message associated with it (e.g. b'JOIN
#channel') and there is at least one where there is a big difference
between a blank message (b'') and no message - b'TOPIC #channel' is a
request for the topic while b'TOPIC #channel :' clears the topic since
the part after the b':' is b'' (b'TOPIC #channel :Welcome to #channel'
sets the topic to "Welcome to #channel"). In my code, I would have an
object representing a message rather than parsing it multiple times. If
the message
attribute is not None, I send b'{command} {args} :{message}', otherwise
b'{command} {args}'. If I considered '' falsey, either I would require
all messages to have ":" (which would not actually be part of the
message) or have any request to view the topic as a channel op clear the
topic. This would apply to the server parsing the message as well. A few
other commands have messages optional as well, but they are not as
serious as TOPIC.

I could do:

if has_message:
send('{command} {args} :{message}')
else:
send('{command} {args}')

but then I'd have to make sure has_message stays accurate since message
won't necessarily be. Or maybe I could leave message undefined and catch
the appropriate exception. However, using None is the cleanest and most
obvious.

I know Rick likes to troll, but I do agree with him that "if something:"
for arbitrary objects can be ambiguous or confusing. I don't think
if/while must have True or False, but not every object has an obvious
truth value.
--
CPython 3.3.0b1 | Windows NT 6.1.7601.17803
 
Reply With Quote
 
 
 
 
Chris Angelico
Guest
Posts: n/a
 
      07-17-2012
On Tue, Jul 17, 2012 at 11:57 AM, Andrew Berg <(E-Mail Removed)> wrote:
> I could do:
>
> if has_message:
> send('{command} {args} :{message}')
> else:
> send('{command} {args}')
>
> but then I'd have to make sure has_message stays accurate since message
> won't necessarily be. Or maybe I could leave message undefined and catch
> the appropriate exception. However, using None is the cleanest and most
> obvious.
>
> I know Rick likes to troll, but I do agree with him that "if something:"
> for arbitrary objects can be ambiguous or confusing. I don't think
> if/while must have True or False, but not every object has an obvious
> truth value.


Using None when '' is a valid token is the right thing to do (see
also, for instance, SQL's NULL, which is often used the same way). And
then you have gone away from the language's idea of whether a string
is truthy or not, so you get explicit:

if message is not None:
send('{command} {args} :{message}')

Easy! Or if the language went the other way ("all strings are true"),
it would be the other way around, you'd use "if message!=''" for the
other case. It's not a difficult problem.

Carry on bikeshedding.

ChrisA
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      07-17-2012
On Mon, 16 Jul 2012 20:22:18 -0500, Andrew Berg wrote:

> On 7/15/2012 3:28 PM, Terry Reedy wrote:
>> Because everything does (or should).

> I can see how truth testing for empty values is convenient, but perhaps
> objects should only have a truth value if explicitly given one -
> particularly in cases where such a value wouldn't be obvious or the
> obvious value isn't the actual one:


You have run into Python's default behaviour: objects are treated as
something by default. If you want them to represent nothing, you have to
explicitly code that case.

py> o = object()
py> bool(o)
True

Yet again, thinking about something versus nothing instead of true/false
makes the behaviour both obvious and correct: of course an object should
be treated as something (true-like) rather than nothing (false-like) by
default, it's an *object* is it not?

If you want your type to implement non-default semantics, such as
container semantics, then you need to code it.


>>>> c = types.SimpleNamespace()
>>>> if c: print('c')

> ...
> c
>>>> c.__dict__

> {}
>
> Would it not be reasonable to expect an empty namespace to have a truth
> value of False since [] and friends do? It's a bit of a gray area for an
> object defined by "class C: pass", but this is *specifically intended*
> to be a namespace. Why should things like functions or exceptions have
> truth values?


And this is a good life-lesson that any class called "SimpleFoo" will not
stay simple for long.

If you are right that SimpleNamespace should be treated as a container,
then it should implement container semantics. Since it doesn't, that is
either:

1) a bug; or
2) a triumph of laziness over correctness

I imagine though that the Python dev's answer will basically be #2: "it
isn't a container, it just behaves a little bit like a container, except
when it doesn't" kinda thing. But feel free to report it as a bug and see
what happens.

(This is not *entirely* wrong, because SimpleNamespace certainly doesn't
*claim* to be a container, nor does it expose the full container API. But
it should, even if that means it is no longer quite so simple.)



--
Steven
 
Reply With Quote
 
Ranting Rick
Guest
Posts: n/a
 
      07-17-2012
On Jul 16, 11:11*pm, Steven D'Aprano <steve
(E-Mail Removed)> wrote:

> I imagine though that the Python dev's answer will basically be #2: "it
> isn't a container, it just behaves a little bit like a container, except
> when it doesn't" kinda thing.


The emperor has no clothes!
 
Reply With Quote
 
Devin Jeanpierre
Guest
Posts: n/a
 
      07-17-2012
On Mon, Jul 16, 2012 at 12:03 AM, Steven D'Aprano
<(E-Mail Removed)> wrote:
> On Sun, 15 Jul 2012 22:15:13 -0400, Devin Jeanpierre wrote:
>
>> For example, instead of "if stack:" or "if bool(stack):", we could use
>> "if stack.isempty():". This line tells us explicitly that stack is a
>> container.

>
> isempty is not a container method.


Your entire reply is predicated on this idea that I was talking about
writing classes with this extra "isempty" method.

No. I was talking about having "isempty" be part of the collection
interface, and eliminating polymorphic bool conversion.

If you were confused, instead of assuming I meant something patently
absurd, you should have asked for a clarification.

-- Devin
 
Reply With Quote
 
Chris Angelico
Guest
Posts: n/a
 
      07-17-2012
On Tue, Jul 17, 2012 at 2:18 PM, Ranting Rick
<(E-Mail Removed)> wrote:
> On Jul 16, 11:11 pm, Steven D'Aprano <steve
> (E-Mail Removed)> wrote:
>
>> I imagine though that the Python dev's answer will basically be #2: "it
>> isn't a container, it just behaves a little bit like a container, except
>> when it doesn't" kinda thing.

>
> The emperor has no clothes!


The Troll's New Point.

ChrisA
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      07-17-2012
On Mon, 16 Jul 2012 20:57:43 -0500, Andrew Berg wrote:

> I have a better real example, but I opted not to use it before since it
> requires some explanation - IRC messages. A client-to-server message has
> the basic form of b'COMMAND arguments :message' (e.g. b'PRIVMSG #channel
> :hi guys!'). Some commands have no message part because there is no
> message associated with it (e.g. b'JOIN #channel') and there is at least
> one where there is a big difference between a blank message (b'') and no
> message - b'TOPIC #channel' is a request for the topic while b'TOPIC
> #channel :' clears the topic since the part after the b':' is b''
> (b'TOPIC #channel :Welcome to #channel' sets the topic to "Welcome to
> #channel").


Okay, so you have two distinct "nothing" states when considering the
message part of an IRC command: the empty string, and missing.

That's okay. Floats have two zeroes (+0.0 and -0.0); complex numbers have
four. (Although they try hard to hide that distinction from you.)

There's nothing that says that you can only have a single falsey value in
a type, or that you might not sometimes wish to distinguish between
different false-like states. You need to distinguish between the many
different true-like messages, so you should not be surprised that you
need to distinguish between two false-like messages.

There are many ways to implement this. Here are just the most obvious:

1) a Command object where the message attribute is optional, but if
present, it is always a string;

2) a Command object where the message attribute is always present, but
can be a string or some non-string sentinel value (e.g. None);

3) a string, where the message attribute is determined by the location
of the colon, if any

4) a tuple with either two or three fields: (command, channel [,message])



> In my code, I would have an object representing a message
> rather than parsing it multiple times. If the message
> attribute is not None, I send b'{command} {args} :{message}', otherwise
> b'{command} {args}'.


Clear and obvious. Nothing wrong with that.


> I could do:
>
> if has_message:
> send('{command} {args} :{message}')
> else:
> send('{command} {args}')
>
> but then I'd have to make sure has_message stays accurate since message
> won't necessarily be.


Yes, keeping a separate variable is a mug's game. Encapsulate it in the
Command object, and have the Command object responsible for keeping it in
sync (assuming it is mutable), or just make Command immutable and be done
with it.


> Or maybe I could leave message undefined and catch
> the appropriate exception. However, using None is the cleanest and most
> obvious.


Yes it is. What's your point?

You've discovered a real-world situation where you can't collapse the
entire universe of valid values into just two, True and False, without
losing information. Did you think that this would be surprising?

Python developers often talk about interpreting objects "in a boolean
context" -- that's a pretty big hint that the semantics are to collapse
the value into two states. If you need three (or four, or fifty)
distinguishable states, then obviously boolean context will not solve
your problem. I never said it would.



--
Steven
 
Reply With Quote
 
Dennis Lee Bieber
Guest
Posts: n/a
 
      07-17-2012
On 16 Jul 2012 17:57:45 GMT, Albert van der Horst
<(E-Mail Removed)4all.nl> declaimed the following in
gmane.comp.python.general:

> In article <(E-Mail Removed)>,
> Ranting Rick <(E-Mail Removed)> wrote:
>
> >We DON'T want Python to silently convert "cost" to a string. What we
> >DO want is to force the author to use the str function thereby making
> >the conversion explicit.

>
> We do want Python to silently convert "cost" to a string in the
> proper context.
>
> cost= 3.75
> print( cost )
>

Ah, but to some of us, "print" itself implies "convert argument to
human readable string format"... ie, an explicit "cast".
--
Wulfraed Dennis Lee Bieber AF6VN
http://www.velocityreviews.com/forums/(E-Mail Removed) HTTP://wlfraed.home.netcom.com/

 
Reply With Quote
 
Andrew Berg
Guest
Posts: n/a
 
      07-17-2012
On 7/16/2012 11:11 PM, Steven D'Aprano wrote:
> If you are right that SimpleNamespace should be treated as a container,
> then it should implement container semantics. Since it doesn't, that is
> either:
>
> 1) a bug; or
> 2) a triumph of laziness over correctness
>
> I imagine though that the Python dev's answer will basically be #2: "it
> isn't a container, it just behaves a little bit like a container, except
> when it doesn't" kinda thing. But feel free to report it as a bug and see
> what happens.

I'm not saying it's necessarily wrong, but I do think it quacks a lot
like a container, even though it isn't one, especially if you're
listening for quacks instead of looking for ducks.
--
CPython 3.3.0b1 | Windows NT 6.1.7601.17803
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Implicit conversion to boolean in if and while statements Stefan Behnel Python 0 07-15-2012 09:17 AM
Re: Implicit conversion to boolean in if and while statements Chris Angelico Python 0 07-15-2012 08:47 AM
Subtle difference between boolean value and boolean comparison? Metre Meter Javascript 7 08-06-2010 08:40 PM
if statements and case statements questions John Crichton Ruby 6 07-12-2010 06:17 PM
difference between 'boolean' and 'java.lang.Boolean' J Leonard Java 4 01-19-2008 02:56 AM



Advertisments