RE: I sing the praises of lambda, my friend and savior!

Discussion in 'Python' started by Robert Brewer, Oct 11, 2004.

  1. Jeff Shannon wrote:
    > Maybe I'm just ignorant or behind the times, but I still
    > haven't seen a
    > real argument as to *why* lambdas are so useful. There's some
    > assertions about how avoiding giving something a name makes things
    > clearer, which I disagree with. ('Explicit is better than
    > implicit.' I
    > don't see how 'no name' makes the purpose of a code segment
    > clearer than
    > 'some meaningfully descriptive name', no matter how many times it's
    > asserted.) There's complaints that it takes a whole two
    > extra lines to
    > type a proper function def, as opposed to being able to use lambdas
    > inline... but again, I'd claim that with a properly named
    > function, the
    > intent at point-of-use will be quite clear and the cost of two extra
    > lines of code is minimal.


    All I can say is, "sometimes it's not minimal". Adapters are a great
    example:

    xforms = {dejavu.icontains: lambda x, y: x + " Like '%" + y[1:-1] +
    "%'",
    dejavu.icontainedby: icontainedby,
    dejavu.istartswith: lambda x, y: x + " Like '" + y[1:-1] +
    "%'",
    dejavu.iendswith: lambda x, y: x + " Like '%" + y[1:-1] + "'",
    dejavu.ieq: lambda x, y: x + " = " + y,
    dejavu.now: lambda: "Now()",
    dejavu.today: lambda: "DateValue(Now())",
    dejavu.year: lambda x: "Year(" + x + ")",
    }

    Conciseness is a continuum. I understand (and agree with) your
    contention that many lambdas wouldn't suffer from a full function
    definition. Writing the above with full functions, however, would take
    us to the other extreme end of the continuum, which is boilerplate for
    boilerplate's sake. (If I ever write another unnecessary Java
    getter/setter pair, shoot me. ;)

    The other use case where I use lambdas heavily is in querying
    databases*; I wrap up lambdas in an Expression object which can then be
    passed around through the domain model and into the data source layer
    (and can even be pickled). I chose lambdas for two reasons:

    1) I admit, one-liners. But much more importantly,

    2) The restricted expressivity of lambdas is a plus when using them as
    queries. I purposefully don't want to have to handle multiple statements
    (especially loops), nor assignment. They just get in the way. Finally,
    when building such queries on the fly, I gain a bit of a security;
    lambdas function like little "restricted execution" blocks.


    Robert Brewer
    MIS
    Amor Ministries


    * See the "logic" module in svn://casadeamor.com/dejavu/trunk
     
    Robert Brewer, Oct 11, 2004
    #1
    1. Advertising

  2. Robert Brewer

    Jeff Shannon Guest

    Robert Brewer wrote:

    >Jeff Shannon wrote:
    >
    >
    >>Maybe I'm just ignorant or behind the times, but I still
    >>haven't seen a
    >>real argument as to *why* lambdas are so useful. There's some
    >>assertions about how avoiding giving something a name makes things
    >>clearer, which I disagree with. ('Explicit is better than
    >>implicit.' I
    >>don't see how 'no name' makes the purpose of a code segment
    >>clearer than
    >>'some meaningfully descriptive name', no matter how many times it's
    >>asserted.) There's complaints that it takes a whole two
    >>extra lines to
    >>type a proper function def, as opposed to being able to use lambdas
    >>inline... but again, I'd claim that with a properly named
    >>function, the
    >>intent at point-of-use will be quite clear and the cost of two extra
    >>lines of code is minimal.
    >>
    >>

    >
    >All I can say is, "sometimes it's not minimal". Adapters are a great
    >example:
    >
    >xforms = {dejavu.icontains: lambda x, y: x + " Like '%" + y[1:-1] +
    >"%'",
    > dejavu.icontainedby: icontainedby,
    > dejavu.istartswith: lambda x, y: x + " Like '" + y[1:-1] +
    >"%'",
    > dejavu.iendswith: lambda x, y: x + " Like '%" + y[1:-1] + "'",
    > dejavu.ieq: lambda x, y: x + " = " + y,
    > dejavu.now: lambda: "Now()",
    > dejavu.today: lambda: "DateValue(Now())",
    > dejavu.year: lambda x: "Year(" + x + ")",
    > }
    >
    >Conciseness is a continuum. I understand (and agree with) your
    >contention that many lambdas wouldn't suffer from a full function
    >definition. Writing the above with full functions, however, would take
    >us to the other extreme end of the continuum, which is boilerplate for
    >boilerplate's sake. (If I ever write another unnecessary Java
    >getter/setter pair, shoot me. ;)
    >
    >


    Well, all I can say is that I had to sit down and work through some
    examples to figure out what each of those lambdas would do. It looks
    like a tangled mess of punctuation and x's and y's to me. Maybe this
    just means I'm stupid, but... ::shrug::

    I'm also not sure what the point is of defining a callable that returns
    a literal string, but I suppose you're just following a protocol
    established elsewhere.

    Personally, I'd be likely to solve this particular issue by defining a
    make_formatter() function:

    def make_formatter(format):
    def formatter(*args):
    return format % tuple(args)
    return formatter

    xforms = {dejavu.icontains: make_formatter("%s Like '%%%s%%'"),
    dejavu.icontainedby: icontainedby,
    dejavu.istartswith: make_formatter("%s Like '%s%%'"),
    dejavu.iendswith: make_formatter("%s Like '%%%s'"),
    dejavu.ieq: make_formatter("%s = %s"),
    dejavu.now: make_formatter("Now()"),
    dejavu.today: make_formatter("DateValue(Now())"),
    dejavu.year: make_formatter("Year(%s)")
    }

    # [...]
    xforms[dejavu.icontains](x, y[1:-1])

    I'm not sure that this is much clearer than your example, but I
    certainly don't think it's worse. (Admittedly, much of the gain in my
    eyes comes from using string interpolation rather than addition, which
    looks clunky and ugly to me, but I suppose that tastes may vary...)

    I suppose that the fact that all of these methods just happen to be
    building strings may be an artifact of the specific example, rather than
    a general case. I haven't really needed to use adapters, so I can't
    really say how often a general transformation along these lines might be
    applicable...

    Jeff Shannon
    Technician/Programmer
    Credit International
     
    Jeff Shannon, Oct 12, 2004
    #2
    1. Advertising

  3. On Mon, Oct 11, 2004 at 07:47:43PM -0700, Jeff Shannon wrote:
    | Robert Brewer wrote:
    | >xforms = {dejavu.icontains:
    | > lambda x, y: x + " Like '%" + y[1:-1] +"%'",

    Robert had 3 examples of a particular lambda, in this case, I'd
    consider making a separate function, 'unquote' which seems to
    be what he's doing. However, the idea of a lookup table having
    a great many varieties of thingies is not uncommon; and lambda
    is very useful in this case.

    | >Conciseness is a continuum. I understand (and agree with) your
    | >contention that many lambdas wouldn't suffer from a full function
    | >definition. Writing the above with full functions, however, would take
    | >us to the other extreme end of the continuum, which is boilerplate for
    | >boilerplate's sake.

    Hear Hear!

    | Well, all I can say is that I had to sit down and work through some
    | examples to figure out what each of those lambdas would do.

    Your problem seems to be with using string concatination (a very
    straight-forward and common method of building strings, I might add)
    rather than with lambda,

    xforms = {
    dejavu.icontains:
    lambda x,y: "%s Like '%%%s%%' % (x,y[1:-1]),
    dejavu.ieq:
    lambda x,y: "%s = %s" % (x,y),
    dejavu.now: lambda: "Now()",
    dejavu.today: lambda: "DateValue(Now())",
    dejavu.year:
    lambda x: "Year(%s)" % x
    }

    | I'm also not sure what the point is of defining a callable that returns
    | a literal string, but I suppose you're just following a protocol
    | established elsewhere.

    This is called lazy evaulation, the caller doesn't _know_ that it is
    just a string till it evaluates the code block. It could, just as easily
    be, for example, a computation that creates a string.

    lambda: "current time is %s" % time.ctime()

    This expression varies depending on when you ask for its value.

    | Personally, I'd be likely to solve this particular issue by defining a
    | make_formatter() function:
    |
    | def make_formatter(format):
    | def formatter(*args):
    | return format % tuple(args)
    | return formatter
    |
    | xforms = {dejavu.icontains: make_formatter("%s Like '%%%s%%'"),
    ....
    | }
    |
    | # [...]
    | xforms[dejavu.icontains](x, y[1:-1])

    What you've done:
    - completely changed the semantics of his example
    - made the logic not quite so easily understandable; I have to
    now "look" for the definition of make_formatter
    - created a rather 'useless' function and clouded my head
    with a name for it
    - used alot more vertical space in my code that amounts
    to a few (unnecessary) extra pages to deal with.

    Also, your make_formatter is a very simple lambda:

    xforms = { dejavu.icontains:
    lambda *args: "%s Like '%%%s%%'" % args,

    That ain't so hard is it?

    | I suppose that the fact that all of these methods just happen to be
    | building strings may be an artifact of the specific example, rather than
    | a general case. I haven't really needed to use adapters, so I can't
    | really say how often a general transformation along these lines might be
    | applicable...

    This string building is quite common in the style of programming
    I use as well. It is a general case for me, and lambda makes my
    life much nicer.

    On Mon, Oct 11, 2004 at 01:51:00PM -0700, Jeff Shannon wrote:
    | But because of Python's line- and indentation-based syntax, doing all of
    | that on a single line is... um... awkward at best, to put it mildly.

    There are lots of things in python that can be single-line, including
    at this point the ability to declare and invoke a function. For
    example, I can declare a mapping or sequence using a single-line
    format, ["such", "as", "this", "list"] or { "like": "this dict" }.

    I like the ability to use my entire 80 column screen for code, when
    appropriate. While the indentation helps readability, it should not
    be forced when it is not necessary. How ugly would python be if it
    forced lists to be declared one-line-per-list-item?

    | And once you make a lambda multiline, then you lose most of the point of
    | it -- at least, as far as I understand what the point is (having an
    | in-line, anonymous callable). Once you allow statements and multiple
    | expressions, all you're gaining is anonymity, which seems like a pretty
    | paltry benefit to me.

    The primary advantage of lambda is that it defines a function where
    you need it, not before. The ability to use screen realestate better
    is a nice advantage, as is not having to 'mint' a name for temporary use.

    Instead of arguing against lambda, which is already in the core language
    and used by many people, perhaps you could suggest a syntax improvement
    that would make lambda more understandable? Your're advocating taking
    away a very nice tool without proposing a resonable replacement.

    Best,

    Clark

    --
    Clark C. Evans Prometheus Research, LLC.
    http://www.prometheusresearch.com/
    o office: +1.203.777.2550
    ~/ , mobile: +1.203.444.0557
    //
    (( Prometheus Research: Transforming Data Into Knowledge
    \\ ,
    \/ - Research Exchange Database
    /\ - Survey & Assessment Technologies
    ` \ - Software Tools for Researchers
    ~ *
     
    Clark C. Evans, Oct 12, 2004
    #3
  4. Robert Brewer

    Jeff Shannon Guest

    Clark C. Evans wrote:

    >Instead of arguing against lambda, which is already in the core language
    >and used by many people, perhaps you could suggest a syntax improvement
    >that would make lambda more understandable? Your're advocating taking
    >away a very nice tool without proposing a resonable replacement.
    >


    To be a bit more accurate, I'm not so much advocating its removal, as I
    am concurring with the "powers that be" who've already been discussing
    dropping it from Py3K. Several people were bemoaning that (rumored)
    decision; I was merely pointing out that I can understand why they're
    (supposedly) doing so, and that I don't think that it's the sort of loss
    that some are claiming. Even if you convince me that lambdas *are*
    amazingly useful... well, it doesn't accomplish anything, because I'm
    not influencing anyone to drop lambdas, I'm just agreeing with the
    people who are already dropping lambdas.

    (And for the record -- yes, I can now see a few special cases in which
    lambdas do improve clarity. It still seems, however, that these are
    definitely special cases and are therefore not special enough to break
    the rules. I do feel that the introduction of lambdas broke a number of
    Python's rules. Once again, lambdas may offer local maxima in clarity,
    but at a cost in global clarity. Reputedly, GvR also feels that lambdas
    break Python's rules, and he's becoming pickier about breaking the rules
    as Python matures... thus the discussion of dropping them in Py3K.)

    Jeff Shannon
    Technician/Programmer
    Credit International
     
    Jeff Shannon, Oct 13, 2004
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steven Bethard

    singing the praises of unicode and codecs

    Steven Bethard, Dec 10, 2004, in forum: Python
    Replies:
    0
    Views:
    298
    Steven Bethard
    Dec 10, 2004
  2. Roman Suzi
    Replies:
    13
    Views:
    608
    Bengt Richter
    Jan 7, 2005
  3. Pedro Del Gallego

    Bad Smells sing in a rails application

    Pedro Del Gallego, Jun 27, 2007, in forum: Ruby
    Replies:
    0
    Views:
    110
    Pedro Del Gallego
    Jun 27, 2007
  4. Steve Dogers

    lambda vs non-lambda proc

    Steve Dogers, Mar 30, 2009, in forum: Ruby
    Replies:
    1
    Views:
    178
    Sean O'Halpin
    Mar 30, 2009
  5. Robert

    sing along

    Robert, Sep 30, 2003, in forum: Javascript
    Replies:
    0
    Views:
    103
    Robert
    Sep 30, 2003
Loading...

Share This Page