[OPINION] - does language really matter if they all dothe samething?

Terry Reedy tjreedy at udel.edu
Sat Jan 24 12:30:57 EST 2004


"Dietrich Epp" <dietrich at zdome.net> wrote in message
news:58587302-4E30-11D8-8FAB-0003934ACDEC at zdome.net...
> The rest of the post is dedicated to two examples of patterns which
> don't quite fit into Python, but are used well in some projects written
> in other languages.
...
> My Lisp project related to an RPG and random
> generation of items.  It had lots of code like the following:
>
> (defun random-sword-magic-power (quality)
>    (choose-random-assoc
>      quality (poor medium good)
>      ((5 0 0) (glows-in-the-dark))
>      ((3 3 0) (magically-silent))
>      ((1 5 1) (elemental-power (select-random '(earth water air fire))))
>      ((0 2 4) (magical-keen-edge))
>      ((0 0 2) (append (random-sword-magic-power 'medium)
>                       (random-sword-magic-power 'medium)))))
>
> The numbers on the left are probabilities relative to the other
> probabilities in the same column.  So, when generating a random 'poor'
> magic quality of a sword, you have a 5/9 chance of getting 'glow in the
> dark'.  For a 'good' quality, you have a 2/7 chance of getting two
> 'medium' qualities instead.  It is difficult for me to imagine how one
> would go about making this function more concise, to me it looks
> downright minimal.  The only thing I could see making it smaller would
> be removing the parentheses, but they would have to be replaced by
> something else such as commas or tabs.

This seems straightforward: define a function by partial application of
another, more general function.  Nothing obviously Lisp specific.  A Python
equivalent needs _ instead of - in names and , instead of ' ' to separate
seq items (with spaces optional).  Maybe something like

def random_sword_magic_power(quality):
    return choose-random-assoc(
      quality, (poor,medium,good),
      ((5,0,0), glows_in_the_dark),
      ...
      ((0,0,2), random_sword_magic_power(medium)+
                   random_sword_magic_power(medium))
    )

perhaps with some of the apparent names quoted as literal strings instead,
depending on programming style.

> I'm not trying to say that all applications are like my application,
> and I'm not trying to say that my application can't be written in
> Python.  I'm just saying that using macros, a paradigm that Python
> doesn't even come close to supporting, makes reading and writing
> functions like the above a lot easier.

I knows of things for which this is true, but your example is not obviously
one of them ;-).  Does c_r_a really have to be evaluated at compile rather
than run time?

> You don't even need to know that 'choose-random-assoc' is a macro

I didn't, but I am sure a Lisp programmer would have.

> you just need to know how to use it.

Part of knowing that is knowing what to quote and not to quote.  Since
macros quote args while functions evaluate them, (at least for some lisps,
but I have not read CL rules), it would seem that maybe I would have to
know.  If c_r_a were a function, would the call be *exactly* the same?

> I challenge anyone to come up with a better way to express the above
> function in Python.  If I think it's better, I'll write "PYTHON RULZ"
> on my forehead and post a photo on the web.

I slightly prefer my Python version, but I suspect you will not, so you
remain safe.

> I agree that functions are objects in Python.  However, not everything
> in Python is an object.

Python is a language for manipulating defined types of information objects,
and only such.  Python code is a specific set of directions for doing so.
That is what 'Everything in Python is an object' means and truthfully
states.

>  For example, names are not objects.

Of course not.  Names, as such, are part of the Python grammar, with their
own syntax (production) rule.  They, along with statements, expressions,
operators, puctuation, literals, and comments (etc), are parts of the
programs in which we express our object manipulation intent.  They, along
with all the other grammatical units, are not the objects manipulated.

However, a particular Python interpreter may choose to convert names to
runtime objects for use in its runtime operations.  (CPython does this for
global names and generally for attributes but usually not for function
locals.)  And it may choose to make them available as strings at runtime.
And it may have functions that 'dereference' runtime strings as if the
equivalent sequence of chars had been written (unquoted) in the code.
Hence some of the confusion.

> In Objective C:
...
> In Python, first try:
>
> def reset_settings(self):
>      try:
>          self.set_settings(self.delegate.default_settings(self))
>      except AttributeError:
>          self.set_settings(some_fallback_value)
>
> But wait!  What if there is an error in
> self.delegate.default_settings() which raises an AttributeError?  It
> might confuse the hell out of a programmer who might go looking for the
> bug in reset_settings(), because it's using the fallback value for some
> odd reason.  So we should reimplement it.

If multiple parts of an expressions can raise the same exception, and you
want to tell which part of the expression one comes from (so as to handle
it differently), yes, you will have to compute the expression in stages, as
you do here:

> Python, second try:
>
> def reset_settings(self):
>      method = None
>      try:
>          method = self.delegate.default_settings
>      except AttributeError:
>          pass
>      if method:
>          self.set_settings(method(self))
>      else:
>          self.set_settings(some_fallback_value)

An alternative would have been to 'not do that'.  Instead, differentiate
the exceptions.  Something like

class MyAttributeError(AttributeError): pass

    def default_settings(self):
        try:
           ...
        except AttributeError: raise MyAttributeError

Then 'first try' would, I believe, work same as 'second try' (but callers
might need to know of MyAttributeError).

> If you think this example is contrived, maybe you haven't worked with
> the paradigms used in Objective-C very much.  The example above was
> used dozens of times in a class that I wrote in Objective-C which draws
> a grid to the screen, for example, when it asks itself or its delegate
> what color the grid should be, or the maximum scale allowed.  The
> practice is also used heavily by Apple's Cocoa libraries, which are my
> favorite UI libraries of all time to program with.

If you program in one language using idiomatic patterns from another
language, you may need to write adapter functions, like reset_settings,
that embody the pattern, to ease the translation.  Or stick with the other
language, if you prefer it, or switch patterns, which many of us have done,
at least in part.

Terry J. Reedy







More information about the Python-list mailing list