473,421 Members | 1,627 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,421 software developers and data experts.

A critic of Guido's blog on Python's lambda

Python, Lambda, and Guido van Rossum

Xah Lee, 2006-05-05

In this post, i'd like to deconstruct one of Guido's recent blog about
lambda in Python.

In Guido's blog written in 2006-02-10 at
http://www.artima.com/weblogs/viewpo...?thread=147358

is first of all, the title “Language Design Is Not Just Solving
Puzzles”. In the outset, and in between the lines, we are told that
“I'm the supreme intellect, and I created Python”.

This seems impressive, except that the tech geekers due to their
ignorance of sociology as well as lack of analytic abilities of the
mathematician, do not know that creating a language is a act that
requires little qualifications. However, creating a language that is
used by a lot people takes considerable skill, and a big part of that
skill is salesmanship. Guido seems to have done it well and seems to
continue selling it well, where, he can put up a title of belittlement
and get away with it too.

Gaudy title aside, let's look at the content of his say. If you peruse
the 700 words, you'll find that it amounts to that Guido does not like
the suggested lambda fix due to its multi-line nature, and says that he
don't think there could possibly be any proposal he'll like. The
reason? Not much! Zen is bantered about, mathematician's impractical
ways is waved, undefinable qualities are given, human's right brain is
mentioned for support (neuroscience!), Rube Goldberg contrivance
phraseology is thrown, and coolness of Google Inc is reminded for the
tech geekers (in juxtaposition of a big notice that Guido works
there.).

If you are serious, doesn't this writing sounds bigger than its
content? Look at the gorgeous ending: “This is also the reason why
Python will never have continuations, and even why I'm uninterested in
optimizing tail recursion. But that's for another installment.”. This
benevolent geeker is gonna give us another INSTALLMENT!

There is a computer language leader by the name of Larry Wall, who said
that “The three chief virtues of a programmer are: Laziness,
Impatience and Hubris” among quite a lot of other ingenious
outpourings. It seems to me, the more i learn about Python and its
leader, the more similarities i see.

So Guido, i understand that selling oneself is a inherent and necessary
part of being a human animal. But i think the lesser beings should be
educated enough to know that fact. So that when minions follow a
leader, they have a clear understanding of why and what.

----

Regarding the lambda in Python situation... conceivably you are right
that Python lambda is perhaps at best left as it is crippled, or even
eliminated. However, this is what i want: I want Python literatures,
and also in Wikipedia, to cease and desist stating that Python supports
functional programing. (this is not necessarily a bad publicity) And, I
want the Perl literatures to cease and desist saying they support OOP.
But that's for another installment.

----
This post is archived at:
http://xahlee.org/UnixResource_dir/w...bda_guido.html

* * Xah
* * xa*@xahlee.org
http://xahlee.org/

May 6 '06
267 10484


Pisin Bootvong wrote:
Joe Marshall wrote:
Alex Martelli wrote:
Most languages allow `unnamed numbers'. The `VAT_MULTIPLIER' argument
is a
strawman. Would you want to have to use a special syntax to name the
increment
in loop?

defnumber zero 0
defnumber one { successor (zero); }

for (int i = zero; i < limit; i += one) { ...}

If you language allows unnamed integers, unnamed strings, unnamed
characters, unnamed arrays or aggregates, unnamed floats, unnamed
expressions, unnamed statements, unnamed argument lists, etc. why
*require* a name for trivial functions?
Wouldn't all the other constructs benefit by having a required name as
well?

Is this a Slippery Slope fallacious argument?
(http://c2.com/cgi/wiki?SlipperySlope)

"if python required you to name every function then soon it will
require you to name every number, every string, every immediate result,
etc. And we know that is bad. Therefore requiring you to name your
function is bad!!!! So Python is bad!!!!"
How about:

If Common Lisp lets you use unnamed function, then soon everyone will
start not naming their function. Then soon they will start not naming
their variable, not naming their magic number, not naming any of their
class, not naming any function, and then all Common Lisp program will
become one big mess. And we know that is bad. So allowing unnamed
function is bad!!!! So Common Lisp is bad!!!!!


Funny you should mention that. Cells (obviously) have turned out to be a
gold mine for me in terms of development. And they have exactly one
non-limiting limitation: once you start using them, you have to use them
almost everywhere, because they create a different dataflow, or better
put, the dataflow replaces the control flow of imperative programming,
so there is no way to add a little subsection of functionality with
imperative code because all the action is over in dataflow-land.

I call it non-limiting because it is more like a healthy discipline: as
a consequence, all application semantics end up expressed as so many
discrete little cell rules. Which brings me to the punch line...

try to debug an app where all the code is in anonymous functions!!!

well, it was not a complete disaster because by hook or by crook one
could figure out which rule was at fault even in the worst case, and
most of the time there was not much question. But still...

well, it took me embarrasingly long to notice something. I never
actually coded (lambda (self) yada yada) for a rule. I always used a
macro: (c? yada yada)

This was great because it is more succinct and because once I had a
couple hundred of these i had little problem making serious overhauls to
the implementation. And of course if you know Lisp and macros...

duhhhhh! They operate on the code! So in two seconds I added a new slot
to a Cell called "code", and part of the macro expansion was to stuff
the source code into the code slot. ie...

The code: (c? (yada yada yada))
Becomes:
(make-c-dependent
:code '((yada yada yada))
:value-state :unevaluated
:rule (c-lambda (yada yada yada)))

c-lambda? I have a few of those c? macros, so I "submacro" the necessary
lambda form:

(lambda (slot-c &aux (self (c-model slot-c)) (.cache (c-value slot-c)))
(declare (ignorable .cache self))
(yada yada yada))

I almost never have to look at that code slot (as I said, most of the
time I can tell from the instance class and the slot name which rule I
screwed up) but when I am stumped, I just inspect the source code. :)

Oh, wait, this is not the "Should Python have macros" thread, is it?

:)

kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
May 10 '06 #151
Patrick May <pj*@spe.com> wrote:
al***@mac.com (Alex Martelli) writes:
...an alleged reply to me, which in fact quotes (and responds to)
only to statements by Brian, without mentioning Brian...

Mr May, it seems that you're badly confused regarding Usenet's
quoting conventions.


It seems that someone pisses in your cornflakes nearly every
morning.

For the record, I was attempting to respond to your post which I
only saw quoted in another message. Please excuse any accidental
misquoting.


Your message was an immediate followup to mine, but all the text you
quoted in it was by Brian (w/o mentioning him) -- you quoted no text
written by me.
Your "pragmatic benefits", if such they were, would also apply to the
issue of "magic numbers",


That claim is, frankly, silly. A function is far more
understandable without a name than a value like 1.19 in isolation.
The situations aren't remotely comparable.


I think the comparability is definitely there. Somebody asked me about
translating a bunch of Lisp he'd written (he later admitted he had
misunderstood the power of python's def, and that it lets one do all
he's using unnamed functions for); well, each of those HOF's returns an
unnamed function *with a nice short comment explaining WHAT it does*.

The code would be of far worse quality without the nice short comments,
but it would be much better if the comments were turned into *NAMES*
(allowing easier inspection in interactive development, debugging
including examination of tracebacks, etc). What's the *POINT* of coding
(python syntax):

def blank(*a):
" return a blank picture "
return lambda *ignore_args: []

rather than:

def blank(*a):
def blank_picture(*ignore_args): return []
return blank_picture

and so forth? The former is obscure (ok, it's an anonymous function
taking and ignoring arbitrary args and returning an empty list, but WHY,
WHAT DOES IT MEAN?!), except for the explanatory comment; the latter
clearly defines the purpose of the returned-function by its name. The
situation is exactly parallel to "magic numbers", as in:

total *= 1.19

is entirely mysterious (OK, total, is being multiplied by 1.19, but WHY,
WHAT DOES IT MEAN?!), better is

# augment total by VAT
total *= 1.19

and better still

VAT_MULTIPLIER = 1.19
total *= VAT_MULTIPLIER

A comment is better than nothing (given that the 1.19 constant, or the
function ignoring its arguments and returning empty list, are mysterious
in their purpose), a name is better still.

cost: I like languages that are and stay SMALL and SIMPLE.


Like Scheme?


Didn't want to trigger some flamewar;-), but, yes, if that was my only
choice, I'd much rather use small, simple Scheme than huge, complicated,
rich, powerful Common Lisp. ((But in this case I'm biased by early
experiences, since when I learned and used Lisp-ish languages there WAS
no Common Lisp, while Scheme was already there, although not quite the
same language level as today, I'm sure;-)).
Alex
May 10 '06 #152
Cameron Laird <cl****@lairds.us> wrote:
...
On this one isolated matter, though, I'm confused, Alex: I sure
think *I* have been writing DSLs as specializations of Python,
and NOT as "a language in its own right". Have I been fooling
myself, or are you making the point that Lisp-based DSLs live in
a larger syntactic universe than Python's, or ...?


With Lisp (or Scheme, for that matter), a DSL "lives" in exactly the
same world as the base language, while being able to add or tweak
whatever syntax it needs; with Python (or C++ or Java, for that matter),
a DSL is either a completely separate beast (parsed, compiled, perhaps
interpreted in the "host" language), or else it uses exactly the same
syntax as used in the host language. To rapidly build, experiment with,
and tweak, DSL's, a language with macros is thus advantaged.

As to how crucial that is for _production_ (as opposed to _research_)
purposes, well, obviously I prefer having no macros (or else I'd use
some form of Lisp, or perhaps Dylan -- at least for my own private
purposes, such as my long-standing personal research into the
fundamentals of contract bridge -- while in fact I prefer to use Python
for those purposes just as for others). But that doesn't make me blind
to the advantages of macros for DSL-building purposes (if I was totally
sold on both Python AND macros, I think I might build a macro
preprocessor on top of Python -- the current ASL-based compiler probably
makes that task much more feasible than it used to be -- but, macros
would be somewhat complicated as in Dylan, not extremely easy as in
Scheme [[or, I guess, Common Lisp, though I have no real experience with
those -- on the surface they look murkier than Scheme's, but that may be
just an issue of habit on my part]]).
Alex
May 10 '06 #153
Joe Marshall <ev********@gmail.com> wrote:
...
Doesn't Google also employ such people as the inventor of Limbo
programming language, one of the inventors of Dylan, and a Smalltalk
expert?


....not to mention Lisp gurus (such as Peter Norvig), C++ gurus (such as
Matt Austern) and Java ones (such as Josh Bloch) [[and I'm certainly
forgetting many!]].

The difference, if any, is that gurus of Java, C++ and Python get to
practice and/or keep developing their respectively favorite languages
(since those three are the "blessed" general purpose languages for
Google - I say "general purpose" to avoid listing javascript for
within-browser interactivity, SQL for databases, XML for data
interchange, HTML for web output, &c, &c), while the gurus of Lisp,
Limbo, Dylan and Smalltalk don't (Rob Pike, for example, is one of the
architects of sawzall -- I already pointed to the whitepaper on that
special-purpose language, and he co-authored that paper, too).
Alex
May 10 '06 #154
Alex Martelli wrote:
Joe Marshall <ev********@gmail.com> wrote:
...
If you language allows unnamed integers, unnamed strings, unnamed
characters, unnamed arrays or aggregates, unnamed floats, unnamed
expressions, unnamed statements, unnamed argument lists, etc. why
*require* a name for trivial functions?


I think it's reasonable to make a name a part of functions, classes and
modules because they may often be involved in tracebacks (in case of
uncaught errors): to me, it makes sense to let an error-diagnosing
tracebacks display packages, modules, classes and functions/methods
involved in the chain of calls leading to the point of error _by name_.

I think it's reasonable to make a name a part of types for a different
reason: new types are rarely meant to be used "just once"; but also, if
during debugging any object is displayed, it's nice to be able to show,
as part of the display, "this object is of type X and ...", with X shown
as a name rather than as a complete (thus lengthy) description. (any
decent interactive shell/debugger will let you drill down into the
details as and when you need to, of course, but a well-chosen name can
be often sufficient during such interactive exploration/debugging
sessions, and therefore save time and effort).


Any time you want an anonymous function (or class, or type, or number)
it would be because that thing is sufficiently small and simple that the
best name for it is the code itself. In one game I worked on, there was
a function named canPerformAction_and_isNotActionInQueue. It was a
simple, one line function:

bool canPerformAction_and_isNotActionInQueue( Action action ) {
return canPerformAction( action ) && !isActionInQueue( action );
}

There was no better, more abstract name, as the design required this
logic for a completely arbitrary reason -- so arbitrary it changed
multiple times in development. For a little while it was used in two
places. Then one of those places changed to have only the
isActionInQueue part. There was no useful abstraction to be made, and
it is in cases like these (which come up a lot when using functions as
parameters) where anonymous functions are a win.

-- MJF
May 10 '06 #155
M Jared Finder <ja***@hpalace.com> wrote:
...
Any time you want an anonymous function (or class, or type, or number)
it would be because that thing is sufficiently small and simple that the
best name for it is the code itself. In one game I worked on, there was


That's not what I see happen in practice in the real world -- please
check this thread for the guy who pointed me at some Lisp code of his to
draw pictures, and how each anonymous function is code returned had a
nice little comment (which would yield a perfectly suitable name, as I
showed in a Python translation of one of them). In the real world,
people don't choose anonymous functions only in these alleged cases
where anonymous is best -- if anonymous functions are available, they're
used in even more cases where naming would help (just as, again in the
real world, plenty of "magic numbers" sully the code which SHOULD be
named... but just don't GET named).

BTW, in your case canPerformQueuedAction seems a good name to me (I'd
probably eliminate the 'Action' part, since the _argument_ is an Action,
but I'd need to see more context to suggest the best name).
Alex
May 10 '06 #156

Kaz Kylheku wrote:

Now imagine you had to do this with every object.

def add_five(x)
# return x + 5 <-- anonymous integer literal, not allowed!!!
five = 5 # define it first
return x + five

I mentioned that as Slippery slope fallacious argument in other reply.
[...]
That doesn't mean you can't develop scalable solutions to all kinds of
problems using Python. But it does mean that the scalability of the
overall solution comes from architectural details that are not related
to Python itself. Like, say, having lots of machines linked by a fast
network, working on problems that decompose along those lines quite
nicely.


Is there such language that allow scalability without any need for
design on the underlying architecture?
Python doesn't obscure or become obstacle in utilise those
architecture. Python allow one to design scalable architecture. So
Python IS scalable, isn't it? Only when Python prevent the up-scaling
or Python made scaled up project unmanagable that you can say that
Python is not scalable.

In 'Team scalable' axis, Python is easy to learn for average
programmer. So it is easier for Python to scale up.
'Data scalable' axis is language neutral, it depends on how you
architecture your database, etc.

'User requirement scalable' axis require both infrastructure and
language to provide:

No matter how scalable your language is, you cannot make a 100MHz/128MB
server serve 100,000 client a second over the internet.

No matter how many server and load balancing you have, you cannot
practically program gmail using purely MS-DOS bat file.

May 10 '06 #157
al***@mac.com (Alex Martelli) writes:
Any time you want an anonymous function (or class, or type, or number)
it would be because that thing is sufficiently small and simple that the
best name for it is the code itself.
In the real world, people don't choose anonymous functions only in
these alleged cases where anonymous is best
In the real world, people do a lot of things they shouldn't.

Any feature can be abused, and poor style is possible in any
language. I just checked my code for lambdas, and they are
exclusively short half-liners passed as parameters to higher order
functions. Naming them would only complicate the code, just like
naming (other) intermediate results would.
if anonymous functions are available, they're used in even more
cases where naming would help


Perhps, but not necessarily. But how about the converse: if every
function must be named, they will be named even where naming them
hurts.

-k
--
If I haven't seen further, it is by standing in the footprints of giants
May 10 '06 #158
Ken Tilton wrote:
Python has a weak lambda, statements do not always
return values, it does not have macros, and I do not know if it has
special variables.


I am pretty much ignorant of Common Lisp, but I have the impression
they are the
same as Scheme parameters, i.e. thread-local dynamically scoped
variables
(feel free to correct me if I am mistaken). If I am right, here is how
you would emulate them in recent versions of Python:

import threading, time

special = threading.local()
special.x = 0

def getx():
return special.x

def set_x(value):
special.x = value
time.sleep(3-value) # thread-2 completes after thread-1
print "%s is setting x to %s" % (threading.currentThread(), getx())

if __name__ == '__main__':
print getx() # => 0
threading.Thread(None, lambda : set_x(1)).start() # => 1
threading.Thread(None, lambda : set_x(2)).start() # => 2
time.sleep(3)
print getx() # => 0

Michele Simionato

May 10 '06 #159
Alex Martelli wrote:
yes, if that was my only
choice, I'd much rather use small, simple Scheme than huge, complicated,
rich, powerful Common Lisp. ((But in this case I'm biased by early
experiences, since when I learned and used Lisp-ish languages there WAS
no Common Lisp, while Scheme was already there, although not quite the
same language level as today, I'm sure;-)).


Alas, today Scheme is not minimal at all. I mean, the document
describing the standard is short, but real implementations are pretty
rich.
I am also surprised by your claim in this thread that Scheme macros are
simpler than
Common Lisp macros; perhaps, you are not familiar with syntax-case.
BTW, there is still research going on on macros, for instance look at
http://srfi.schemers.org/srfi-72/srfi-72.html which is pretty nice.
Just to bring some info in yet another useless usenet flamewar.

Michele Simionato

May 10 '06 #160
Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:

Joe Marshall wrote:
Alex Martelli wrote:
Most languages allow `unnamed numbers'. The `VAT_MULTIPLIER' argument
is a
strawman. Would you want to have to use a special syntax to name the
increment
in loop?

defnumber zero 0
defnumber one { successor (zero); }

for (int i = zero; i < limit; i += one) { ...}

If you language allows unnamed integers, unnamed strings, unnamed
characters, unnamed arrays or aggregates, unnamed floats, unnamed
expressions, unnamed statements, unnamed argument lists, etc. why
*require* a name for trivial functions?
Wouldn't all the other constructs benefit by having a required name as
well?

Is this a Slippery Slope fallacious argument?
(http://c2.com/cgi/wiki?SlipperySlope)


No it is not.
"if python required you to name every function then soon it will
require you to name every number, every string, every immediate result,
etc. And we know that is bad. Therefore requiring you to name your
function is bad!!!! So Python is bad!!!!"


I think this is a strawman. IMO requiring to name a function can
make things cumbersome.

I don't suppose anyone thinks the following is good practice.

one = 1.
lst.append(one)
Yet this practice is forced upon you in a number of cases when
you require functions to be named. Look at the following:

def incr_cnt_by_one(obj):
obj.cnt += 1

treat_all(lst, incr_cnt_by_one)

So the question I have is: Why is requiring me to give this function
a name considered a good thing, when it leads to a situation that
is considered bad practice in case of a number.

--
Antoon Pardon
May 10 '06 #161
Pisin Bootvong <jo********@gmail.com> wrote:
+---------------
| No matter how scalable your language is, you cannot make a 100MHz/128MB
| server serve 100,000 client a second over the internet.
+---------------

Sure you can! That's ~1000 CPU cycles/request, which [assuming at least
a 100BASE-TX NIC] is plenty to service 100K *small* requests/s... ;-}

Of course, you might have to write it in assembler on bare metal,
but the good news is that with only a 1000 cycle budget, at least
the code won't be very large! ;-}
-Rob [someone who remembers 0.5 MIPS DEC PDP-10s being used
for >100 simultaneous commercial timesharing users]

-----
Rob Warnock <rp**@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

May 10 '06 #162

Rob Warnock wrote:
Pisin Bootvong <jo********@gmail.com> wrote:
+---------------
| No matter how scalable your language is, you cannot make a 100MHz/128MB
| server serve 100,000 client a second over the internet.
+---------------

Sure you can! That's ~1000 CPU cycles/request, which [assuming at least
a 100BASE-TX NIC] is plenty to service 100K *small* requests/s... ;-}

Of course, you might have to write it in assembler on bare metal,
but the good news is that with only a 1000 cycle budget, at least
the code won't be very large! ;-}

Well, I was really asking for a service that really service something
complicate and useful though :-D

And donot forget to account for OS CPU time (well may be you can write
your own OS for it too :-D )


-Rob [someone who remembers 0.5 MIPS DEC PDP-10s being used
for >100 simultaneous commercial timesharing users]

-----
Rob Warnock <rp**@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607


May 10 '06 #163
al***@mac.com (Alex Martelli) writes:
if anonymous functions are available, they're used in even more
cases where naming would help


Yes, you're right. But don't stop here. What about expressions? Many
people write very complex expression, that are hard to understand. A
good language should forbid these abuse and don't allow expressions
with more than 2 or maybe 3 operators!

Forbid everything that might be abused and you have a perfect
language?

I like Python and I teach Python, I'm also used to Java and C#. But
one of the best solutions to problems of beginners and not so
brilliant programmers is something like the Dr. Scheme enviroment:
Choose your language level yourself. Everyting (allowed constructs,
error messages,...) will be adjusted to your choosen level. And
experts have all at their fingertips they want and need. Code isn't
blowed up and screwed with workaround for language limitations (that
are aimed at beginners and less capable programmers).

Why only adjust to the less capable people? Give everyone what they
need and want! :)

--
Stefan.
May 10 '06 #164
Pisin Bootvong <jo********@gmail.com> wrote:
+---------------
| Rob Warnock wrote:
| > | No matter how scalable your language is, you cannot make a
| > | 100MHz/128MB server serve 100,000 client a second over the internet.
| > +---------------
| >
| > Sure you can! That's ~1000 CPU cycles/request, which [assuming at least
| > a 100BASE-TX NIC] is plenty to service 100K *small* requests/s... ;-}
|
| Well, I was really asking for a service that really service something
| complicate and useful though :-D
+---------------

If "only" being useful is enough, 100 cycles is enough for a DNS server,
or an NTP server, or even a stub HTTP server that delivers some small
piece of real-time data, like a few realtime environmental sensors
[temperature, voltages, etc.].

+---------------
| > Of course, you might have to write it in assembler on bare metal,
| > but the good news is that with only a 1000 cycle budget, at least
| > the code won't be very large! ;-}
|
| And donot forget to account for OS CPU time (well may be you can write
| your own OS for it too :-D )
+---------------

Uh... What I meant by "bare metal" is *no* "O/S" per se, only a
simple poll loop servicing the attention flags[1] of the various
I/O devices -- a common style in lightweight embedded systems.
-Rob

[1] a.k.a. "interrupt request" bits, except with interrupts not enabled.

-----
Rob Warnock <rp**@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

May 10 '06 #165

Antoon Pardon wrote:
Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:
Is this a Slippery Slope fallacious argument?
(http://c2.com/cgi/wiki?SlipperySlope)
No it is not.

[...]

So the question I have is: Why is requiring me to give this function
a name considered a good thing, when it leads to a situation that
is considered bad practice in case of a number.

--


Slippery Slope::
"Argumentation that A is bad, because A might lead to B, and B
to C, and we all know C is very bad."
Why is requiring me to give this function
a name considered a good thing, when it leads to a situation that
is considered bad practice in case of a number.


A === "requiring me to give function a name"
no B
C === "requiring me to give number a name"

"Argumentation that requiring one to give function a name is bad,
because that might lead to requiring one to give number a name, and we
all know that that is very bad."
Now you tell me which part of that is not Slippery slope argument.

-- Or are you trying to make a sarcastic joke? I'm sorry if I didn't
get it. --

May 10 '06 #166
Alex Martelli wrote:
I think it's reasonable to make a name a part of functions, classes and
modules because they may often be involved in tracebacks (in case of
uncaught errors): to me, it makes sense to let an error-diagnosing
tracebacks display packages, modules, classes and functions/methods
involved in the chain of calls leading to the point of error _by name_.


It seems to me that there's something of a circularity here. Either in your
logic if applied to language design in general, or as a self-perpetuating habit
when applied to Python in particular.

The assumption is that functions are in some sense rather "big" things -- that
each function performs a well-defined action which can be understood in
isolation. That may well be true in idiomatically written Python (I've never
cared for the look of the language myself, so I don't know what's considered
"normal"), but it isn't true in general. With the assumption, it makes sense
to say that every function /could/ have a name, and so, why not /give/ it a
name ? But without the assumption, when many little anonymous functions are
used, the idea of giving them all names appears pettifogging to the point of
idiocy. If the language and/or culture expects that all/most functions will be
named, then "little" functions (in my sense) won't be used; hence the
self-perpetuating habit. But I don't think that the underlying logic supports
that habit independently of its own self-perpetuating nature.

E.g. consider the Smalltalk code (assumed to be the body of a method):

aCollection
do: [:each |
each > 0 ifTrue: [^ true]].
^ false.

which iterates over a collection checking to see if any element is > 0. If so
then the method answers true ("^" -- spelled "return" in Java), otherwise it
answers false. In that code,
[^ true]
is syntactically and semantically an anonymous function, which is only invoked
if the antecedent is true (in point of fact the compiler inlines that function
away but I don't think that's relevant here). The passage beginning
[:each | ...
and reaching to the matching ] is also an anonymous function with one parameter
(each) which is applied to each element of the collection in turn. (In this
case it really is an anonymous function, even at the implementation level.)
What "name" would you give to either of them ? I don't believe that /any/ name
is possible, and certainly that no name is desirable.

In my working Smalltalk environment today, there are 60099 methods defined
across 3369 classes. In that codebase there are 38112 anonymous functions. Do
you really want to have to find names for them all ?

-- chris
May 10 '06 #167
Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:

Antoon Pardon wrote:
Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:
> Is this a Slippery Slope fallacious argument?
> (http://c2.com/cgi/wiki?SlipperySlope)


No it is not.

[...]

So the question I have is: Why is requiring me to give this function
a name considered a good thing, when it leads to a situation that
is considered bad practice in case of a number.

--


Slippery Slope::
"Argumentation that A is bad, because A might lead to B, and B
to C, and we all know C is very bad."


But I have seen noone here argue that requiring functions to be named
leads to requiring all variables to be named.
Why is requiring me to give this function
a name considered a good thing, when it leads to a situation that
is considered bad practice in case of a number.


A === "requiring me to give function a name"
no B
C === "requiring me to give number a name"

"Argumentation that requiring one to give function a name is bad,
because that might lead to requiring one to give number a name, and we
all know that that is very bad."


That is not the arguement I'm making.

The argument is that a particular pratice is considered bad coding,
(with an example giving a number) and then showing that requiring
a name for a function, almost makes such a practice inevitable (for
certain functions used as parameters)

--
Antoon Pardon
May 10 '06 #168
Pisin Bootvong wrote:
Slippery Slope::
"Argumentation that A is bad, because A might lead to B, and B
to C, and we all know C is very bad."


For the Slippery Slope criticism to be applicable, there would have to be some
suggestion that removing anonymous functions /would actually/ (tend to) lead to
removing anonymous values in general. There was no such suggestion.

The form of the argument was more like reasoning by analogy: if context A has
features like context B, and in B some feature is known to be good (bad) then
the analogous feature in A is also good (bad). In that case an attack on the
validity of the argument would centre on the relevance and accuracy of the
analogy.

Alternatively the argument might be seen as a generalisation/specialisation
approach. Functions are special cases of the more general notion of values.
We all agree that anonymous values are a good thing, so anonymous functions
should be too. If you parse the argument like that, then the attack should
centre on showing that functions have relevant special features which are not
shared by values in general, and so that we cannot validly deduce that
anonymous functions are good.

-- chris
May 10 '06 #169
On Mon, 08 May 2006 18:46:57 -0400, Ken Tilton <ke*******@gmail.com>
wrote:


David C. Ullrich wrote:
On 08 May 2006 12:53:09 -0700, tf*@conquest.OCF.Berkeley.EDU (Thomas
F. Burdick) wrote:

Ken Tilton <ke*******@gmail.com> writes:
No, you do not want on-change handlers propagating data to other
slots, though that is a sound albeit primitive way of improving
self-consistency of data in big apps. The productivity win with
VisiCalc was that one simply writes rules that use other cells, and
the system keeps track of what to update as any cell changes for
you. You have that exactly backwards: every slot has to know what
other slots to update. Ick.

No no, that's fine and the way it should be: when you change a slot,
it should know who to update. And that's also the way it works in
Cells. The trick is that Cells takes care of that part for you:

I'm glad you said that - this may be what he meant, but it seems
more plausible than what he actually said.


There may be some confusion here because there are two places for code
being discussed at the same time, and two sense of propagation.

the two places for code are (1) the rule attached to A which is
responsible for computing a value for A and (2) a callback for A to be
invoked whenever A changes. Why the difference?

In Cells, A is a slot such as 'background-color'. Whenever that changes,
we have to do something more. On Mac OS9 it was "InvalidateRect" of the
widget. In Cells-Tk, it is:
(Tcl_interp "mywidget configure -background <new color>")

In my OpenGL GUI, it is to rebuild the display-list for the widget.

That is the same no matter what rule some instance has for the slot
background-color, and different instances will have different rules.

As for propagating, yes, Cells propagates automatically. More below on
that. What I saw in the example offered was a hardcoded on-change
callback that was doing /user/ propagation form B to A (and B to A! ...
doesn't that loop, btw?


No, there's no looping in the example. Yes, the code determining what
b returns should be attached to b instead of to a, but the code I
gave does work as advertised. (I mean give me a break - I provided
a sample use so you could simply run it. Installing Python is not
hard.)

If you, um, look at the code you see that "cells.a = 42" triggers
cells.__setattr__, which fires a's callback; the callback then
reaches inside and sets the value of b _without_ going through
__setattr__, hence without triggering b's callback.

In Cells you can't have A depend on B and also B depend on A?
That seems like an unfortunate restriction - I'd want to be
able to have Celsius and Farenheit, so that setting either
one sets the other.

Of course if there are no loops it's easier to see how
you managed to do the stuff you were talking about elsewhere,
(at least sometimes) delaying execution until needed.
Anyway...)

all
the *programmer* has to care about is what values a slot depends on --
Cells takes care of inverting that for you, which is important because
that's a job that a computer is much better at than a human.

Fine. I suppose that is better; if b is going to return a + 1
the fact that this is what b returns should belong to b, not
to a. So a has an update list including b, so when a's value
is set a tells b it needs to update itself.

If we're allowed to pass (at some point, to some constructor
or other) something like (b, a + 1, [a]), which sets up a
cell b that shall return a + 1, and where the [a] is used
in the constructor to tell a to add b to a's update list
then this seems like no big deal.

And doing that doesn't seem so bad - now when the programmer
is writing b he has to decide that it should return a + 1
and also explicitly state that b shall depend on a; this
is all nice and localized, it's still _b_ telling _a_ to
add b to a's update list, and the programmer only has
to figure out what _b_ depends on when he's writing _b_.
Doesn't seem so bad.

But of course it would be better to be able to pass just
something morally equivalent to (b, a + 1) to whatever
constructor and have the system figure out automatically
that since b returns a + 1 it has to add a to b's update
list. There must be some simple trick to accomplish that
(using Python, without parsing code).


Right, you do not want to parse code. It really would not work as
powerfully as Cells, which notice any dynamic access to another cell
while a rule is running. So my rule can call a function on "self" (the
instance that wons the slot being calculated, and since self can have
pointers to other instances, the algorithm can navigate high and low
calling other functions before finally reading another ruled slot. You
want to track those.
Exactly what the trick is I
don't see immediately.


To compute a value for a slot that happens to have a rule associated
with it, have a little cell datastructure that implements all this and
associate the cell with the slot and store a pointer to the rule in the
cell. Then have a global variable called *dependent* and locally:

currentdependent = *dependent*
oldvalue = cell.value
newvalue = call cell.rule, passing it the self instance
*dependent* = currentvalue

if newvalue not = oldvalue
call on-change on the slot name, self, newvalue and oldvalue
(the on-chnage needs to dispatch on as many arguments as
the language allows. Lisp does it on them all)

In the reader on a slot (in your getattr) you need code that notices if
the value being read is mediated by a ruled cell, and if the global
*dependent* is non empty. If so, both cells get a record of the other
(for varying demands of the implementation).

In Cells do we just pass a rule using other cells to
determine this cell's value, or do we also include
an explicit list of cells that this cell depends on?


Again, the former. Just write the rule, the above scheme dynamically
figures out the dependencies. Note then that dependencies vary over time
because of different branches a rule might take.

I want to reassure the community that this (nor the spreadsheet analogy
<g>) is not just my crazy idea. In 1992:

http://www.cs.utk.edu/~bvz/active-va...readsheet.html

"It is becoming increasingly evident that imperative languages are
unsuitable for supporting the complicated flow-of-control that arises in
interactive applications. This paper describes a declarative paradigm
for specifying interactive applications that is based on the spreadsheet
model of programing. This model includes multi-way constraints and
action procedures that can be triggered when constraints change the
values of variables."

Cells do not do multi-way constraints, btw.


My _guess_ is that a "multi-way constraint" is something like
what's above, where A depends on B and B depends on A?
Nor partial constraints. To
hard to program, because the system gets non-deterministic. That kinda
killed (well, left to a small niche) the whole research programme. I
have citations on that as well. :)

kenny

************************

David C. Ullrich
May 10 '06 #170
In article <1h***************************@mac.com>,
Alex Martelli <al***@mac.com> wrote:
Cameron Laird <cl****@lairds.us> wrote:
...
On this one isolated matter, though, I'm confused, Alex: I sure
think *I* have been writing DSLs as specializations of Python,
and NOT as "a language in its own right". Have I been fooling
myself, or are you making the point that Lisp-based DSLs live in
a larger syntactic universe than Python's, or ...?


With Lisp (or Scheme, for that matter), a DSL "lives" in exactly the
same world as the base language, while being able to add or tweak
whatever syntax it needs; with Python (or C++ or Java, for that matter),
a DSL is either a completely separate beast (parsed, compiled, perhaps
interpreted in the "host" language), or else it uses exactly the same
syntax as used in the host language. To rapidly build, experiment with,
and tweak, DSL's, a language with macros is thus advantaged.

As to how crucial that is for _production_ (as opposed to _research_)
purposes, well, obviously I prefer having no macros (or else I'd use
some form of Lisp, or perhaps Dylan -- at least for my own private
purposes, such as my long-standing personal research into the
fundamentals of contract bridge -- while in fact I prefer to use Python
for those purposes just as for others). But that doesn't make me blind
to the advantages of macros for DSL-building purposes (if I was totally
sold on both Python AND macros, I think I might build a macro
preprocessor on top of Python -- the current ASL-based compiler probably
makes that task much more feasible than it used to be -- but, macros
would be somewhat complicated as in Dylan, not extremely easy as in
Scheme [[or, I guess, Common Lisp, though I have no real experience with
those -- on the surface they look murkier than Scheme's, but that may be
just an issue of habit on my part]]).
Alex


Ah! I understand much better now.

You correctly distinguish, say, Lisp, Dylan, ... from Python, C,
Java, ... for their syntactic aptness at construction of DSLs.
I don't want that to mislead readers, though, who might thus fail
to see how Python *is* different from C, Java, ..., in its
convenience for implementation of a particular kind of Python-
looking DSL. As you know, it's easy (if heavy with security
consequences) in Python to eval(), and it's not in C or Java.
The Python run-time builds in a complete interpreter, and that's
different from the base functionality of C or Java.

A consequence is that, in Python, it's an exercise for a beginner
to write, say an assembler whose syntax is a sequence of function
calls (<URL: http://www.unixreview.com/documents/s=9133/ur0404e/ >).
C or Java can't really boast the same.
May 10 '06 #171
Stefan Nobis <sn****@gmx.de> wrote:
al***@mac.com (Alex Martelli) writes:
if anonymous functions are available, they're used in even more
cases where naming would help


Yes, you're right. But don't stop here. What about expressions? Many
people write very complex expression, that are hard to understand. A
good language should forbid these abuse and don't allow expressions
with more than 2 or maybe 3 operators!


That would _complicate_ the language (by adding a rule). I repeat what
I've already stated repeatedly: a good criterion for deciding which good
practices a language should enforce and which ones it should just
facilitate is _language simplicity_. If the enforcement is done by
adding rules or constructs it's probably not worth it; if the
"enforcements" is done by NOT adding extra constructs it's a double win
(keep the language simpler AND push good practices).
Alex

May 10 '06 #172
>>>>> "Alex" == Alex Martelli <al***@mac.com> writes:

Alex> The difference, if any, is that gurus of Java, C++ and Python get to
Alex> practice and/or keep developing their respectively favorite languages
Alex> (since those three are the "blessed" general purpose languages for
Alex> Google - I say "general purpose" to avoid listing javascript for
Alex> within-browser interactivity, SQL for databases, XML for data
Alex> interchange, HTML for web output, &c, &c), while the gurus of Lisp,
Alex> Limbo, Dylan and Smalltalk don't (Rob Pike, for example, is one of the
Alex> architects of sawzall -- I already pointed to the whitepaper on that
Alex> special-purpose language, and he co-authored that paper, too).

That's crazy. Some of the key developers of Smalltalk continue to work
on the Squeak project (Alan Kay, Dan Ingalls, and I'm leaving someone
out, I know it...). So please remove Smalltalk from that list.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<me****@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

*** Posted via a free Usenet account from http://www.teranews.com ***
May 10 '06 #173

Antoon Pardon wrote:
Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:

Antoon Pardon wrote:
Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:
> Is this a Slippery Slope fallacious argument?
> (http://c2.com/cgi/wiki?SlipperySlope)

No it is not.

[...]

So the question I have is: Why is requiring me to give this function
a name considered a good thing, when it leads to a situation that
is considered bad practice in case of a number.

--
Slippery Slope::
"Argumentation that A is bad, because A might lead to B, and B
to C, and we all know C is very bad."


But I have seen noone here argue that requiring functions to be named
leads to requiring all variables to be named.


If I misinterpret your intended meaning, then I'm terribly sorry.
However let me clarify how I understand your statements -- English is
not my native language but I'm quite sure I have good English skill.

you said:
Why is requiring me to give this function
a name considered a good thing, when it leads to a situation that
is considered bad practice in case of a number.
So in that question, one of the your assumption is that:

"it (required function naming) ***LEADS*** to a situation that is
considered bad practice in case of a number (required number naming)"

You have not seen anyone here
"argue that requiring functions to be named leads to requiring all

variables to be named"

But obviously I have seen someone "argue that requiring functions to be
named leads to requiring **NUMBER** to be named"

And you said that requiring number to be named is bad.
Where did I misunderstand that you, with all good faith, were not
trying to say that "A leads B which is bad so "why is A considered a
good thing""? And how is it not slippery argument?

To put my response another way, I would ask:
Does Python require you to name all your number? expression? (Hint: the
answer is no)

So where did you get the idea that requiring function to be named, as
Python does, leads to requiring number to be named? Is it in a research
anywhere? Or do majority of people here agree so (that it leads to)?

Why is requiring me to give this function
a name considered a good thing, when it leads to a situation that
is considered bad practice in case of a number.


A === "requiring me to give function a name"
no B
C === "requiring me to give number a name"

"Argumentation that requiring one to give function a name is bad,
because that might lead to requiring one to give number a name, and we
all know that that is very bad."


That is not the arguement I'm making.

The argument is that a particular pratice is considered bad coding,
(with an example giving a number) and then showing that requiring
a name for a function, almost makes such a practice inevitable (for
certain functions used as parameters)


Your example:

def incr_cnt_by_one(obj):
obj.cnt += 1

treat_all(lst, incr_cnt_by_one)

Did not in anyway show that the number one is required to be named. 1
in that code is written literally; you didn't have to write "one = 1"
first. The function to increment obj.cnt by one is named. but the
number 1 itself is not named.
Antoon Pardon


May 10 '06 #174
Pisin Bootvong <jo********@gmail.com> wrote:
...
Is there such language that allow scalability without any need for
design on the underlying architecture?


Perhaps Erlang...? I have no specific experience with it, but according
to the rumor mill it forces or cajoles you into an architecture that's
quite appropriate for scaling -- i.e., sure that architecture needed to
be designed, but (if I understand Erlang correctly) it's now built into
the language and you're more or less going to use the right paradigm.
Alex
May 10 '06 #175
Rob Warnock <rp**@rpw3.org> wrote:
...
If "only" being useful is enough, 100 cycles is enough for a DNS server,
or an NTP server, or even a stub HTTP server that delivers some small
piece of real-time data, like a few realtime environmental sensors
[temperature, voltages, etc.].


Reminds me of Stuart Cheshire's description of how they managed to
shoehorn zeroconf (aka bonjour, the artist formerly known as rendezvous)
into a risible amount of ROM (less than 1K byte, if I recall correctly)
left in an embedded microcontroller (for a video camera, I think).
Zeroconf is at heart a few clever tricks on top of DNS (plus 169.254.*
IPs), and in the end they managed by one more clever trick (the thingy
ignores WHAT the request is for, and just spits out the same response
each and every time -- pushing the boundaries of DNS but, it seems,
still technically staying within those boundaries;-).

Not directly relevant to the scaling debate (the camera's expected to be
on a LAN, serving a few requests per second at most), but the limit
being on bits rather than cycles somehow "tastes" similar to me.
Alex

May 10 '06 #176


mi***************@gmail.com wrote:
Ken Tilton wrote:
Python has a weak lambda, statements do not always
return values, it does not have macros, and I do not know if it has
special variables.

I am pretty much ignorant of Common Lisp, but I have the impression
they are the
same as Scheme parameters, i.e. thread-local dynamically scoped
variables
(feel free to correct me if I am mistaken). If I am right, here is how
you would emulate them in recent versions of Python:

import threading, time

special = threading.local()
special.x = 0

def getx():
return special.x

def set_x(value):
special.x = value
time.sleep(3-value) # thread-2 completes after thread-1
print "%s is setting x to %s" % (threading.currentThread(), getx())

if __name__ == '__main__':
print getx() # => 0
threading.Thread(None, lambda : set_x(1)).start() # => 1
threading.Thread(None, lambda : set_x(2)).start() # => 2
time.sleep(3)
print getx() # => 0

Michele Simionato


I was not thinking about the thread issue (of which I know little). The
big deal for Cells is the dynamic bit:

(let ((*dependent* me))
(funcall (rule me) me))

Then if a rule forces another cell to recalculate itself, *dependent*
gets rebound and (the fun part) reverts back to the original dependent
as soon as the scope of the let is exited.

In this case, because my code is so brilliant <g>, there is only one
place in the code where a rule gets called, so it would be easy enough
to manage by saving/restoring the existing value around storing a new
value there.

I do wonder what would happen to Cells if I ever want to support
multiple threads. Or in a parallel processing environment.

kenny
--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
May 10 '06 #177

Pisin Bootvong wrote:
Is this a Slippery Slope fallacious argument?
(http://c2.com/cgi/wiki?SlipperySlope)

"if python required you to name every function then soon it will
require you to name every number, every string, every immediate result,
etc. And we know that is bad. Therefore requiring you to name your
function is bad!!!! So Python is bad!!!!"


No, it is a question about consistency. Why are functions singled out?

Or is this an attempt to apply an Argumentum ad Logicam fallacy?

May 10 '06 #178

Alex Martelli wrote:

I think it's reasonable to make a name a part of functions, classes and
modules because they may often be involved in tracebacks (in case of
uncaught errors): to me, it makes sense to let an error-diagnosing
tracebacks display packages, modules, classes and functions/methods
involved in the chain of calls leading to the point of error _by name_.

I think it's reasonable to make a name a part of types for a different
reason: new types are rarely meant to be used "just once"; but also, if
during debugging any object is displayed, it's nice to be able to show,
as part of the display, "this object is of type X and ...", with X shown
as a name rather than as a complete (thus lengthy) description. (any
decent interactive shell/debugger will let you drill down into the
details as and when you need to, of course, but a well-chosen name can
be often sufficient during such interactive exploration/debugging
sessions, and therefore save time and effort).
I agree that symbolic debugging info is a good thing.
Indeed, "given an object, how do I get its NAME" (for inspection and
debugging purposes) is the most frequently asked question on
comp.lang.python, and I've grown a bit tired of answering "you can't, an
object in general intrinsically ``has no name'', it might have many or
none at all, blah blah" -- yeah, this is technically true (in today's
Python), but there's no real reason why it should stay that way forever
(IMHO). If we at least ALLOWED named objects everywhere, this would
further promote the use of names as against mysterious "magic numbers",
since the programmer would KNOW that after
VAT_MULTIPLIER = 1.19
then displaying in a debugger or other interactive session that
PARTICULAR instance of the value 1.19 would show the name string
'VAT_MULTIPLIER' as well (or no doubt a more structured name constructed
on the fly, identifying package and module-within-package too).
The problem is that a `name' is a mapping from a symbolic identifier to
an object and that this mapping must either be global (with the
attendant name collision issues) or within a context (with the
attendant question of `in which context').
Mandating names for _everything_ would complicate the language by
forcing it to provide builtin names for a lot of elementary building
blocks: so for most types of objects it's best to "gently nudge". For
functions, classes, modules, and packages, I think the naming is
important enough (as explained above) to warrant a syntax including the
name; better, therefore, not to complicate the language by providing
another different syntax in each case just to allow the name to be
omitted -- why encourage a pratice that's best discouraged, at the price
of language simplicity?


I agree. This is why I write
(defun foo (x) ...)

rather than
(setf (symbol-function 'foo) (lambda (x) ...))

However, there are places where names are cumbersome. They are
certainly cumbersome for most literal objects like numbers and strings.
There are circumstances where they are cumbersome for function
objects. The function (lambda (x) (+ x 3)) doesn't really need a name.
It isn't any big deal if you give it a name, but it's a trivial
annoyance to be forced to give it a name. It becomes a major annoyance
when you write code in continuation-passing-style or monadic style.

It is an annoyance when refactoring code, too. Suppose you had written
(mapcar #'sin list-of-numbers)

and you realize that the numbers are in degrees. With an unnamed
function, this is an easy fix:
(mapcar (lambda (x) (sin (deg->rad x))) list-of-numbers)

With a named function, you have to do one of these:
(flet ((sin-d (x) (sin (deg->rad x))))
(mapcar #'sin-d list-of-numbers))

or
(mapcar (flet ((sin-d (x) (sin (deg->rad x)))) #'sin-d)
list-of-numbers)
Matthias Felleisen once suggested that *every* internal function should
be named. I just said `continuations'. He immediately amended his
statement with `except those'.

May 10 '06 #179
al***@mac.com (Alex Martelli) writes:
I think it's reasonable to make a name a part of functions, classes and
modules because they may often be involved in tracebacks (in case of
uncaught errors): to me, it makes sense to let an error-diagnosing
tracebacks display packages, modules, classes and functions/methods
involved in the chain of calls leading to the point of error _by name_.


But it would be even nicer if the traceback could point back to the
exact location in the source code where the function definition
occurred, and that wouldn't need any name for the function.
May 10 '06 #180
al***@mac.com (Alex Martelli) writes:
Didn't want to trigger some flamewar;-), but, yes, if that was my only
choice, I'd much rather use small, simple Scheme than huge, complicated,
rich, powerful Common Lisp. ((But in this case I'm biased by early
experiences, since when I learned and used Lisp-ish languages there WAS
no Common Lisp, while Scheme was already there, although not quite the
same language level as today, I'm sure;-)).


If that was in the early to mid eighties, which I seem to recall you
mentioning, the Lisp dialects mostly in use were huger, more
complicated, richer and more powerful than Common Lisp in many, if not
most, respects, as far as I can tell. Common Lisp is a (later)
augmented least common denominator of those Lisps. The really big
thing that's newer and greater in CL is CLOS and the condition system.

',mr

--
[Emacs] is written in Lisp, which is the only computer language that is
beautiful. -- Neal Stephenson, _In the Beginning was the Command Line_
May 10 '06 #181
"Alex Martelli" wrote...
Joe Marshall wrote:
...
If you language allows unnamed integers, unnamed strings, unnamed
characters, unnamed arrays or aggregates, unnamed floats, unnamed
expressions, unnamed statements, unnamed argument lists, etc. why
*require* a name for trivial functions?
Event the trivial function can have a name. Does it make
the trivial function more understandable if I do not give a name?
I understand what lambda means, but it is clearer for me to see
something like (with more meaningful name than shown here):
def fn(x): ... return x + 5

and to use it like...
fn(3) 8

Still, I can anonymize it later, if I really need
a = [fn]
or I can give it another name
z = fn
In my opinion, the cry for lambda in Python comes
from people used to functional languages, because
they are not used to the procedural style and it
does not fit them at the beginning.
Frankly, functional style seems "more strange" to me
(i.e. the counter example). Still, I do not say it is bad.
But it never came to my mind to say "Please, rewrite
the LISP so that it looked more like Pascal. I do not like
the lambda."

Also, Python is compiled (to bytecode), imperative language,
and the form of definition of the chunks of code is more
natural to the compiler and to the customs
how the procedural program is written and how its parts
are referenced and put together to form bigger chunks
of code.
I think it's reasonable to make a name a part of functions, classes and
modules because they may often be involved in tracebacks (in case of
uncaught errors): to me, it makes sense to let an error-diagnosing
tracebacks display packages, modules, classes and functions/methods
involved in the chain of calls leading to the point of error _by name_.


I agree with Alex here. I USUALLY do not need debugger, but sometimes
it is exremely handy to discover what happens (through debugger or few
print commands, its a matter of taste). And Python is very fine here:
dir(fn) ['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__get__',
'__getattribute__', '__hash__', '__init__', '__module__', '__name__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__str__', 'func_closure', 'func_code', 'func_defaults', 'func_dict',
'func_doc', 'func_globals', 'func_name'] fn.__name__ 'fn'

and even the anonymized function still knows its original name and type
a[0].__name__ 'fn' type(a[0]) <type 'function'>

If lambda functions in Python are tweaked internally into normal Python
functions...
z = lambda x: x * 3
dir(z) ['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__get__',
'__getattribute__', '__hash__', '__init__', '__module__', '__name__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__str__', 'func_closure', 'func_code', 'func_defaults', 'func_dict',
'func_doc', 'func_globals', 'func_name'] z.__name__ '<lambda>' type(z)

<type 'function'>

.... what makes them better, than the named function? If I do not loose
anything by simplification, I want to have it simpler.

pepr
May 10 '06 #182
Alex Martelli wrote:
Stefan Nobis <sn****@gmx.de> wrote:
al***@mac.com (Alex Martelli) writes:
if anonymous functions are available, they're used in even more
cases where naming would help

Yes, you're right. But don't stop here. What about expressions? Many
people write very complex expression, that are hard to understand. A
good language should forbid these abuse and don't allow expressions
with more than 2 or maybe 3 operators!


That would _complicate_ the language (by adding a rule). I repeat what
I've already stated repeatedly: a good criterion for deciding which good
practices a language should enforce and which ones it should just
facilitate is _language simplicity_. If the enforcement is done by
adding rules or constructs it's probably not worth it; if the
"enforcements" is done by NOT adding extra constructs it's a double win
(keep the language simpler AND push good practices).


Your reasoning, taken to the extreme, implies that an assembly language,
by virtue of having the fewest constructs, is the best designed language
ever. But we know that not to be the case -- rarely do even embedded
developers program in assembly language any more. Why?

Because assembly language is so simple that it's very tedious to write.
There's no function call primitive -- you have to manually generate a
function call pattern yourself. There's no looping primitive -- you
have to manually generate a looping pattern yourself. I feel sorry for
the person who's debugging an assembly program using manually generated
code that implements a vtable-based dynamic dispatch.

Any feature that allows me to write less code to do the same thing has a
huge positive -- the reduction of human generated, and therefore error
prone, code. I think the advantages of anonymous functions:
a) explicitly documenting that the function is used in only one place
b) enabling generic iteration and looping routines
c) not having to maintain a unique name for the function
d) making the language more elegant
e) making the language simpler to implement
greatly outweigh the small disadvantage of adding one additional
construct to the language.

-- MJF
May 10 '06 #183

"Chris Uppal" wrote...
Alex Martelli wrote:
I think it's reasonable to make a name a part of functions, classes and
modules because they may often be involved in tracebacks (in case of
uncaught errors): to me, it makes sense to let an error-diagnosing
tracebacks display packages, modules, classes and functions/methods
involved in the chain of calls leading to the point of error _by name_.
[...] E.g. consider the Smalltalk code (assumed to be the body of a method):

aCollection
do: [:each |
each > 0 ifTrue: [^ true]].
^ false.

which iterates over a collection checking to see if any element is > 0. If so then the method answers true ("^" -- spelled "return" in Java), otherwise it answers false. In that code,
[^ true]
is syntactically and semantically an anonymous function, which is only invoked if the antecedent is true (in point of fact the compiler inlines that function away but I don't think that's relevant here). The passage beginning
[:each | ...
and reaching to the matching ] is also an anonymous function with one parameter (each) which is applied to each element of the collection in turn. (In this case it really is an anonymous function, even at the implementation level.) What "name" would you give to either of them ? I don't believe that /any/ name is possible, and certainly that no name is desirable.


for element in aCollection:
if element > 0:
return True
return False

And adding "def test(aCollection):" does not make it more complex,
in my opinion. And possibly, the chunk of code may be written
in some other way, more Pythonically. Maybe the attempt to
rewrite programs from other languages into Python and
the effort to use the same "tricks" like in the original program,
causes the cry for preserving lambda in future Python.

pepr
May 10 '06 #184
Ken Tilton wrote:
I was not thinking about the thread issue (of which I know little). The
big deal for Cells is the dynamic bit:

(let ((*dependent* me))
(funcall (rule me) me))

Then if a rule forces another cell to recalculate itself, *dependent*
gets rebound and (the fun part) reverts back to the original dependent
as soon as the scope of the let is exited.


Python 2.5 has a "with" statement (yes, the name is Lispish on purpose)
that could be used to implement this. See
http://www.python.org/dev/peps/pep-0343

Michele Simionato

May 10 '06 #185
Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:

Antoon Pardon wrote:
Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:
>
> Antoon Pardon wrote:
>> Op 2006-05-09, Pisin Bootvong schreef <jo********@gmail.com>:
>> > Is this a Slippery Slope fallacious argument?
>> > (http://c2.com/cgi/wiki?SlipperySlope)
>>
>> No it is not.
>>
>> [...]
>>
>> So the question I have is: Why is requiring me to give this function
>> a name considered a good thing, when it leads to a situation that
>> is considered bad practice in case of a number.
>>
>> --
>
> Slippery Slope::
> "Argumentation that A is bad, because A might lead to B, and B
> to C, and we all know C is very bad."
But I have seen noone here argue that requiring functions to be named
leads to requiring all variables to be named.


If I misinterpret your intended meaning, then I'm terribly sorry.
However let me clarify how I understand your statements -- English is
not my native language but I'm quite sure I have good English skill.

you said:
>> Why is requiring me to give this function
>> a name considered a good thing, when it leads to a situation that
>> is considered bad practice in case of a number.
So in that question, one of the your assumption is that:

"it (required function naming) ***LEADS*** to a situation that is
considered bad practice in case of a number (required number naming)"


The bad practice I was talking about was that the number was essentially
given a meaningless name that didn't add any information. There is
no adavantage using 'one' as a variable name over using 1 directly.

If for some reason I needed a 2 in the code every time 'one' was
used, I can hardy turn

one = 1

into

one = 2

Because people would still see things like:

foo(one)

In the cade and would expect this to be equivallent with

foo(1)

and not the equivallent of

foo(2)
You have not seen anyone here "argue that requiring functions to be named leads to requiring all variables to be named"

But obviously I have seen someone "argue that requiring functions to be
named leads to requiring **NUMBER** to be named"
IMO you misinterpreted someome's word that way.
And you said that requiring number to be named is bad.
Yes that is the starting point. But that is just an
example of what bad practices will follow: the use
of meaningless names.
Where did I misunderstand that you, with all good faith, were not
trying to say that "A leads B which is bad so "why is A considered a
good thing""? And how is it not slippery argument?
This is my argument:

1) Using meaningless names is a bad coding practice. (with the number example)
2) Requiring names in particular circumstances will
lead to meaninless names in those circumstances.
3) Requiring names for functions will lead to
meanless names for some functions.
4) Requiring names for functions will thus lead to
bad coding practice in a number of cases.
To put my response another way, I would ask:
Does Python require you to name all your number? expression? (Hint: the
answer is no)

So where did you get the idea that requiring function to be named, as
Python does, leads to requiring number to be named? Is it in a research
anywhere? Or do majority of people here agree so (that it leads to)?


I didn't get that idea.
>> Why is requiring me to give this function
>> a name considered a good thing, when it leads to a situation that
>> is considered bad practice in case of a number.
>
> A === "requiring me to give function a name"
> no B
> C === "requiring me to give number a name"
>
> "Argumentation that requiring one to give function a name is bad,
> because that might lead to requiring one to give number a name, and we
> all know that that is very bad."


That is not the arguement I'm making.

The argument is that a particular pratice is considered bad coding,
(with an example giving a number) and then showing that requiring
a name for a function, almost makes such a practice inevitable (for
certain functions used as parameters)


Your example:

def incr_cnt_by_one(obj):
obj.cnt += 1

treat_all(lst, incr_cnt_by_one)

Did not in anyway show that the number one is required to be named. 1
in that code is written literally; you didn't have to write "one = 1"
first. The function to increment obj.cnt by one is named. but the
number 1 itself is not named.


You missed the point entirely. Isn't "one" a horrible name to use?
It doesn't buy you anything over the use of 1 and may even cause
confusion should anyone ever write something like one = 2.

And isn't incr_cnt_by_one just as horrible a name to use. If I ever
needed another function I couldn't just use another body with
the same function name because something like

def incr_cnt_by_one(obj):
obj.buzy = False

would probably cause just as much confusion as

one = 2.

But if I am required to give such simple functions a name it
is almost inevitable I have to use such a horrible name.
the alternative is to use bland names like "func" but what
advantage does the name give you anyway? I either call
all such one-liners "func" and then there is debug help
in the name or I will have to be sure that every function
somehow has a unique name. Having to track how far I am
in the range of func1, func2 accross the code seem very
cumbersome and not worth the while. Think of what may
happen if you start using different packages each with
there own func1, func2 range of functions.

--
Antoon Pardon

--
Antoon Pardon

May 10 '06 #186
al***@mac.com (Alex Martelli) writes:
But if we can agree to name every function except continuations I'll be
content


FWIW, I disagree:

A simple example, doubling each entry in a list:

map (*2) xs
vs. let double x = x*2 in map double xs

Here's another example, extracting all lines that contain at least one
word:

filter (not.null) . map words . lines

Note that I'm using the following anonymous functions:

not . null
filter (not . null)
map words
filter (not.null) . map words

Would it really improve anything if I named these? It seems
incredibly pedestrian, along the lines of requiring a comments for
every source line:

x++; /* increase x by one */
a[x] = ' '; /* insert a space in a at position x */

Sometimes the best documentation is the code itself. Sometimes the
best name for a function is the code itself.

-k
--
If I haven't seen further, it is by standing in the footprints of giants
May 10 '06 #187
> I do wonder what would happen to Cells if I ever want to support
multiple threads. Or in a parallel processing environment.


AFAIK It should be fine.
In LW, SBCL and ACL all bindings of dynamic variables are thread-local.

Cheers,
Sean.

May 10 '06 #188
Ketil Malde <ke********@ii.uib.no> wrote:
+---------------
| Sometimes the best documentation is the code itself.
| Sometimes the best name for a function is the code itself.
+---------------

And there's no reason that an anonymous LAMBDA [even if compiled]
couldn't store its source code in the "name" slot for debugging
printouts [e.g., stack backtraces].
-Rob

-----
Rob Warnock <rp**@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

May 10 '06 #189
Ken Tilton wrote:
"Now if you are like most
people, you think that means X. It does not."


As far as natural language and understanding are concerned, "to mean" means
conformity to what most people understand, Humpty Dumpties notwithstanding.

Cheers.
May 10 '06 #190
Bill Atkins wrote:

It's interesting how much people who don't have macros like to put
them down and treat them as some arcane art that are too "*insane*"ly
powerful to be used well.

They're actually very straightforward and can often (shock of shocks!)
make your code more readable, without your efficiency taking a hit.


Not even efficiency of debugging ? A real problem with macros is that run-time
tracebacks etc, list macro outputs and not your macro'ed source code. And that
becomes an acute problem if you leave code for somebody else to update. Or did
lisp IDEs make progress on that front ?
May 10 '06 #191
Petr Prikryl wrote:
for element in aCollection:
if element > 0:
return True
return False


[I'm not sure whether this is supposed to be an example of some specific
language (Python ?) or just a generic illustration. I'll take it as the
latter, since it makes my point easier to express. I'll also exaggerate, just
a little...]

But now, in order to hack around the absence of a sensible and useful
feature -- /only/ in order to do so -- you have added two horrible new
complications to your language. You have introduced a special syntax to
express conditionals, and (worse!) a special syntax to express looping. Not
only does that add a huge burden of complexity to the syntax, and semantics, of
the language (and, to a lesser extent, its implementation), but it also throws
out any semblance of uniformity.

Once you've started down that route then you've lost all hope of user-defined
control structures which operate on a par with the built-in ones. And please
note that "control structures" are not limited to C-style "for" "while" etc.

E.g. in Java there's an unresolved, and irresolvable, tension between whether a
failing operation should return an error condition or throw an exception -- the
problem is that exceptions are (IMO and most other peoples' here) intended for
exceptional conditions, and for many operations "failure" is not exceptional.
One, highly effective, resolution to the problem is for the operation to be
parameterised with the action to take if it fails (defaulting to code to raise
an exception). In Java that approach, though technically possible, is totally
infeasible due to the pathetic overuse of unwanted syntax, and the underuse of
simple and powerful primitives.

E.g. can you add three-way comparisons (less-than, same-as, greater-than to,
say, Python with corresponding three-way conditional control structures to
supplement "if" etc ? Are they on a semantic and syntactic par with the
existing ones ? In Smalltalk that is trivial (too trivial to be particularly
interesting, even), and I presume the same must be true of Lisp (though I
suspect you might be forced to use macros).

I should say that if your example /is/ in fact Python, then I believe that
language allows fairly deep hooks into the execution mechanism, so that at
least the "for" bit can be mediated by the collection itself -- which is better
than nothing, but nowhere near what I would call "good".

-- chris
May 10 '06 #192
Bill Atkins wrote:
My favorite macro is ITERATE [...]


Thanks for the examples.

-- chris
May 10 '06 #193
On Tue, 09 May 2006 05:35:47 -0500, David C. Ullrich
<ul*****@math.okstate.edu> wrote:
On Mon, 08 May 2006 18:46:57 -0400, Ken Tilton <ke*******@gmail.com>
wrote:
[...]

If you, um, look at the code you see that "cells.a = 42" triggers
cells.__setattr__, which fires a's callback; the callback then
reaches inside and sets the value of b _without_ going through
__setattr__, hence without triggering b's callback.

In Cells you can't have A depend on B and also B depend on A?
That seems like an unfortunate restriction - I'd want to be
able to have Celsius and Farenheit, so that setting either
one sets the other.
Realized later that I hadn't thought this through.

I'd been assuming that of course we should be allowed to
have A and B depend on each other. Hence if a change in
A propagates to a change in B that change in B has to
be a non-propagating change - thought I was just so
clever seeing a way to do that.

But duh, if that's how things are then we can't have
transitive dependencies working out right; surely we
want to be able to have B depend on A and then C
depend on B...

(And also if A and B are allowed to depend on each
other then the programmer has to ensure that the
two rules are inverses of each other, which seems
like a bad constraint in general, something non-trivial
that the programmer has to get right.)

So fine, no loops. If anything, if we know that
there are no loops in the dependencies that simplifies
the rest of the programming, no need for the sort of
finagling described in the first paragraph above.
But this raises a question:

Q: How do we ensure there are no loops in the dependencies?

Do we actually run the whole graph through some algorithm
to verify there are no loops?

The simplest solution seems like adding the cells one
at a time, and only allowing a cell to depend on
previously added cells. It's clear that that would
prevent loops, but it's not clear to me whether or
not that disallows some non-looping graphs. A
math question the answer to which is not immediately
clear to me (possibly trivial, the question just
ocurred to me this second):

Say G is a (finite) directed graph with no loops. Is it always
possible to order the vertices in such a way that
every edge goes from a vertex to a _previous_ vertex?
Of course if there are no loops it's easier to see how
you managed to do the stuff you were talking about elsewhere,
(at least sometimes) delaying execution until needed.
Anyway...)


all
the *programmer* has to care about is what values a slot depends on --
Cells takes care of inverting that for you, which is important because
that's a job that a computer is much better at than a human.
Fine. I suppose that is better; if b is going to return a + 1
the fact that this is what b returns should belong to b, not
to a. So a has an update list including b, so when a's value
is set a tells b it needs to update itself.

If we're allowed to pass (at some point, to some constructor
or other) something like (b, a + 1, [a]), which sets up a
cell b that shall return a + 1, and where the [a] is used
in the constructor to tell a to add b to a's update list
then this seems like no big deal.

And doing that doesn't seem so bad - now when the programmer
is writing b he has to decide that it should return a + 1
and also explicitly state that b shall depend on a; this
is all nice and localized, it's still _b_ telling _a_ to
add b to a's update list, and the programmer only has
to figure out what _b_ depends on when he's writing _b_.
Doesn't seem so bad.

But of course it would be better to be able to pass just
something morally equivalent to (b, a + 1) to whatever
constructor and have the system figure out automatically
that since b returns a + 1 it has to add a to b's update
list. There must be some simple trick to accomplish that
(using Python, without parsing code).


Right, you do not want to parse code. It really would not work as
powerfully as Cells, which notice any dynamic access to another cell
while a rule is running. So my rule can call a function on "self" (the
instance that wons the slot being calculated, and since self can have
pointers to other instances, the algorithm can navigate high and low
calling other functions before finally reading another ruled slot. You
want to track those.
Exactly what the trick is I
don't see immediately.


To compute a value for a slot that happens to have a rule associated
with it, have a little cell datastructure that implements all this and
associate the cell with the slot and store a pointer to the rule in the
cell. Then have a global variable called *dependent* and locally:

currentdependent = *dependent*
oldvalue = cell.value
newvalue = call cell.rule, passing it the self instance
*dependent* = currentvalue

if newvalue not = oldvalue
call on-change on the slot name, self, newvalue and oldvalue
(the on-chnage needs to dispatch on as many arguments as
the language allows. Lisp does it on them all)

In the reader on a slot (in your getattr) you need code that notices if
the value being read is mediated by a ruled cell, and if the global
*dependent* is non empty. If so, both cells get a record of the other
(for varying demands of the implementation).

In Cells do we just pass a rule using other cells to
determine this cell's value, or do we also include
an explicit list of cells that this cell depends on?


Again, the former. Just write the rule, the above scheme dynamically
figures out the dependencies. Note then that dependencies vary over time
because of different branches a rule might take.

I want to reassure the community that this (nor the spreadsheet analogy
<g>) is not just my crazy idea. In 1992:

http://www.cs.utk.edu/~bvz/active-va...readsheet.html

"It is becoming increasingly evident that imperative languages are
unsuitable for supporting the complicated flow-of-control that arises in
interactive applications. This paper describes a declarative paradigm
for specifying interactive applications that is based on the spreadsheet
model of programing. This model includes multi-way constraints and
action procedures that can be triggered when constraints change the
values of variables."

Cells do not do multi-way constraints, btw.


My _guess_ is that a "multi-way constraint" is something like
what's above, where A depends on B and B depends on A?
Nor partial constraints. To
hard to program, because the system gets non-deterministic. That kinda
killed (well, left to a small niche) the whole research programme. I
have citations on that as well. :)

kenny

************************

David C. Ullrich

************************

David C. Ullrich
May 10 '06 #194
Followup-To: comp.lang.lisp

Bill Atkins <NO**********@rpi.edu> writes:
The cool thing about ITERATE is that it lets you express looping
concepts in a language designed explicitly for such a purpose, e.g.

(iter (for x in '(1 3 3))
(summing x)) => 7

(iter (for x in '(1 -3 2))
(finding x maximizing (abs x))) => -3

(iter (for x in '(a b c 1 d 3 e))
(when (symbolp x)
(collect x))) => (a b c d e)


While such macros indeed allow to generate efficient code, I don't
find these examples convincing in terms of readability. The same
examples in my language where iteration is based on higher order
functions are shorter and also clear:

Sum [1 3 3]
=> 7

[1 (-3) 2]->MaximumBy Abs
=> -3

[#a #b #c 1 #d 3 #e]->Select (_ %Is SYMBOL)
=> [#a #b #c #d #e]

--
__("< Marcin Kowalczyk
\__/ qr****@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
May 10 '06 #195
David C Ullrich asked:
Q: How do we ensure there are no loops in the dependencies?

Do we actually run the whole graph through some algorithm
to verify there are no loops?


The question you are asking is the dependency graph a "directed
acyclic graph" (commonly called a DAG)? One algorithm to determine if
it is, is called "topological sort". That algorithm tells you where
there are cyclces in your graph, if any, and also tells you the order
of the dependencies, i.e. if x is updated, what you have to update
downstream AND THE ORDER you have to perform the downstream
computations in. We use this algorithm for solving just the kind of
dataflow problems you are talking about in our circuit design tools.
Circuit designs have one-way dependencies that we want to sort and
resolve--similarly, we don't want cycles in our circuits except ones
that pass through clocked flip-flops. We solve such problems on
circuits with millions of gates, i.e. enough gates to represent the
CPU of your computer or a disk controller chip or a router.

I believe there are also algorithms that allow you to construct only
acyclic (the technical term for non-looping) graphs and don't require
you to enter the vertexes (verticies if you prefer) of the graph in
any specific order, and in the worst case you can always run the
topological sort on any graph and determine if the graph is cyclic.

The area is well-studied and you can find a variety of algorithms that
solve most interesting graph problems as they all occur over-and-over
in numerous diverse fields.

Hope this helps,
-Chris

************************************************** ***************************
Chris Clark Internet : co*****@world.std.com
Compiler Resources, Inc. Web Site : http://world.std.com/~compres
23 Bailey Rd voice : (508) 435-5016
Berlin, MA 01503 USA fax : (978) 838-0263 (24 hours)
------------------------------------------------------------------------------
May 10 '06 #196


sross wrote:
I do wonder what would happen to Cells if I ever want to support
multiple threads. Or in a parallel processing environment.

AFAIK It should be fine.
In LW, SBCL and ACL all bindings of dynamic variables are thread-local.


Ah, I was guilty of making an unspoken segue: the problem is not with
the *dependent* special variable, but with the sequentially growing
numeric *datapulse-id* ("the ID") that tells a cell if it needs to
recompute its value. The ID is not dynamically bound. If threads T1 and
T2 each execute a toplevel, imperative assignment, two threads will
start propagating change up the same dependency graph... <shudder>

Might need to specify a "main" thread that gets to play with Cells and
restrict other threads to intense computations but no Cells?

Actually, I got along quite a while without an ID, I just propagated to
dependents and ran rules. This led sometimes to a rule running twice for
one change and transiently taking on a garbage value, when the
dependency graph of a Cell had two paths back to some changed Cell.

Well, Cells have always been reengineered in the face of actual use
cases, because I am not really smart enough to work these things out in
the abstract. Or too lazy or something. Probably all three.

kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
May 10 '06 #197
M Jared Finder <ja***@hpalace.com> wrote:
...
Your reasoning, taken to the extreme, implies that an assembly language,
by virtue of having the fewest constructs, is the best designed language
Except that the major premise is faulty! Try e.g.
<http://docs.sun.com/app/docs/doc/817-5477/6mkuavhrf#hic> and count the
number of distinct instructions -- general purpose, floating point,
SIMD, MMX, SSE, SSE2, OS support... there's *hundreds*, each with its
own rules as to what operand(s) are allowed plus variants such as (e.g.)
cmovbe{w,l,q} for "conditional move if below or equal" for word, long,
quadword (no byte variant) -- but e.g cmpxchg{b,w,l,q} DOES have a byte
variant too, while setbe for "set if below or equal" ONLY has a byte
variant, etc, etc -- endless memorization;-).

When you set up your strawman arguments, try to have at least ONE of the
premises appear sensible, will you?-)

I never argued against keeping languages at a high level, of course
(that's why your so utterly unfounded argument would be a "strawman"
even if it WAS better founded;-).
prone, code. I think the advantages of anonymous functions: ... e) making the language simpler to implement


Adding one construct (e.g., in Python, having both def and lambda with
vast semantic overlap, rather than just one) cannot "make the language
simpler to implement" -- no doubt this kind of "reasoning" (?) is what
ended up making the instruction-set architecture of the dominant
families of CPUs so bizarre, intricate, and abstruse!-)
Alex
May 10 '06 #198
M Jared Finder wrote:
Alex Martelli wrote:
Stefan Nobis <sn****@gmx.de> wrote:
al***@mac.com (Alex Martelli) writes:

if anonymous functions are available, they're used in even more
cases where naming would help

Yes, you're right. But don't stop here. What about expressions? Many
people write very complex expression, that are hard to understand. A
good language should forbid these abuse and don't allow expressions
with more than 2 or maybe 3 operators!


That would _complicate_ the language (by adding a rule). I repeat what
I've already stated repeatedly: a good criterion for deciding which good
practices a language should enforce and which ones it should just
facilitate is _language simplicity_. If the enforcement is done by
adding rules or constructs it's probably not worth it; if the
"enforcements" is done by NOT adding extra constructs it's a double win
(keep the language simpler AND push good practices).


Your reasoning, taken to the extreme, implies that an assembly language,
by virtue of having the fewest constructs, is the best designed language
ever.


Assembly languages don't have the fewest constructs; kernel languages such
as Core ML or Kernel-Oz do. In any case, I didn't read Alex's point as
being that simplicity was the only criterion on which to make decisions
about what practices a language should enforce or facilitate; just
"a good criterion".

However, IMHO anonymous lambdas do not significantly increase the complexity
of the language or of programs, and they can definitely simplify programs in
functional languages, or languages that use them for control constructs.

--
David Hopwood <da******************@blueyonder.co.uk>
May 10 '06 #199


Boris Borcic wrote:
Ken Tilton wrote:
"Now if you are like most people, you think that means X. It does not."

As far as natural language and understanding are concerned, "to mean"
means conformity to what most people understand, Humpty Dumpties
notwithstanding.


Nonsense. You are confusing that quality of natural language with most
people's quality of being sloppy readers, or in your case, a sloppy
thinker. Misapplying an analogy is not a question of usage -- when I
said spreadsheet and they thought of spreadsheets, so far so good,
right? -- it just sloppiness and laziness.

I do it, too, all the time. :) Life is too short, we get by precisely by
using partial information.

You remind me of American educators recent (past several decades, that
is) history of apologizing for asking students to work and softening the
curriculum until they all get A's.

Here is another analogy. Sometimes people hit the gas and think they hit
the brake pedal. They crash around a parking lot pushing the gas pedal
down harder and harder. Did they take out the brake pedal to avoid that
confusion? No, they put an interlock between the brake and the ignition key.

Same thing. :)

kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
May 10 '06 #200

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

181
by: Tom Anderson | last post by:
Comrades, During our current discussion of the fate of functional constructs in python, someone brought up Guido's bull on the matter: http://www.artima.com/weblogs/viewpost.jsp?thread=98196 ...
30
by: Mike Meyer | last post by:
I know, lambda bashing (and defending) in the group is one of the most popular ways to avoid writing code. However, while staring at some Oz code, I noticed a feature that would seem to make both...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development projectplanning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.