From: WoodHacker
Subject: Efficiency
Date: 
Message-ID: <1133440670.618193.275530@g14g2000cwa.googlegroups.com>
When using slot-value and the same value is used more than once in a
form, is it more efficient to  use a LET to extract that value (and use
the local variable repeatedly) or does it not make a difference?   In
fact, is using LET ineffient?    Or is the difference so slight it
doesn't really make a difference in most normal programming?

From: Arthur Lemmens
Subject: Re: Efficiency
Date: 
Message-ID: <op.s03wa7uowpmq96@news.xs4all.nl>
WoodHacker <·······@comcast.net> wrote:

> When using slot-value and the same value is used more than once in a
> form, is it more efficient to  use a LET to extract that value (and use
> the local variable repeatedly) or does it not make a difference?

I expect that using a LET is more efficient.  I feel that it usually
makes the code easier to read as well, so that's a double bonus.

> In fact, is using LET ineffient?

Executive summary: if using LET is inefficient, you have a bad compiler.
From: Ulrich Hobelmann
Subject: Re: Efficiency
Date: 
Message-ID: <3v8bg0F14cc1sU1@individual.net>
WoodHacker wrote:
> When using slot-value and the same value is used more than once in a
> form, is it more efficient to  use a LET to extract that value (and use
> the local variable repeatedly) or does it not make a difference?   In
> fact, is using LET ineffient?    Or is the difference so slight it
> doesn't really make a difference in most normal programming?

I'd expect slot-value to have some overhead (sure), but most importantly 
I assume that it might run into aliasing problems.  So if the Lisp 
compiler can't know if something inbetween the slot-value calls might 
change the slot, it has to make two calls.

Whatever you do, LET is definitely the most efficient it can get.  Only 
in a very stupid compiler would the LET waste a couple of bytes per 
variable (if the variable is unused after a while), but in every other 
case you are guaranteed that there are no more function calls needed to 
access its value.

Even for cases like expressions where most modern compilers find the 
common subexpressions on their own, I'm a LET advocate because it IMHO 
makes programs more readable (less complexity per line).

Also check out WITH-SLOTS and WITH-ACCESSORS, but I'm not sure how their 
performance is.  PCL (p. 212 footnote) says that they just macroexpand 
into normal (slot-value) things, so maybe it's best to use LET if you're 
sure it's too slow otherwise ;)

-- 
The road to hell is paved with good intentions.
From: ···············@yahoo.com
Subject: Re: Efficiency
Date: 
Message-ID: <1133451955.188882.56690@g14g2000cwa.googlegroups.com>
I thought
  (with-slots (a) x ...)
would expand into
  (let ((a (slot-value x 'a))) ...)
So I was suprised by the following result (Allegro 7.0):

(macroexpand
  '(with-slots (a) x
    (+ a 1)
    (+ a 2)
    (+ a 3)))

(LET ((#:G4 X))
  (DECLARE (SYSTEM::VARIABLE-REBINDING X #:G4))
  #:G4
  (+ (SLOT-VALUE #:G4 'A) 1)
  (+ (SLOT-VALUE #:G4 'A) 2)
  (+ (SLOT-VALUE #:G4 'A) 3))
T

Back to the OP's question: wouldn't it be more efficient to make the
last part
  (LET ((#:G5 (SLOT-VALUE #:G4 'A)))
    (+ #:G5 1)
    ...)
From: André Thieme
Subject: Re: Efficiency
Date: 
Message-ID: <1133452795.680922.167710@g49g2000cwa.googlegroups.com>
How much sense would it make if with-slots bound the slot-value with a
let?

(with-slots (a) x
  (setf a 10))

...

(format t "value: ~d" (slot-value x 'a))  ; would this print 10?
From: ·········@cern.ch
Subject: Re: Efficiency
Date: 
Message-ID: <yzou0dsiyvg.fsf@cern.ch>
> I thought
>   (with-slots (a) x ...)
> would expand into
>   (let ((a (slot-value x 'a))) ...)

Did you perhaps overlook SETF as the obvious reason why your
LET-expansion cannot work in the general case?

(with-slots (a) x (setf a ...)) -> (setf (slot-value x 'a) ...)

Ole
From: Edi Weitz
Subject: Re: Efficiency
Date: 
Message-ID: <uacfk3hl8.fsf@agharta.de>
On 1 Dec 2005 07:45:55 -0800, ···············@yahoo.com wrote:

> I thought
>   (with-slots (a) x ...)
> would expand into
>   (let ((a (slot-value x 'a))) ...)

See the CLHS for WITH-SLOTS[1] where it says that

  "The macro WITH-SLOTS translates an appearance of the slot name as a
   variable into a call to SLOT-VALUE."

So, your expansion above would be illegal.

This makes sense if, say, you have an :AROUND method for
SLOT-VALUE-USING-CLASS[2] which syncs the slots of your object with an
underlying SQL database.  The LET expansion would then change the
semantics of the code:

  (let ((a (slot-value x 'a)))
    ;;; do something else 
    ;;; at the same time another thread modifies the database
    (work-with a)  ;;; <-- uh, value not up to date

See also the "Notes" where a "typical" expansion with SYMBOL-MACROLET
is shown.

Cheers,
Edi.

[1] <http://www.lispworks.com/documentation/HyperSpec/Body/m_w_slts.htm>
[2] <http://www.lisp.org/mop/dictionary.html#slot-value-using-class>

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: ···············@yahoo.com
Subject: Re: Efficiency
Date: 
Message-ID: <1133533520.656382.165420@g44g2000cwa.googlegroups.com>
Thanks to all for pointing out my oversight.
From: WoodHacker
Subject: Re: Efficiency
Date: 
Message-ID: <1133534961.445953.26370@g49g2000cwa.googlegroups.com>
Thanks, everybody, for insight.     For some reason or other I got it
into my head that LET must be less efficient (just imagining it is a
lot easier than trying to prove it).    The code certainly is easier to
read using LET.

Thanks again... 

Bill
From: Coby Beck
Subject: Re: Efficiency
Date: 
Message-ID: <%j%jf.230724$ir4.20924@edtnps90>
"WoodHacker" <·······@comcast.net> wrote in message 
····························@g49g2000cwa.googlegroups.com...
> Thanks, everybody, for insight.     For some reason or other I got it
> into my head that LET must be less efficient (just imagining it is a
> lot easier than trying to prove it).    The code certainly is easier to
> read using LET.

I know Pascal expressed it very well, but it can't be emphasized enough that 
you should write your code for clarity and correctness and only when 
everything is working fine but you need to make things faster should you 
optimize any code for speed.  And then it should only be the specific parts 
you have identified through profiling that get tweaked.

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Pascal Bourguignon
Subject: Re: Efficiency
Date: 
Message-ID: <87r78xhs52.fsf@thalassa.informatimago.com>
"WoodHacker" <·······@comcast.net> writes:

> When using slot-value and the same value is used more than once in a
> form, is it more efficient to  use a LET to extract that value (and use
> the local variable repeatedly) or does it not make a difference?   In
> fact, is using LET ineffient?    Or is the difference so slight it
> doesn't really make a difference in most normal programming?

It depends on the compiler.   When you write let, the compiler may
remove it anyways.  So in general, using LET adds no cost.



[348]> (disassemble (compile (defun h (o) (print (slot-value o 'a)) (print (slot-value o 'a)))))

Disassembly of function H
(CONST 0) = A
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
11 byte-code instructions:
0     (LOAD&PUSH 1)
1     (CONST&PUSH 0)                      ; A
2     (CALLS2&PUSH 62)                    ; SLOT-VALUE
4     (PUSH-UNBOUND 1)
6     (CALLS1 132)                        ; PRINT
8     (LOAD&PUSH 1)
9     (CONST&PUSH 0)                      ; A
10    (CALLS2&PUSH 62)                    ; SLOT-VALUE
12    (PUSH-UNBOUND 1)
14    (CALLS1 132)                        ; PRINT
16    (SKIP&RET 2)
NIL
[349]> 

Here, the lexical scope is not created at run-time, but slot-value is
called only once; so in clisp it is better to use LET to fetch the
slot-value:

[346]> (disassemble (compile (defun f (o) (let ((a (slot-value o 'a))) (print a) (print a)))))

Disassembly of function F
(CONST 0) = A
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
10 byte-code instructions:
0     (LOAD&PUSH 1)
1     (CONST&PUSH 0)                      ; A
2     (CALLS2&PUSH 62)                    ; SLOT-VALUE
4     (LOAD&PUSH 0)
5     (PUSH-UNBOUND 1)
7     (CALLS1 132)                        ; PRINT
9     (LOAD&PUSH 0)
10    (PUSH-UNBOUND 1)
12    (CALLS1 132)                        ; PRINT
14    (SKIP&RET 3)
NIL


Here, LET is entirely removed:

[347]> (disassemble (compile (defun g (o) (let ((a 42)) (print a) (print a)))))
WARNING in G :
variable O is not used.
Misspelled or missing IGNORE declaration?

Disassembly of function G
(CONST 0) = 42
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
7 byte-code instructions:
0     (CONST&PUSH 0)                      ; 42
1     (PUSH-UNBOUND 1)
3     (CALLS1 132)                        ; PRINT
5     (CONST&PUSH 0)                      ; 42
6     (PUSH-UNBOUND 1)
8     (CALLS1 132)                        ; PRINT
10    (SKIP&RET 2)
NIL
[348]> 


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Our users will know fear and cower before our software! Ship it!
Ship it and let them flee like the dogs they are!"
From: Pascal Costanza
Subject: Re: Efficiency
Date: 
Message-ID: <3v8jndF14qcasU1@individual.net>
WoodHacker wrote:
> When using slot-value and the same value is used more than once in a
> form, is it more efficient to  use a LET to extract that value (and use
> the local variable repeatedly) or does it not make a difference?   In
> fact, is using LET ineffient?    Or is the difference so slight it
> doesn't really make a difference in most normal programming?

It is not important whether it is a slight difference or not. The more 
important question is: Does it matter even if it is not a slight 
difference? A program typically spends 80% of its execution in 20% of 
the code (or so, that's just a rule of thumb). So it's unlikely that 
even a big difference has an important impact on the overall execution 
of your programs.

General rules for efficiency:

- Don't optimize your programs too soon.

- Only optimize the parts of your program that you know will have an 
effect on the overall performance. You can find those parts by using 
profilers.

- Focus on better algorithms / program organization rather than 
micro-optimizations.

- Better algorithms: If you find yourself iterating over a list several 
times, think about how you can change the algorithm so that it iterates 
over that list just once.

- Better program organization: Rather than optimizing certain parts of 
your program, think about how to reorganize your programs so that they 
cannot affect the overall performance anymore. For example, caching 
helps in many cases because it avoids to run costly parts of your 
program more often than necessary.


Consequentially, it's better to focus on expressing your programs in a 
way that makes them better understandable and maintainable because this 
probably affects later stages of program development much more (evolving 
it to a new version, etc.). A LET can make your programs better 
understandable because it gives you the opportunity to give good, 
meaningful names to intermediate values. However, it's probably not a 
good idea to do this for each and every intermediate result, so try to 
strike a good balance here. Only worry about efficiency if you're sure 
that it really matters.


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/