switch

Asun Friere afriere at yahoo.co.uk
Fri Dec 11 23:13:46 EST 2009


On Dec 11, 1:38 am, Tim Chase <python.l... at tim.thechases.com> wrote:

> It's clean if it were the solution to my problem

Picking out that line first, just to be clear about this.

You missed the disclaimer.

This was never meant to be a solution to your problem.  It was
solution to the problem contained in the code you posted.

Carl, asked a question, in response you provided an example, and I
wrote a solution.  I did so to in order to illustrate how something
resembling a dispatch mechansism can save a programmer from ending up
with a "rat's-nest" of elif chainage.  I hope you did not
misunderstand me as advocating your pulling apart working production
code.  Heck, I wouldn't, err ...don't, do this.

Which is _not_ to say that it isn't actually a solution your problem
as well! :)


>>[One guy analogy]
>
> This is where you make a false assumption

Again "I don't really know your problem only the code you've posted."
If I misunderstood the record types as originating from different
providers, I'm sure you will find that my code, which faithfully
reimplements yours, does not.

> -- the contents and
> parsing of the "switch" are provider-specific in this case,
> mapping to a common ontology of the Phone object:
>
>     class MonopolyProvider1Parser:
>       ...
>       switch row['recordtype']:
>         case '01':
>           phone.international += Decimal(row['internationalcost'])
>           // optionally a "break" here depending on
>           // C/C++/Java/PHP syntax vs. Pascal syntax which
>           // doesn't have fall-through
>         case '02':
>           phone.text_messaging += (
>             int(row['textmessages sent']) +
>             int(row['pages received']) +
>             int(row['textmessages sent']) +
>             int(row['pages received'])
>         ...
>         default:
>           raise WhatTheHeckIsThis()
>
>     class MonopolyProvider2Parser:
>       ...
>       switch row['recordtype']:
>         case 'abc':
>           phone.international += (
>             Decimal(row['canada cost']) +
>             Decimal(row['eu cost']) +
>             Decimal(row['mexico cost']) +
>             Decimal(row['other intl cost'])
>             )
>         case 'xyz':
>           phone.text_messaging += int(row['textmessages'])
>         ...
>         default:
>           raise WhatTheHeckIsThis()
>
Fair enough. What you posted was a subset of your overall problem.
Obviously!

Inasmuch as the code that you posted accurately represents a subset of
your problem, the solution given is still applicable, at least to that
subset of your problem.  It's just that each inidividual
MonopolyProvider will require its own set of data sources.  In any
case, I'm sure you could work out it could be applied, if you put your
mind to it.

I agree this involves more code than the example required, possibly
for less gain and I believe it is still advantageous to organise the
code in a way which separates knowledge from logic.  At least when
that knowledge is non-trivial.

> > # The one thing I'm sure I don't understand from the code is where the
> > original rectypes comes into the process.
>
Sorry, my worrying there about whether we need to look the appropriate
RecType up in that dict was just a distraction.  The problem isn't in
the dict, but with that the try should only be trapping unknown types,
not problems of instantiation.  I should have written:
     try :
        AppropriateRecType = rectypes[rectype]
    except KeyError :
        raise WhatTheHeckIsThisError('unknown rectype: %s' % rectype)
    record = ApproriateRecType(row)

>  From the provider data -- sometimes CSV files, sometimes
> tab-delimited text files, sometimes MS Access MDB files,
> sometimes a web service...
> varies per-provider (and some providers
> have multiple formats, like Verizon has MyBIZ and IBAS; ATT has
> their WinCD and Premier; etc).  No two formats are the same, so
> the logic needed to parse the data into our internal homogenized
> Phone data structure varies per each one.  And the logic (or lack
> thereof) used by many providers in creating their formats require
> reverse-engineering most of them through trial-and-error, and
> huge ugly if/elif/else chains.

I feel your pain, I really do ... and a dispatch mechanism could
relieve some of it. ;)

Now I'm not saying you should implement it on extant production code.
As I wrote above, I still use, and unfortunately maintain, older code
which is a hideous mess of elif chains.  The task of challenging these
elif chains is daunting, and rewriting such working code won't rank in
my work priorities for the foreseeable future.

This is why, elif chains, when they first arise, or better perhaps,
when they first begin to grow, should be examined to see whether they
are a bud that ought to be nipped, whether they sensibly can be
nipped, and if so how.  They are, in Carl's words, "red flags," at
least they are if your're "not a very good progammer," like me.  I
invite all my fellow NVGPs to treat them as such as well. :)

I can compare extending and maintaining code I wrote using old school
elifs and flags to that written using the State and dispatch patterns,
(code which python makes practicable).  OO makes life easier for an
older NVGP such as myself, a young gun like you might not need to rely
on clear code. ;)



More information about the Python-list mailing list