Ruby and Python

Alex Martelli aleaxit at yahoo.com
Mon Nov 20 04:23:56 EST 2000


"graham" <graham73 at telocity.com> wrote in message
news:B63D9C65.17342%graham73 at telocity.com...
> Alex Martelli
> > [on functions]
> > They're treated exactly like every other object, and thus
> > are first-class.
>
> It's fine if you want to go on believing that Python has first class
> functions, but the fact that you have to manually form closures for
> functions means that they are not first class in the accepted (and
> admittedly informal) definition of "first class". Ocaml, Haskell, etc

Here's an "accepted definition of first-class", from a typical
(and, incidentally, quite usable) Scheme course:
http://www.cs.odu.edu/~zeil/cs355/Handouts/schemedoc/schemedoc/node13.html

"""
In Scheme, as in most dialects of Lisp, functions are first-class. This
means that they are values, just like any other data type--they may be
passed as arguments to functions  and returned as values of functions.
"""

*Are values like any other data type -- may be passed as arguments and
returned as values*.  THIS is the typical "accepted, admittedly informal"
definition.


Similarly, take a typical introduction to functional programming, at
http://cs.wwc.edu/~aabyan/221_2/PLBOOK/Functions.html:

"LISP ... in 1958 ... provided for recursion, first-class functions ...
dynamic rather than static scope rules".  Gist of the quote: LISP in
the 1958 version is said to provide first-class functions, although
it lacks any static scoping but provides dynamic scoping instead.


Not all authors agree on this (that early LISP provided first-class
functions), but it does appear to be the most-widespread opinion
about this issue.


Taking Charles Elkan's lectures at
http://www-cse.ucsd.edu/graduate/Comps/vogt/proglang/elkan.lectures:

"""
In a nutshell, at "definition time", when an abstraction is evaluated
to give a "function value":
 - under static scoping the function value is a closure
  which saves the current environment
 - under dynamic scoping, only the abstraction expression is saved.
"""

we see that Python is far closer to what Elkan defines as 'static
scoping' -- it just doesn't (currently) define "the current
environment" to include any NESTING (lexical or otherwise).

Of course, Elkan's explicit definition of "first-class" is:
"""
FIRST-CLASS VALUES

Defn: A value is first-class if it can be used in all contexts
where other values can be used, in particular:
        - as a literal value
        - as part of a larger value
        - as a function argument
        - as a function result
"""


Are you disputing that THIS is what a value "being first-class"
means?  And/or are you disputing that function-objects in Python
meet this definition?  Besides the arguments/results parts, they
can surely be used 'as part of a larger value' (a tuple, or list,
or dictionary, ...), and as literals too, e.g.:

atuple = (1, "2", 3.0, lambda x: 4+x, 5+0j, 6L, [7], (8,), {9:10})

This 'larger value' (a 9-elements tuple) uses as its "parts"
various literals of different 'first-class' Python types --
each with its own, different syntax -- the fourth one being
a function.

"All contexts" in Elkan's definition needs to be taken _in
context_, of course, -- e.g.,
    atuple[i] + 7
is OK for i in (0,2,4,5), but not otherwise -- that doesn't
mean strings, functions, lists, tuples, and dictionaries
aren't first-class, just that "addition of 7" is not defined
for these particular types, while it is for integers, floats,
complex and longs.  Just trying to forestall some cavils...:-).


> all have first class functions in the accepted meaning.
>
> I am not criticising Python on this issue. All I am saying is that
> to go around saying Python has first class functions is misleading,

No, it's just applying the common-or-garden definition.  A function
is first-class, but it's (currently) not a (nested) lexical closure.
It's not in issue of criticism of praise, but one of precision in
the use of words.

Is the following idiom familiar at all...?

(defun make-adder (n)
  (lexical-let ((n n))
    (function (lambda (m) (+ n m)))))

The result of make-adder isn't any less 'first-class' because an
explicit lexical-let was needed to make it into a lexical-closure,
in a Lisp dialect that otherwise binds dynamically.  This is not
a _defense_ of dynamical binding (nor of Python's current, limited
form of statical binding) -- just a *terminological clarification*.

Humpty-Dumpty-ish use of words is not correct or acceptable on
a public technical forum, in my opinion.


> particulary when comparing Python with other languagees, as the
> original author did with Ruby. If you want to say that "Python has
> first class functions, except that you have to manually form closures",
> that's fine, but that's not the same as "having first class functions".

You don't *have* to 'form closures' at all -- you form them if
and when you feel a need for them.  This issue has no bearing
on 'first-classness' of functions, and it would therefore be
totally inappropriate to tag it in an "exception clause" to
an assertion about said first-classness -- as if it was somehow
a LIMITATION of the first-classness aspect, when it just isn't.

It would be like saying something like, e.g., 'Python has first
class unlimited-precision integers (bignums), except that you
have to syntactically denote them with a trailing L'.  The lack
of, e.g., Smalltalk-ish implicit conversion between fixnums and
bignums may be a plus or a minus, but it has nothing to do with
the *first-classness* of such numbers, and it wold be misleading
to imply or assert it does.


Alex






More information about the Python-list mailing list