Combining test and assignment

Hello, this is very spur of the moment, and so I apologize if I am missing the obvious reasons for why this would be horribly dumb. I sometimes find myself annoyed that I cannot access the result of an expression in a conditional statememt. Consider: if spam(): ... frobulate the return value of spam() ... else: ... value too low to frobulate ... In order to frobulate spam(), either need to call it again in the indented block, or preassign: x = spam() if x: ... frobulate x ... The first option is usually inefficient, and the second feels ugly to me because something relevant to a block is happening outside it and its header. Instead, I'd love to be able to: if spam() as x: ... frobulate x ... Further, there are two reasons this seems a particularly good fit in Python: - There is a _syntactic_ precedent, or at least great similarity to the 'with' statement. - Because calls in Python return None if they don't ex- plicitly return anything else, there is no "can't assign void to x" to worry about. I haven't given much thought to scoping, particularly for else clauses, yet, at least not enough to make up my mind. The other question is if this reads good "as English" or needs to be 'if spam() then as x:', or if that's even an issue. Thoughts? Best regards, Eike

This suggestion (i.e. embedded assignment in while and if headers) has been made several times, and always come to a grinding halt on one simple problem: it isn't expressive enough. The current idiom is this : x = EXPR if predicate(x): # Do something Given a value and a predicate, this allows you to execute code conditionally based on whether or not the predicate is true. Simple embedded assignment, though, only works when the predicate is just "bool" - as soon as the condition differs from the value you want to access, you need to revert to the existing idiom *anyway*. Given the non-trivial costs of adding new syntax, that gets the idea put into the "not worth the hassle" bucket. The obvious escalation of the suggestion is to adopt "(EXPR as NAME)" as a general purpose embedded assignment expression. However, this idea has problems of its own: 1. In with statements and exception handlers, 'as' does *not* denote ordinary assignment. In the former case, the name is bound to the result of the EXPR.__enter__() call, in the latter to the exception instance that was actually caught. If assignment expressions were added, these could become a rather subtle trap (especially since many __enter__() methods just return self) 2. Generator expressions and the various forms of comprehension create new scopes to avoid leaking iteration variables, so, if embedded assignments were to do anything useful there, additional forms like "(EXPR as nonlocal NAME)" and "(EXPR as global NAME)" would be needed. (And, in the nonlocal case, would still require that the name already be defined in the containing scope) 3. Adding assignment expressions would mean having two ways to perform assignments at the statement level (either using the existing statement form or using the new expression form) To date, nobody has been interested enough in the latter idea to put together a formal PEP and reference implementation for python-dev's consideration, and the former idea has been informally rejected several times due to the lack of generality. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 1/22/2012 4:48 AM, Nick Coghlan wrote:
Actually, just to be clear, in the use case I had in mind spam() is returning a numeric value. That satisfies a truth test and is still useful in other ways (but I assume you are actually on the same page, hence the quotation marks around bool). Another case I come across frequently is with the re module, where re.match() returns either None or a MatchObject. if re.match(pattern, string) as m: ... make use of the match object ... Anyway, thank you for a comprehensive reply and recap of the history.
I thought a bit about what Python offers today in terms of built-in tools to approximate what I want. My first thought was to try and abuse context managers, but aside from being horribly ugly, a with statement also can't prevent its body from being run, it seems. Another, possibly better way is to modify locals(), i.e.: if test(expr, 'var'): ... do stuff ... Where the test function returns the expression but also stores its results in locals()['var']. I wonder if a function like this (with a better name obviously) would have a place in the stdlib somewhere, or is it too much of a limited-use hack?
Cheers, Nick.
-- Best regards, Eike Hein

On Sat, Jan 21, 2012 at 8:05 PM, Eike Hein <sho@eikehein.com> wrote:
That doesn't actually work (unless you happen to be writing code in module-level scope, where globals are locals): http://docs.python.org/library/functions.html#locals : "Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter." Cheers, Chris

On 1/22/2012 5:11 AM, Chris Rebert wrote:
That doesn't actually work (unless you happen to be writing code in module-level scope, where globals are locals):
Right, brainfart - the locals() of test aren't the locals of the callsite obviously :). And nonlocal won't work due to the lack of an existing binding in the outer scope. Can anyone think of another way to do an assignment and a truth test in the same expression with today's tools?
Yep, I was actually confusing this with vars() in terms of whether modifying its return value is considered kosher. Thanks. Sadly that makes the above harder ...
Cheers, Chris
-- Best regards, Eike Hein

On Jan 22, 2:18 pm, Eike Hein <s...@eikehein.com> wrote:
I've seen something similar to this used before: class Holder(object): def __call__(self, value): self.value = value return self def __eq__(self, val): return self.value == val __req__ = __eq__ from random import choice some_func = lambda: choice(['a','b','c']) holder = Holder() if holder(some_func()) == 'a': print 'A' elif holder == 'b': print 'B' elif holder == 'c': print 'C' As you can see, it still requires a value to be defined before the conditional, though :)

On Sat, Jan 21, 2012 at 11:05 PM, Eike Hein <sho@eikehein.com> wrote:
Perhaps. Does bool(spam()) produce the right answer? Or did you need to work with 0, or ignore -1?
Another, possibly better way is to modify locals(), i.e.:
Well, not locals directly, but the following was inspired by the quantification thread. You still need to declare the Var before the test expression, but the declaration can be just a placeholder. x=Var() ... if Var(expr): -jJ

Nick Coghlan wrote:
I dislike assignment as an expression, and am glad that Python doesn't have it. Even though the form "expr as name" avoids the common C gotcha, I am -1 on adding it to Python. I believe it is an unnatural way of writing that obscures the code rather than simplifies it. (Sometimes, shorter is not better.) For example, when writing code, I might start off by thinking: if spam() != 'ham': frobulate(spam()) Then I would apply DRY and factor out the call to spam: x = spam() if x != 'ham': frobulate(x) This matches my thought processes and corresponds to how you might naturally describe the algorithm in English: Let x equal spam(). If x != 'ham', then frobulate(x). The important thing is that you name the thing you care about before using it. I think this is a very natural way of writing: first you give the thing you care about a name, then you refer to it by name. Assignment as an expression feels unnatural to me: if spam() as x != 'ham': frobulate(x) doesn't really correspond to any natural English order. The assignment is dropped in the middle of another clause: If -- let x = spam() -- x != 'ham', then frobulate(x). It saves a line, but is not a natural way of writing for me. I would not like to read code written that way. Assignment as an expression also lends itself to writing buggy code like this: while spam() as x and ham() as y: frobulate(x) glommify(y) which is wrong, because y won't be defined if x has a true value. The alternative would require defeating the short-circuit nature of "and", which would be bad. Perhaps the only thing going for it is that it would allow list comprehensions to not repeat themselves: # instead of this [frobulate(x) for x in seq if frobulate(x) > 0] # you could have this [y for x in seq if frobulate(x) as y > 0] Although I prefer to use an inner map: [y for y in map(frobulate, seq) if y > 0] # use itertools.imap in Python2 -- Steven

I think one could use the same new construct I proposed for one of the recent lengthy discussions. For your convenience, I copy this below, in disregards of quoting style as it provides an overarching reply to this thread. You could use sample <generator expression> as x: # do something with x break else: # do something else here the generator expression would be "spam()" sample y for y in (spam(),) if cond(y) as x: (...) or allow a short form sample y for spam() if cond(y) as x: (...) I really think this expressions could add a lot to Python's expressiveness. As an important note, in the case below, the difference to just a "for loop" or "generator" would be that <generator expression> is re-evaluated from scratch every time the loop returns to the sample statement. This is what I think would set it apart besides providing extra uses otherwise. Admittedly, it is a very complicated construct. Longer than most good English sentences. (for which those above are not good examples) -Alexander -------- Original Message -------- Subject: Re: [Python-ideas] Fwd: quantifications, and tuple patterns Date: Mon, 16 Jan 2012 22:00:52 -0600 From: Alexander Heger <python@2sn.net> To: python-ideas@python.org Dear Tom,
I had the same thought going through the thread, but I think the problem here would be that any is a function that returns a Boolean value. You could add a key parameter to return something else, say a tuple of a truth value and a sample ( any( ..., sample = True) ) but that could break because 1) "any" could be another function in the context, 2) while would need to deal with special return values in this case A suggestion to replace the "while any" case is sample <generator expression> as x: # do something with x ("sample" may not be the best keyword choice) From the discussion so far I do not see how to easily avoid having a new keyword specifically, your example would become sample v for v in vertices if v.incoming_count == 0 as v1: # do things with v1 In case you only want one sample, you could add the break statement sample db.query(page_name=page_name) as page: render_template(page) break else: error404() -Alexander On 01/21/2012 10:51 PM, Steven D'Aprano wrote:

On Jan 21, 2012, at 6:51 PM, Steven D'Aprano wrote:
I dislike assignment as an expression, and am glad that Python doesn't have it. Even though the form "expr as name" avoids the common C gotcha, I am -1 on adding it to Python.
I find it interesting that Go-lang follows your intuition and so added the "assignment first" conditional. Here's an example from their docs: if x := f(); x < y { return x } else if x > z { return z } else { return y } In Python, we'd just put the x = f() first, but in Go, putting the assignment into the conditional affects the scoping of things. The x goes out of scope once the if is over.

On 22 January 2012 04:51, Steven D'Aprano <steve@pearwood.info> wrote:
While in general I agree with you, there *is* a natural reading of this: "if spam() isn't 'ham', frobulate it" The fact that you have to choose a name is because computer languages have to be more explicit than natural languages, and can't deal with the implicit referent involved in the English usage of "it". The need for assignment comes from the need for a name. You could actually deal with the if-or-while-expression-assignment case by defining a special variable __it__ to mean the value of the condition in the containing if or while expression, but it has all the same lack of generality issues as any proposal that limits itself to if/while conditions. And short of explicitly marking the expression somehow, you can't generalise any further. Paul.

On Sun, Jan 22, 2012 at 10:04 PM, Paul Moore <p.f.moore@gmail.com> wrote:
Yeah, I agree characterising embedded assignments as a more formal equivalent of natural language pronouns is a useful way to think about them. However, one of the other reasons that these proposals tend not to go anywhere is that they ultimately boil down to some people hating the idea of having to write something they personally think of as one operation as a sequence of operations instead. Like multi-line lambdas, adding embedded assignments doesn't really increase the power and expressivity of the language as a whole all that much - it just moves the dividing line between what can be cleanly expressed in a single statement and what must be expressed as multiple statements a bit. Embedded assignments *do* address some instances of the loop-and-a-half problem, but even there, the more general idiom of "while True:" + "if exit_cond: break" can handle the situation quite happily. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

22.01.12 14:04, Paul Moore написав(ла):
Kotlin (http://confluence.jetbrains.net/display/Kotlin/Kotlin) has "it": names filter {it.startsWith("A")} sortby {it} map {it.toUpperCase()} foreach {print(it)}

On Sun, Jan 22, 2012 at 4:04 AM, Paul Moore <p.f.moore@gmail.com> wrote:
This is reminiscent of Perl's $_ variable, which represents the "current topic". http://www.perl.com/pub/2002/10/30/topic.html Cheers, Chris

On Sun, 22 Jan 2012 12:04:48 +0000 Paul Moore <p.f.moore@gmail.com> wrote:
Others have pointed out that they can. My favorite example is Paul Graham's anaphoric macros, which bind the evaluated expression to "it" and then call the associated blocks. Two things of note in his discussion (http://dunsmor.com/lisp/onlisp/onlisp_18.html). First, he provides versions for the other conditional execution statements. Second, the one that is *most* used - he claims even more often than the regular version - is for while. <mike -- Mike Meyer <mwm@mired.org> http://www.mired.org/ Independent Software developer/SCM consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

On Sun, Jan 22, 2012 at 12:04:48PM +0000, Paul Moore wrote:
That's not quite the same, because there is an implicit assignment, which is ambiguous. Are you frobulating spam(), or 'ham'? Without having domain-specific knowledge, guessing is risky. E.g. this is easy to interpret: If the cat is on the mat, feed it. since we know that cats can eat but mats don't. But this is not: If the cat is on the mat, put it in the box. So I stand by my claim: there is no natural English analog of an explicit assignment in the middle of the clause.
Actually they can. Hypertalk had at least two such implicit variables, "it" and "the result", with different rules for when each were set. I'm sure other languages have done similar. But really, it's not a great idea. The possibility of ambuiguity and confusion is too great. And what happens when you have two or more such variables? And in practice, you end up assigning "it" to a named variable anyway, otherwise it will be overwritten before you get around to using it. The CPython interactive interpreter already has one implicit variable, _ which holds the result of the previous command. I don't think Python the language should follow. -- Steven

On Sun, Jan 22, 2012 at 5:58 PM, Steven D'Aprano <steve@pearwood.info> wrote:
So I stand by my claim: there is no natural English analog of an explicit assignment in the middle of the clause.
There isn't a natural English analogue of explicit assignment at all. English doesn't have variables or anything like them. It has names, but these names cannot be redefined -- try telling someone "Bill is my cat", followed by, "Bill is my dad", and they'll give you a queer look. And then they'll interpret this as two different Bills, rather than just one that was "redefined" to mean something else, and if you refer to Bill again they will ask "which one?" There are unnatural phrases that work like assignment, and those same phrases can be used unnaturally to refer to assignment within an "if" as well. "Let the letter X refer to Y", "now let the letter X refer to Z", "if foo, which the letter X will now refer to, is a piece of ham, ..." But that's kind of silly. More generally, I'm not convinced programming has to fit into "natural" English. It should be expressible, yes, but it doesn't have to be idiomatic English. "Programming is an unnatural act. " (Perlis) (Perhaps it must be idiomatic in Dutch?) -- Devin

On 1/22/2012 7:04 AM, Paul Moore wrote:
The best I can come up with is "if x, which is the result of calling 'spam', is not equal to 'ham', then frobulate x". But I am not going to call that 'natural' speech. More normal would be "Get the result of spam(). If it it not 'ham', then frobulate it." As others noted, the pronoun 'it' is a substitute for local names. But doing that for more than one object or value gets awkward. "Get ham() and spam(). If the first is less than the second, multiply the first by the second plus 3." "Former' and 'latter' are another pair of standardized pronoun-like names. The math device of temporary names is really handy. -- Terry Jan Reedy

This suggestion (i.e. embedded assignment in while and if headers) has been made several times, and always come to a grinding halt on one simple problem: it isn't expressive enough. The current idiom is this : x = EXPR if predicate(x): # Do something Given a value and a predicate, this allows you to execute code conditionally based on whether or not the predicate is true. Simple embedded assignment, though, only works when the predicate is just "bool" - as soon as the condition differs from the value you want to access, you need to revert to the existing idiom *anyway*. Given the non-trivial costs of adding new syntax, that gets the idea put into the "not worth the hassle" bucket. The obvious escalation of the suggestion is to adopt "(EXPR as NAME)" as a general purpose embedded assignment expression. However, this idea has problems of its own: 1. In with statements and exception handlers, 'as' does *not* denote ordinary assignment. In the former case, the name is bound to the result of the EXPR.__enter__() call, in the latter to the exception instance that was actually caught. If assignment expressions were added, these could become a rather subtle trap (especially since many __enter__() methods just return self) 2. Generator expressions and the various forms of comprehension create new scopes to avoid leaking iteration variables, so, if embedded assignments were to do anything useful there, additional forms like "(EXPR as nonlocal NAME)" and "(EXPR as global NAME)" would be needed. (And, in the nonlocal case, would still require that the name already be defined in the containing scope) 3. Adding assignment expressions would mean having two ways to perform assignments at the statement level (either using the existing statement form or using the new expression form) To date, nobody has been interested enough in the latter idea to put together a formal PEP and reference implementation for python-dev's consideration, and the former idea has been informally rejected several times due to the lack of generality. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 1/22/2012 4:48 AM, Nick Coghlan wrote:
Actually, just to be clear, in the use case I had in mind spam() is returning a numeric value. That satisfies a truth test and is still useful in other ways (but I assume you are actually on the same page, hence the quotation marks around bool). Another case I come across frequently is with the re module, where re.match() returns either None or a MatchObject. if re.match(pattern, string) as m: ... make use of the match object ... Anyway, thank you for a comprehensive reply and recap of the history.
I thought a bit about what Python offers today in terms of built-in tools to approximate what I want. My first thought was to try and abuse context managers, but aside from being horribly ugly, a with statement also can't prevent its body from being run, it seems. Another, possibly better way is to modify locals(), i.e.: if test(expr, 'var'): ... do stuff ... Where the test function returns the expression but also stores its results in locals()['var']. I wonder if a function like this (with a better name obviously) would have a place in the stdlib somewhere, or is it too much of a limited-use hack?
Cheers, Nick.
-- Best regards, Eike Hein

On Sat, Jan 21, 2012 at 8:05 PM, Eike Hein <sho@eikehein.com> wrote:
That doesn't actually work (unless you happen to be writing code in module-level scope, where globals are locals): http://docs.python.org/library/functions.html#locals : "Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter." Cheers, Chris

On 1/22/2012 5:11 AM, Chris Rebert wrote:
That doesn't actually work (unless you happen to be writing code in module-level scope, where globals are locals):
Right, brainfart - the locals() of test aren't the locals of the callsite obviously :). And nonlocal won't work due to the lack of an existing binding in the outer scope. Can anyone think of another way to do an assignment and a truth test in the same expression with today's tools?
Yep, I was actually confusing this with vars() in terms of whether modifying its return value is considered kosher. Thanks. Sadly that makes the above harder ...
Cheers, Chris
-- Best regards, Eike Hein

On Jan 22, 2:18 pm, Eike Hein <s...@eikehein.com> wrote:
I've seen something similar to this used before: class Holder(object): def __call__(self, value): self.value = value return self def __eq__(self, val): return self.value == val __req__ = __eq__ from random import choice some_func = lambda: choice(['a','b','c']) holder = Holder() if holder(some_func()) == 'a': print 'A' elif holder == 'b': print 'B' elif holder == 'c': print 'C' As you can see, it still requires a value to be defined before the conditional, though :)

On Sat, Jan 21, 2012 at 11:05 PM, Eike Hein <sho@eikehein.com> wrote:
Perhaps. Does bool(spam()) produce the right answer? Or did you need to work with 0, or ignore -1?
Another, possibly better way is to modify locals(), i.e.:
Well, not locals directly, but the following was inspired by the quantification thread. You still need to declare the Var before the test expression, but the declaration can be just a placeholder. x=Var() ... if Var(expr): -jJ

Nick Coghlan wrote:
I dislike assignment as an expression, and am glad that Python doesn't have it. Even though the form "expr as name" avoids the common C gotcha, I am -1 on adding it to Python. I believe it is an unnatural way of writing that obscures the code rather than simplifies it. (Sometimes, shorter is not better.) For example, when writing code, I might start off by thinking: if spam() != 'ham': frobulate(spam()) Then I would apply DRY and factor out the call to spam: x = spam() if x != 'ham': frobulate(x) This matches my thought processes and corresponds to how you might naturally describe the algorithm in English: Let x equal spam(). If x != 'ham', then frobulate(x). The important thing is that you name the thing you care about before using it. I think this is a very natural way of writing: first you give the thing you care about a name, then you refer to it by name. Assignment as an expression feels unnatural to me: if spam() as x != 'ham': frobulate(x) doesn't really correspond to any natural English order. The assignment is dropped in the middle of another clause: If -- let x = spam() -- x != 'ham', then frobulate(x). It saves a line, but is not a natural way of writing for me. I would not like to read code written that way. Assignment as an expression also lends itself to writing buggy code like this: while spam() as x and ham() as y: frobulate(x) glommify(y) which is wrong, because y won't be defined if x has a true value. The alternative would require defeating the short-circuit nature of "and", which would be bad. Perhaps the only thing going for it is that it would allow list comprehensions to not repeat themselves: # instead of this [frobulate(x) for x in seq if frobulate(x) > 0] # you could have this [y for x in seq if frobulate(x) as y > 0] Although I prefer to use an inner map: [y for y in map(frobulate, seq) if y > 0] # use itertools.imap in Python2 -- Steven

I think one could use the same new construct I proposed for one of the recent lengthy discussions. For your convenience, I copy this below, in disregards of quoting style as it provides an overarching reply to this thread. You could use sample <generator expression> as x: # do something with x break else: # do something else here the generator expression would be "spam()" sample y for y in (spam(),) if cond(y) as x: (...) or allow a short form sample y for spam() if cond(y) as x: (...) I really think this expressions could add a lot to Python's expressiveness. As an important note, in the case below, the difference to just a "for loop" or "generator" would be that <generator expression> is re-evaluated from scratch every time the loop returns to the sample statement. This is what I think would set it apart besides providing extra uses otherwise. Admittedly, it is a very complicated construct. Longer than most good English sentences. (for which those above are not good examples) -Alexander -------- Original Message -------- Subject: Re: [Python-ideas] Fwd: quantifications, and tuple patterns Date: Mon, 16 Jan 2012 22:00:52 -0600 From: Alexander Heger <python@2sn.net> To: python-ideas@python.org Dear Tom,
I had the same thought going through the thread, but I think the problem here would be that any is a function that returns a Boolean value. You could add a key parameter to return something else, say a tuple of a truth value and a sample ( any( ..., sample = True) ) but that could break because 1) "any" could be another function in the context, 2) while would need to deal with special return values in this case A suggestion to replace the "while any" case is sample <generator expression> as x: # do something with x ("sample" may not be the best keyword choice) From the discussion so far I do not see how to easily avoid having a new keyword specifically, your example would become sample v for v in vertices if v.incoming_count == 0 as v1: # do things with v1 In case you only want one sample, you could add the break statement sample db.query(page_name=page_name) as page: render_template(page) break else: error404() -Alexander On 01/21/2012 10:51 PM, Steven D'Aprano wrote:

On Jan 21, 2012, at 6:51 PM, Steven D'Aprano wrote:
I dislike assignment as an expression, and am glad that Python doesn't have it. Even though the form "expr as name" avoids the common C gotcha, I am -1 on adding it to Python.
I find it interesting that Go-lang follows your intuition and so added the "assignment first" conditional. Here's an example from their docs: if x := f(); x < y { return x } else if x > z { return z } else { return y } In Python, we'd just put the x = f() first, but in Go, putting the assignment into the conditional affects the scoping of things. The x goes out of scope once the if is over.

On 22 January 2012 04:51, Steven D'Aprano <steve@pearwood.info> wrote:
While in general I agree with you, there *is* a natural reading of this: "if spam() isn't 'ham', frobulate it" The fact that you have to choose a name is because computer languages have to be more explicit than natural languages, and can't deal with the implicit referent involved in the English usage of "it". The need for assignment comes from the need for a name. You could actually deal with the if-or-while-expression-assignment case by defining a special variable __it__ to mean the value of the condition in the containing if or while expression, but it has all the same lack of generality issues as any proposal that limits itself to if/while conditions. And short of explicitly marking the expression somehow, you can't generalise any further. Paul.

On Sun, Jan 22, 2012 at 10:04 PM, Paul Moore <p.f.moore@gmail.com> wrote:
Yeah, I agree characterising embedded assignments as a more formal equivalent of natural language pronouns is a useful way to think about them. However, one of the other reasons that these proposals tend not to go anywhere is that they ultimately boil down to some people hating the idea of having to write something they personally think of as one operation as a sequence of operations instead. Like multi-line lambdas, adding embedded assignments doesn't really increase the power and expressivity of the language as a whole all that much - it just moves the dividing line between what can be cleanly expressed in a single statement and what must be expressed as multiple statements a bit. Embedded assignments *do* address some instances of the loop-and-a-half problem, but even there, the more general idiom of "while True:" + "if exit_cond: break" can handle the situation quite happily. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

22.01.12 14:04, Paul Moore написав(ла):
Kotlin (http://confluence.jetbrains.net/display/Kotlin/Kotlin) has "it": names filter {it.startsWith("A")} sortby {it} map {it.toUpperCase()} foreach {print(it)}

On Sun, Jan 22, 2012 at 4:04 AM, Paul Moore <p.f.moore@gmail.com> wrote:
This is reminiscent of Perl's $_ variable, which represents the "current topic". http://www.perl.com/pub/2002/10/30/topic.html Cheers, Chris

On Sun, 22 Jan 2012 12:04:48 +0000 Paul Moore <p.f.moore@gmail.com> wrote:
Others have pointed out that they can. My favorite example is Paul Graham's anaphoric macros, which bind the evaluated expression to "it" and then call the associated blocks. Two things of note in his discussion (http://dunsmor.com/lisp/onlisp/onlisp_18.html). First, he provides versions for the other conditional execution statements. Second, the one that is *most* used - he claims even more often than the regular version - is for while. <mike -- Mike Meyer <mwm@mired.org> http://www.mired.org/ Independent Software developer/SCM consultant, email for more information. O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

On Sun, Jan 22, 2012 at 12:04:48PM +0000, Paul Moore wrote:
That's not quite the same, because there is an implicit assignment, which is ambiguous. Are you frobulating spam(), or 'ham'? Without having domain-specific knowledge, guessing is risky. E.g. this is easy to interpret: If the cat is on the mat, feed it. since we know that cats can eat but mats don't. But this is not: If the cat is on the mat, put it in the box. So I stand by my claim: there is no natural English analog of an explicit assignment in the middle of the clause.
Actually they can. Hypertalk had at least two such implicit variables, "it" and "the result", with different rules for when each were set. I'm sure other languages have done similar. But really, it's not a great idea. The possibility of ambuiguity and confusion is too great. And what happens when you have two or more such variables? And in practice, you end up assigning "it" to a named variable anyway, otherwise it will be overwritten before you get around to using it. The CPython interactive interpreter already has one implicit variable, _ which holds the result of the previous command. I don't think Python the language should follow. -- Steven

On Sun, Jan 22, 2012 at 5:58 PM, Steven D'Aprano <steve@pearwood.info> wrote:
So I stand by my claim: there is no natural English analog of an explicit assignment in the middle of the clause.
There isn't a natural English analogue of explicit assignment at all. English doesn't have variables or anything like them. It has names, but these names cannot be redefined -- try telling someone "Bill is my cat", followed by, "Bill is my dad", and they'll give you a queer look. And then they'll interpret this as two different Bills, rather than just one that was "redefined" to mean something else, and if you refer to Bill again they will ask "which one?" There are unnatural phrases that work like assignment, and those same phrases can be used unnaturally to refer to assignment within an "if" as well. "Let the letter X refer to Y", "now let the letter X refer to Z", "if foo, which the letter X will now refer to, is a piece of ham, ..." But that's kind of silly. More generally, I'm not convinced programming has to fit into "natural" English. It should be expressible, yes, but it doesn't have to be idiomatic English. "Programming is an unnatural act. " (Perlis) (Perhaps it must be idiomatic in Dutch?) -- Devin

On 1/22/2012 7:04 AM, Paul Moore wrote:
The best I can come up with is "if x, which is the result of calling 'spam', is not equal to 'ham', then frobulate x". But I am not going to call that 'natural' speech. More normal would be "Get the result of spam(). If it it not 'ham', then frobulate it." As others noted, the pronoun 'it' is a substitute for local names. But doing that for more than one object or value gets awkward. "Get ham() and spam(). If the first is less than the second, multiply the first by the second plus 3." "Former' and 'latter' are another pair of standardized pronoun-like names. The math device of temporary names is really handy. -- Terry Jan Reedy
participants (14)
-
alex23
-
Alexander Heger
-
Carl M. Johnson
-
Chris Rebert
-
Devin Jeanpierre
-
Eike Hein
-
Jakob Bowyer
-
Jim Jewett
-
Mike Meyer
-
Nick Coghlan
-
Paul Moore
-
Serhiy Storchaka
-
Steven D'Aprano
-
Terry Reedy