[Python-Dev] lazy evaluation redux (was dict "setdefault". Feaure request or bugfix?)

Alex Martelli aleax@aleax.it
Tue, 11 Feb 2003 14:33:45 +0100


On Tuesday 11 February 2003 01:23 pm, Jesus Cea Avion wrote:
> <https://sourceforge.net/tracker/index.php?func=detail&aid=684542&group_id=
>5470&atid=355470>
>
> Reading "python cookbook" I reach a very intelligent
> dictionary construction: to use dictionary "setdefault"
> to avoid a "get" or a "try...except".
>
> Nevertheless current "setdefault" behaviour is
> questionable, since it evaluates the default value when
> it is not necessary. In my mind, "setdefault" should
> evaluate the default value when it need to use it, not
> ALWAYS. Example:

OK, you want "lazy evaluation", but only in a very specific case.

I don't think you're going to be able to get such a huge concept
into such a remote and obscure corner case.  If lazy evaluation
is ever to make its way into Python (and it would have many
benefits, as well as many costs), I think it would have to be
much more general *AND* clearly visible at the point of call --
ANY call to:
    whatever(a(), b())
MUST continue to ensure each of a and b is called before
whatever is -- both for backwards compatibility AND to respect
the principle of least astonishment -- that's how Python has
always worked and how anybody would expect it to work,
even if some binding whatever=somedict.setdefault had been
executed previously.

So, syntax is needed at the point of call to tell the program
_readers_ "this expression is passed as a lazily evaluated
argument" -- explicit is better than implicit.  And to let you
write your own callables which are ready to accept lazily
evaluated arguments, syntax is also needed on that side,
both to say "this argument can be a lazily evaluated one"
and to force the evaluation when and if it is necessary (the
latter might be implicit, but I think explicit is better).

E.g., a strawman syntax might be...:

def setdefault(adict, akey, ?avalue):
    if akey not in adict:
        adict[akey] = evaluate_now(avalue)
    return adict[akey]

to be called as, e.g.

setdefault(mydict, 'goo', ?makeavalue(x))

this would use ? for both formal and actual arguments to
mean lazy evaluation, and a new builtin to force the time
of evaluation.  Other choices are, of course, possible.


Alex