From: Steve Howell on
On Apr 2, 7:05 am, Steve Howell <showel...(a)yahoo.com> wrote:
> On Apr 2, 2:04 am, Steven D'Aprano <st...(a)REMOVE-THIS-
>
>
>
> cybersource.com.au> wrote:
> > On Thu, 01 Apr 2010 21:16:18 -0700, Steve Howell wrote:
> > > The ironic thing about the ternary operator is that it is not really
> > > ternary; it's binary.  Even just making an expression from a binary
> > > operator inevitably leads to syntax hell.
>
> > > There is a principle of programming that I would like to coin, which is
> > > the "Tyranny of Three."
>
> > > It is impossible to code for any expression that has three possible
> > > values in any kind of elegant way.  It's just impossible.  Try to code
> > > the bowling game without tearing out your teeth--three conditions:
> > > strike, spare, or normal.
>
> > > The tyranny of three is that 3 is too small for an elegant N-based
> > > solution and too large for a simple condition.
>
> > I'm afraid I don't understand any of that. Can you explain further?
>
> > How is the ternary operator "not really ternary, it's binary"? It
> > requires three arguments, not two, which makes it ternary. In Python
> > syntax:
>
> Of course, I understand that the ternary operator has three arguments,
> but it only has two possible outcomes.
>
> You asked me to elaborate on the "Tyranny of Three."  Let's say you
> have three possible outcomes.
>
> In some languages you would write something like this:
>
> mark = (rolls == 1) && (pins == 10) ? 'strike' :
>        (rolls == 2) && (pins == 10) ? 'spare' :
>                                       'normal'
>
> Many people consider the above very ugly, so they write it like so:
>
>   if pins == 10:
>      if rolls == 1:
>         return 'strike'
>      else:
>         return 'spare'
>   else:
>      return 'normal'
>
> Then the next programmer comes along and "cleans up":
>
>   if pins == 10:
>     return 'strike' if rolls == 1 else 'spare'
>   else:
>     return 'normal'
>
> Then there is this alternative:
>
>   if rolls == 2:
>     return 'spare' if pins == 10 else 'normal'
>   else:
>     return 'strike'
>
> And then:
>
>   if rolls == 2:
>     if pins == 10
>       return 'spare'
>     else
>       return 'normal
>   else:
>     return 'strike'
>
> Or even this:
>
>    return 'strike' if rolls == 1 else ('spare' if pins == 10 else
> 'normal')
>
> The "Tyranny of Three" refers to a problem where there are an infinite
> number of valid solutions, but none of them have any essential beauty,
> so they lead to endless nitpicking and code churn.

I forgot this one:

def obfuscated_triager(rolls, pins,
lookup = ['normal'] * 10 + ['strike'] + [None] * 9 + ['spare']
):
return lookup[rolls * pins]

From: Steve Howell on
On Apr 2, 7:21 am, Steve Holden <st...(a)holdenweb.com> wrote:
> Steve Howell wrote:
> > On Apr 2, 2:04 am, Steven D'Aprano <st...(a)REMOVE-THIS-
> > cybersource.com.au> wrote:
> [...]
> >> How is the ternary operator "not really ternary, it's binary"? It
> >> requires three arguments, not two, which makes it ternary. In Python
> >> syntax:
>
> > Of course, I understand that the ternary operator has three arguments,
> > but it only has two possible outcomes.
>
> That doesn't make it a binary operator. Otherwise what's long
> multiplication, which has an infinite number of possible outcomes?
>

Ok, it's not a binary operator. I just meant it only really selects
from two possible expressions, so you would think there would be one
good way to express that in code, but of course any variation of the
ternary operator leads to endless debates.

>
>
> > You asked me to elaborate on the "Tyranny of Three."  Let's say you
> > have three possible outcomes.
>
> > In some languages you would write something like this:
>
> > mark = (rolls == 1) && (pins == 10) ? 'strike' :
> >        (rolls == 2) && (pins == 10) ? 'spare' :
> >                                       'normal'
>
> > Many people consider the above very ugly, so they write it like so:
>
> >   if pins == 10:
> >      if rolls == 1:
> >         return 'strike'
> >      else:
> >         return 'spare'
> >   else:
> >      return 'normal'
>
> > Then the next programmer comes along and "cleans up":
>
> >   if pins == 10:
> >     return 'strike' if rolls == 1 else 'spare'
> >   else:
> >     return 'normal'
>
> > Then there is this alternative:
>
> >   if rolls == 2:
> >     return 'spare' if pins == 10 else 'normal'
> >   else:
> >     return 'strike'
>
> > And then:
>
> >   if rolls == 2:
> >     if pins == 10
> >       return 'spare'
> >     else
> >       return 'normal
> >   else:
> >     return 'strike'
>
> > Or even this:
>
> >    return 'strike' if rolls == 1 else ('spare' if pins == 10 else
> > 'normal')
>
> > The "Tyranny of Three" refers to a problem where there are an infinite
> > number of valid solutions, but none of them have any essential beauty,
> > so they lead to endless nitpicking and code churn.
>
> The Real Programmer (tm) simply chooses one, implements it and moves on.
> While philosophical discussions are interesting they don't pay the bills.
>

Agreed. The nitpicking and code churn tends to come up when you have
multiple programmers with different aesthetics, although sometimes
even the solo programmer can get overly fiddly.
From: Tim Chase on
Steve Howell wrote:
> I forgot this one:
>
> def obfuscated_triager(rolls, pins,
> lookup = ['normal'] * 10 + ['strike'] + [None] * 9 + ['spare']
> ):
> return lookup[rolls * pins]

Bah...no need to be _quite_ so obscure:
def triager(rolls, pins):
return {
(1, 10):'strike',
(2,10):'spare',
(2,0):'wow, you stink',
}.get((rolls, pins), 'normal')


;-)

-tkc



From: Steve Howell on
On Apr 2, 7:52 am, Tim Chase <python.l...(a)tim.thechases.com> wrote:
> Steve Howell wrote:
> > I forgot this one:
>
> > def obfuscated_triager(rolls, pins,
> >         lookup = ['normal'] * 10 + ['strike'] + [None] * 9 + ['spare']
> >         ):
> >     return lookup[rolls * pins]
>
> Bah...no need to be _quite_ so obscure:
>    def triager(rolls, pins):
>      return {
>        (1, 10):'strike',
>        (2,10):'spare',
>        (2,0):'wow, you stink',
>        }.get((rolls, pins), 'normal')
>
> ;-)
>

Well played.



From: Steven D'Aprano on
On Fri, 02 Apr 2010 07:05:49 -0700, Steve Howell wrote:

>> How is the ternary operator "not really ternary, it's binary"? It
>> requires three arguments, not two, which makes it ternary. In Python
>> syntax:
>>
> Of course, I understand that the ternary operator has three arguments,
> but it only has two possible outcomes.

But the number of outcomes is not what the "binary" in binary operator
refers to. It's the number of arguments.


> You asked me to elaborate on the "Tyranny of Three." Let's say you have
> three possible outcomes.
>
> In some languages you would write something like this:
>
> mark = (rolls == 1) && (pins == 10) ? 'strike' :
> (rolls == 2) && (pins == 10) ? 'spare' :
> 'normal'

Not if you held a gun to my head *wink*


> Many people consider the above very ugly, so they write it like so:
[snip multiple alternative ways of choosing between three alternatives]

All very interesting, but I don't see why you are singling out three
alternatives as particularly difficult. Not all choices between three
possible results are hard to code:

choice = some_integer % 3 # returns 0, 1, or 2.

and choosing between two results isn't necessarily simple either, e.g.
the rules of protocol. Deciding which of two people outrank the other can
be *very* complicated. Does a king outrank a pope? What about a
president? Does a prince of some two-bit speck of dirt outrank a senator
of a superpower? People have worked out (by which I mean, "made up")
rules for all these and more, and they still can't always agree on who
ranks who. International negotiations have floundered and collapsed
because the parties couldn't agree which ambassador got the chair at the
head of the table nearest the door...

You are absolutely right to say that some problems don't have an elegant
solution, but I think you're wrong to single out "three" as special.


--
Steven