declaration -- a declare expression; not evaluated
form -- a form
results -- the multiple values returned by the last form
Description:
update establishes an environment, for the evaluation of the given forms, in which var denotes the corresponding place. Prior to the evaluation of the forms, var is initialized by accessing the value stored in place. The forms may assign a new value to var. After the execution of the forms, the updated value of var is stored back into the place which val denotes. This is all done in such a way that place is evaluated only once.
If place is a multiple value place resulting from VALUES, then the corresponding var denotes the first subform.
When producing the initial values for the variables, the update macro evaluates the places (in left to right order) in an environment in which the variables do not yet have bindings. The variables are then bound in parallel to the resulting values.
The update* macro is different from update in this regard; it evaluates each place in an environment in which the prior variables already have a binding from the evaluaton of the prior places.
If the evaluation of forms is terminated by a dynamic control transfer, then the update of places does not take place.
Places are updated with new values in left to right order by means of store forms. If any store form initiates a dynamic control transfer, that store, and any subsequent stores, will not take place.
The multiple values produced by the last form are returned.
On 2009-11-04, Kaz Kylheku <kkylh...@gmail.com> wrote:
> Macro UPDATE, UPDATE*:
...
> If place is a multiple value place resulting from VALUES, then the > corresponding var denotes the first subform.
The additional places denoted by other subforms are ignored.
...
> Reference implementation:
...
Bugfix:
> collecting (car news) into all-news > - collecting setter into all-setters
+ collecting (if (cdr news) (second setter) setter) into all-setters
The assumption is that if two or more new-value variables emerge for a form from GET-SETF-EXPANSION, i.e. (cdr news) is not nil, then the form must be (VALUES ...), and so the setter form is also based on VALUES. We don't want the entire setter in that case, but just its subform which updates the first value. The assumption is that we ca pull that out using SECOND because the setter looks like (VALUES (SETF ...) (SETF ...)).
But it seems nonportable. 5.1.2.3 says
The storing form in the setf expansion of values returns as multiple values[2] the values of the store variables in step 2. That is, the number of values returned is the same as the number of place forms. This may be more or fewer values than are produced by the values-form
It is pinned down what the storing form returns, but not what it looks like, whereas the above hack depends on what the form looks like.
Looks like I will have to earnestly generate variables for the unused places, capture their values, etc.
On 2009-11-04, vippstar <vipps...@gmail.com> wrote:
> On Nov 4, 7:42?am, Kaz Kylheku <kkylh...@gmail.com> wrote: >> Macro UPDATE, UPDATE*: ><snip CLHS-like documentation>
> Hi Kaz, can you provide some examples for these macros?
Here is one.
Suppose you have three complicated expressions which all denote places.
You want to access these places and then compute new values for all three places based on the prior values, but only access the places once.
Here is the kick: there are dependencies; the new values are functions of the old.
(update ((a (complicated-place-a)) (b (complicated-place-b)) (c (complicated-place-c))) (psetf a (function-one a b c) b (function-two a b c) c (function-three a b c)))
With update, we can compute each new value as an arbitrary function of the prior values of all of the places, while evaluating each of the three place expressions just once.
If we define the functions like this:
(function-one a b c) -> b (function-two a b c) -> c (function-three a b c) -> a
Here is an impelmentation of ROTATEF(*) based on UPDATE, which shows that with UPDATE, you no longer have to know how to use GET-SETF-EXPANSION. (But you have to generate your own gensyms for the update variables!)
(defmacro my-rotatef (&rest forms) (if forms (let ((temps (loop for x in forms collecting (gensym)))) `(update (,@(mapcar #'list temps forms)) (psetf ,@(mapcan #'list temps (rest temps)) ,@(last temps) ,(first temps))))))
[2]> (macroexpand '(my-rotatef)) NIL ; T [3]> (macroexpand '(my-rotatef a)) (UPDATE ((#:G3111 A)) (PSETF #:G3111 #:G3111)) ; T [4]> (macroexpand '(my-rotatef a b)) (UPDATE ((#:G3112 A) (#:G3113 B)) (PSETF #:G3112 #:G3113 #:G3113 #:G3112)) ; T [5]> (macroexpand '(my-rotatef a b c d e)) (UPDATE ((#:G3114 A) (#:G3115 B) (#:G3116 C) (#:G3117 D) (#:G3118 E)) (PSETF #:G3114 #:G3115 #:G3115 #:G3116 #:G3116 #:G3117 #:G3117 #:G3118 #:G3118 #:G3114)) ; T
--- * A crippled ROTATEF which doesn't support multiple value places, and so cannot do (my-rotatef (values a b) (values c d) (values e f)).
Hi! Didn't test it yet. Looks like a nice work. What is wrong? 1. Name is wrong. "Update" is a very general word. It is very likely that everyone uses the name already in her library. So name clashes would occur. E.g. I know about ap5:update and I use it sometimes. So, people would rename your macro in their code and this is bad. 2. Did you really forget &env argument?
+--------------- | 1. Name is wrong. "Update" is a very general word. It is very | likely that everyone uses the name already in her library. | So name clashes would occur. ... +---------------
WITH-PLACES might be a good choice, by analogy to WITH-SLOTS or WITH-ACCESSORS.
-Rob
----- Rob Warnock <r...@rpw3.org> 627 26th Avenue <URL:http://rpw3.org/> San Mateo, CA 94403 (650)572-2607
* (Rob Warnock) <1e6dnfhzaY9rIm_XnZ2dnUVZ_qxi4...@speakeasy.net> : Wrote on Thu, 05 Nov 2009 06:07:18 -0600:
| budden <budden-l...@mail.ru> wrote: | +--------------- | | 1. Name is wrong. "Update" is a very general word. It is very | | likely that everyone uses the name already in her library. | | So name clashes would occur. ... | +--------------- | | WITH-PLACES might be a good choice, by analogy to WITH-SLOTS | or WITH-ACCESSORS.
Or SYMBOL-MACROLETF, As Kalle called it in his 2005 CLL post
> budden <budden-l...@mail.ru> wrote: > +--------------- >| 1. Name is wrong. "Update" is a very general word. It is very >| likely that everyone uses the name already in her library. >| So name clashes would occur. ... > +---------------
> WITH-PLACES might be a good choice, by analogy to WITH-SLOTS > or WITH-ACCESSORS.
WITH-SLOTS is a not a great analogy because under WITH-SLOTS, we really are working with the actual slots by means of local aliases. Not so in UPDATE; the local bindings are really just variables. Assigning to a variable does not instantly change the corresponding place. There is still justification for WITH, based on similarity to things like WITH-MUTEX-LOCK, WITHOUT-INTERRUPTS, where there is some hidden effect inserted before and after the code.
On Thu, 5 Nov 2009 22:37:22 +0000 (UTC), Kaz Kylheku <kkylh...@gmail.com> said:
> ... > I vote for UPDATEF.
Hmmm, it doesn't just update, it also retrieves; READ-WRITE-F is ugly, though, perhaps something with a "modify" root (to match DEFINE-MODIFY-MACRO)?
---Vassil.
-- baguetton, n. a newly discovered particle that can travel in time in the vicinity of large experimental facilities and cause faults in them (cf. boson)
On 2009-11-06, Vassil Nikolov <vniko...@pobox.com> wrote:
> On Thu, 5 Nov 2009 22:37:22 +0000 (UTC), Kaz Kylheku <kkylh...@gmail.com> said: >> ... >> I vote for UPDATEF.
> Hmmm, it doesn't just update, it also retrieves; READ-WRITE-F is
Not necessarily. In the abstract semantics
(update ((a place)) (setf a 42))
accesses place, stores it in a, allows a to be modified, and then stores the value a back into place. But actually, the prior access can be optimized away. The variable A is not live on entry into the body, because the first use of A is to clobber it. Since A is not live, place need not be accessed to retrieve the value for A.
The construction, in this case, expresses that A denotes PLACE, and that PLACE is modified with a value which is not computed by accessing the prior value of PLACE.
> ugly, though, perhaps something with a "modify" root (to match > DEFINE-MODIFY-MACRO)?
The word update usually implies that the new value is related to the old one (though possibly without obtaining the old value from the place being updated).
Example of update implying a read: ``cvs update'' (incorporates local changes by merging, rather than blindly replacing the local files with fresh checkouts). Sometimes a read-modify-write is called an update. In C programming, it is sometims said that the fopen "w+" mode opens a file for update: both reading and writing.
Examples of ``update'' not implying prior read: the controller object, updates the model, which updates the display; or: the local replica of the database is updated from the master server.
The word modify, on the other hand, does not imply at all that the new value is related to the old. If you initialize some storage to all zeros, that's a modification, but probably won't be called an update.
If anything, ``modify'' places even less emphasis on the possibility of prior access than ``update''.
Kaz Kylheku <kkylh...@gmail.com> writes: > WITH-SLOTS is a not a great analogy because under WITH-SLOTS, we > really are working with the actual slots by means of local aliases. > Not so in UPDATE; the local bindings are really just > variables. Assigning to a variable does not instantly change the > corresponding place.
So this is the difference between your UPDATE and the SYMBOL-MACROLETF which Madhu refered to and which works directly with the places, no? When should I use which? Does it make a difference at all, given a Sufficiently Smart Compiler?
Nicolas Neuss <lastn...@math.uni-karlsruhe.de> writes: >> WITH-SLOTS is a not a great analogy because under WITH-SLOTS, we >> really are working with the actual slots by means of local aliases. >> Not so in UPDATE; the local bindings are really just >> variables. Assigning to a variable does not instantly change the >> corresponding place.
> So this is the difference between your UPDATE and the SYMBOL-MACROLETF > which Madhu refered to and which works directly with the places, no? > When should I use which? Does it make a difference at all, given a > Sufficiently Smart Compiler?
Hmm, thinking a little more about it the difference is clear. But I am not yet convinced that I would like code depending on this difference.
* Nicolas Neuss <87my30vy63....@ma-patru.mathematik.uni-karlsruhe.de> : Wrote on Fri, 06 Nov 2009 09:45:56 +0100:
| Nicolas Neuss <lastn...@math.uni-karlsruhe.de> writes: | |>> WITH-SLOTS is a not a great analogy because under WITH-SLOTS, we |>> really are working with the actual slots by means of local aliases. |>> Not so in UPDATE; the local bindings are really just |>> variables. Assigning to a variable does not instantly change the |>> corresponding place. |> |> So this is the difference between your UPDATE and the SYMBOL-MACROLETF |> which Madhu refered to and which works directly with the places, no? |> When should I use which? Does it make a difference at all, given a |> Sufficiently Smart Compiler? | | Hmm, thinking a little more about it the difference is clear. But I am | not yet convinced that I would like code depending on this difference.
I don't think do you have a valid use case for UPDATE/UPDATEF*. The only thing it adds is unconditionally writing ALL the places at the end of execution of BODY, which is of doubtful value. Why this `value-add' is suspect is becauyse BODY can always use temporary variables to keep temporary results.
I would prefer to use Kalle Olavi Niemitalo's SYMBOL-MACROLETF instead, and update the places via regular SETQ/SETF/PSETF etc. No confusion, nothing is hidden unerneath covers.
Others (jimka 2006 etc.) have used the names UPDATE/UPDATEF* for functions which actually do Emacs-Lisp (cl.el)'s CALLF CALLF2.
On the whole I think Kaz Kylhelku's definitions for UPDATE/UPDATEF* have "shady semantics" and limited use --- more like a problem in search of a solution
* Nicolas Neuss <87my30vy63....@ma-patru.mathematik.uni-karlsruhe.de> : Wrote on Fri, 06 Nov 2009 09:45:56 +0100:
| Nicolas Neuss <lastn...@math.uni-karlsruhe.de> writes: | |>> WITH-SLOTS is a not a great analogy because under WITH-SLOTS, we |>> really are working with the actual slots by means of local aliases. |>> Not so in UPDATE; the local bindings are really just |>> variables. Assigning to a variable does not instantly change the |>> corresponding place. |> |> So this is the difference between your UPDATE and the SYMBOL-MACROLETF |> which Madhu refered to and which works directly with the places, no? |> When should I use which? Does it make a difference at all, given a |> Sufficiently Smart Compiler? | | Hmm, thinking a little more about it the difference is clear. But I am | not yet convinced that I would like code depending on this difference.
I don't think do you have a valid use case for UPDATE/UPDATEF*. The only thing it adds is unconditionally writing ALL the places at the end of execution of BODY, which is of doubtful value. Why this `value-add' is suspect is because BODY can always use temporary variables to keep temporary results.
I would prefer to use Kalle Olavi Niemitalo's SYMBOL-MACROLETF instead, and update the places via regular SETQ/SETF/PSETF etc. No confusion, nothing is hidden underneath covers.
Others (jimka 2006 etc.) have used the names UPDATE/UPDATEF* for functions which actually do Emacs-Lisp (cl.el)'s CALLF CALLF2.
On the whole I think Kaz Kylhelku's definitions for UPDATE/UPDATEF* have "shady semantics" and limited use --- more like a solution in search of a problem
Can we really always call setter code twice if we called retriever code once? If we can, I'd prefer symbol-macroletf. It gives us a freedom to call updater zero or more times.
If setf semantics supposes we can only call updater zero or one time, I'd prefer Kaz's update (with some othen name, of course).
budden <budden-l...@mail.ru> writes: > Can we really always call setter code twice if we called retriever > code once?
When it's the setter form returned by get-setf-expansion, yes. The getter form returned by get-setf-expansion should be without side effect, and the setter form returned by get-setf-expansion should have only one side effect, that of modifying the place, AFAIK.
>> Can we really always call setter code twice if we called retriever >> code once?
> When it's the setter form returned by get-setf-expansion, yes. The > getter form returned by get-setf-expansion should be without side > effect, and the setter form returned by get-setf-expansion should have > only one side effect, that of modifying the place, AFAIK.
What if a getter and setter access a memory-mapped register?
Kaz Kylheku <kkylh...@gmail.com> writes: > On 2009-11-08, Pascal J. Bourguignon <p...@informatimago.com> wrote: >> budden <budden-l...@mail.ru> writes:
>>> Can we really always call setter code twice if we called retriever >>> code once?
>> When it's the setter form returned by get-setf-expansion, yes. The >> getter form returned by get-setf-expansion should be without side >> effect, and the setter form returned by get-setf-expansion should have >> only one side effect, that of modifying the place, AFAIK.
> What if a getter and setter access a memory-mapped register?
This cannot count as a side effect, since virtual memory or cache behavior preserves the state of the process, by definition (I don't mean the state of the kernel about the process).
If you mean a time attack, then I could provide you a kernel that will give you the same access time when the data is in cache or physical memory as when it it is not.
>> On 2009-11-08, Pascal J. Bourguignon <p...@informatimago.com> wrote: >>> budden <budden-l...@mail.ru> writes:
>>>> Can we really always call setter code twice if we called retriever >>>> code once?
>>> When it's the setter form returned by get-setf-expansion, yes. The >>> getter form returned by get-setf-expansion should be without side >>> effect, and the setter form returned by get-setf-expansion should have >>> only one side effect, that of modifying the place, AFAIK.
>> What if a getter and setter access a memory-mapped register?
> This cannot count as a side effect, since virtual memory or cache > behavior preserves the state of the process, by definition (I don't > mean the state of the kernel about the process).
Since when would you access a memory mapped I/O register through cached virtual memory?
Kaz Kylheku <kkylh...@gmail.com> writes: > On 2009-11-08, Pascal J. Bourguignon <p...@informatimago.com> wrote: >> Kaz Kylheku <kkylh...@gmail.com> writes:
>>> On 2009-11-08, Pascal J. Bourguignon <p...@informatimago.com> wrote: >>>> budden <budden-l...@mail.ru> writes:
>>>>> Can we really always call setter code twice if we called retriever >>>>> code once?
>>>> When it's the setter form returned by get-setf-expansion, yes. The >>>> getter form returned by get-setf-expansion should be without side >>>> effect, and the setter form returned by get-setf-expansion should have >>>> only one side effect, that of modifying the place, AFAIK.
>>> What if a getter and setter access a memory-mapped register?
>> This cannot count as a side effect, since virtual memory or cache >> behavior preserves the state of the process, by definition (I don't >> mean the state of the kernel about the process).
> Since when would you access a memory mapped I/O register through cached > virtual memory?
Oh, you mean *I/O* register. You didn't write that first.
(Some processors with a lot of registers, or with register stacks, do store some of their registers in memory.)
In any case, I never noted any provision for such a kind of place in CLHS... I'd expect an implementation providing memory mapped I/O register places to have a specific construct in the SYSTEM package or some other implementation specific package.