help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: questioning let


From: Andreas Röhler
Subject: Re: questioning let
Date: Wed, 24 Feb 2010 18:44:53 +0100
User-agent: Thunderbird 2.0.0.19 (X11/20081227)

Pascal J. Bourguignon wrote:
> Andreas Roehler <andreas.roehler@online.de> writes:
> 
>> Hi,
>>
>> behaviour of the example code below puzzles me. Would
>> expect setting of arg by external function, but inside
>> `let', recognised. But remains `1'.
>>
>> (defun arg-setting ()
>>   (interactive)
>>   (let ((arg 1))
>>     (message "%s" arg)
>>     (arg-extern arg)
>>     (message "%s" arg)))
>>
>> (defun arg-extern (arg)
>>   (setq arg (1- arg)))
>>
>> Any help?
> 
> 
> let is equivalent to lambda:
> 
>   (let ((a 1) (b 2)) (list a b)) <=> ((lambda (a b) (list a b)) 1 2)
> 
> defun is binding a lambda to a function cell:
> 
>   (defun f (a b) (list a b))
>        <=> (setf (symbol-function 'f) (lambda (a b) (list a b)))
> 
> Therefore you can see that calling a function defined by defun is a let
> in disguise.
> 
> 
> If you transformed your code following these equivalences, you would
> notice that you have actually TWO variables named arg, one as parameter
> of the function arg-extern, and one as variable in the let in
> arg-setting.
> 
> The setq in arg-extern will modify only the variable parameter of
> arg-extern.  Because they have the same name, this variable hides the
> one defined in the let of arg-setting.  There's no way to access it from
> within arg-extern.
> 
> 
> If they had a different name, you could modify a variable from an outer
> dynamic scope from an inner dynamic scope, because in emacs all the
> variables are dynamic.  But it is considered very bad form to do so:
> this is a big side effect, and what's more, one that depends on the call
> chain.  You should avoid side effects, to increase the readability and
> debugability of your code.  Therefore you should avoid setq and setf.
> Try to write pure function, never try to modify a variable.
> 
> One way to write your code would be:
> 
> (defun do-what-you-need-to-do-with (arg)
>    )
> 
> (defun arg-binding ()
>   (interactive)
>   (let ((arg 1))
>      (message "before arg = %s" arg)
>      (let ((arg (arg-extern arg)))
>        (message "after arg = %s" arg)
>        (do-what-you-need-to-do-with arg))
>      (message "original arg = %s" arg)))
> 
> (defun arg-extern (arg)
>    (message "arg-extern before arg = %s" arg)
>    (message "arg-extern returns = %s" (1- arg))
>    (1- arg))
> 
> before arg = 1
> arg-extern before arg = 1
> arg-extern returns = 0
> after arg = 0
> original arg = 1
> 
> 
> If you need a global variable (perhaps because you need to keep some
> data across command invocations), the I would advise to distringuish it
> from the other by giving it a name surrounded by stars: *var*.  Then, it
> will have a different name, and won't be shadowed (inadvertantly) by
> inner lets, defuns or lambdas.
> 
> (defvar *var* 42)
> 
> (defun arg-extern (arg)
>    (message "arg-extern before arg = %s" arg)
>    (setf *var* (1- arg))
>    (message "arg-extern returns = %s" *var*)
>    *var*)
> 
> (arg-binding)
> *var*  --> 0
> 
> 


Hi Pascal,

thanks a lot for these helpful instructions.
Next days it should go here:

http://repo.or.cz/w/elbb.git

Andreas

BTW every Emacs hacker is invited recording it's stuff there
It's about playing with git too...





reply via email to

[Prev in Thread] Current Thread [Next in Thread]