From: Darmac.uy
Subject: functions vs. stored values
Date: 
Message-ID: <1149710583.984032.110360@y43g2000cwc.googlegroups.com>
Hi, I have some question in order to satisfy my curiosity.
I don't know if it's better to call a function continously or store the
result of it in a symbol and then operate with that symbol.

Look the next example:

;;This...
(append
   (list :ABSOLUTE (second (pathname-directory path)))
   (list "bin" (unique-directory-name))
   (rest (rest (rest (pathname-directory path)))))

;;Or this...

(setq pathname (second (pathname-directory path))
(append
   (list :ABSOLUTE pathname))
   (list "bin" (unique-directory-name))
   (rest (rest (rest pathname))))

You undestand my question? I'm not interested in this example only, I
ask in a more general scenario.
I forget to tell you that I'm working with CLisp.

Thanks in advance.

From: Kaz Kylheku
Subject: Re: functions vs. stored values
Date: 
Message-ID: <1149711875.044324.185160@h76g2000cwa.googlegroups.com>
Darmac.uy wrote:
> Hi, I have some question in order to satisfy my curiosity.
> I don't know if it's better to call a function continously or store the
> result of it in a symbol and then operate with that symbol.

You mean in a variable named by a symbol! You don't store things in
symbols.

> Look the next example:
>
> ;;This...
> (append
>    (list :ABSOLUTE (second (pathname-directory path)))
>    (list "bin" (unique-directory-name))
>    (rest (rest (rest (pathname-directory path)))))
>
> ;;Or this...
>
> (setq pathname (second (pathname-directory path))

Eww... Surely you mean:

  (let ((pathname (second (pathname-directory path))))
    (append ...))

You should not assign to a variable (with SETQ or any other assignment
operator) if that variable has not been previously defined.  The
consequences of doing so are undefined according to ANSI Common Lisp.

> (append
>    (list :ABSOLUTE pathname))
>    (list "bin" (unique-directory-name))
>    (rest (rest (rest pathname))))

You can do this differently, by the way:

  (list* :absolute pathname "bin" (unique-directory-name) (cdddr
pathname))

The LIST* function is like LIST, except that the last argument is a
list that is appended. I.e. it becomes the CDR of the last cons, rather
than the CAR.  When LIST* is called with two arguments, it's equivalent
to CONS.

This might be a good stylistic candidate for backquote as well:

  `(:absolute ,pathname "bin" ,(unique-directory-name) ,@(cddr
pathname))
From: Ron Garret
Subject: Re: functions vs. stored values
Date: 
Message-ID: <rNOSPAMon-E926D8.15201407062006@news.gha.chartermi.net>
In article <························@h76g2000cwa.googlegroups.com>,
 "Kaz Kylheku" <········@gmail.com> wrote:

> Darmac.uy wrote:
> > Hi, I have some question in order to satisfy my curiosity.
> > I don't know if it's better to call a function continously or store the
> > result of it in a symbol and then operate with that symbol.
> 
> You mean in a variable named by a symbol! You don't store things in
> symbols.

You can:

(let* ((s1 (gensym))
       (s2 s1))
  (setf (symbol-value s1) 123)  ; Note no quote
  (symbol-value s2))            ; Ditto

Here there is a value stored in a symbol, but no corresponding variable.

Granted this is probably not what the OP had in mind.

rg
From: Thibault Langlois
Subject: Re: functions vs. stored values
Date: 
Message-ID: <1149719836.733374.156840@g10g2000cwb.googlegroups.com>
Darmac.uy wrote:
> Hi, I have some question in order to satisfy my curiosity.
> I don't know if it's better to call a function continously or store the
> result of it in a symbol and then operate with that symbol.
>
> Look the next example:
>
> ;;This...
> (append
>    (list :ABSOLUTE (second (pathname-directory path)))
>    (list "bin" (unique-directory-name))
>    (rest (rest (rest (pathname-directory path)))))
>
> ;;Or this...
>
> (setq pathname (second (pathname-directory path))
> (append
>    (list :ABSOLUTE pathname))
>    (list "bin" (unique-directory-name))
>    (rest (rest (rest pathname))))
>
> You undestand my question? I'm not interested in this example only, I
> ask in a more general scenario.

Assuming "better" means faster, you can in general use the MEMOIZATION
package that let you experiment both ways without altering
your code. The MEMOIZED-TIME macro allows you to find what solution
is faster.

Thibault
From: Kaz Kylheku
Subject: Re: functions vs. stored values
Date: 
Message-ID: <1149724207.847474.219120@u72g2000cwu.googlegroups.com>
Thibault Langlois wrote:
> Assuming "better" means faster, you can in general use the MEMOIZATION
> package that let you experiment both ways without altering
> your code. The MEMOIZED-TIME macro allows you to find what solution
> is faster.

Caching the result of a repeated sub-expression in a temporary variable
isn't what is understood to be memoization.

Memoization means that the arguments of the function are used as a
search key to find a previously computed answer. This lookup cannot
possibly be as fast as simply pulling out the value from a local
variable!

These two approaches are not even competing optimization strategies;
the use of one doesn't preclude the other. Even if a function is
memoized, it may still makes sense to use a temporary in order to
eliminate redundant calls to it.
From: Thomas A. Russ
Subject: Re: functions vs. stored values
Date: 
Message-ID: <ymi1wu0czqe.fsf@sevak.isi.edu>
"Darmac.uy" <········@gmail.com> writes:

> Hi, I have some question in order to satisfy my curiosity.
> I don't know if it's better to call a function continously or store the
> result of it in a symbol and then operate with that symbol.

It really depends on a number of factors, one of which is how often you
refer to the results and how hard the function has to work to produce
the results.

> Look the next example:
> 
> ;;This...
> (append
>    (list :ABSOLUTE (second (pathname-directory path)))
>    (list "bin" (unique-directory-name))
>    (rest (rest (rest (pathname-directory path)))))

For accessors, the cost is probably very reasonable, since it would
normally be equivalent to an array access.  I personally would tend to
use a variable.  (See below).

By the way, LIST takes any number of arguments.  You don't need to
create these separate two-element lists and then append them.  There is
even a special LIST* form that appends in the last argument, which is
really what you need here.  Doing the separate LIST calls and the
implicit copy in APPEND is WAY more wasteful of resources than looking
up the pathname directory each time.  Try this instead:

(list* :ABSOLUTE (second (pathname-directory path))
       "bin" (unique-directory-name)
       (rest (rest (rest (pathname-directory path)))))

I presume you already know that PATH contains an absolute directory
path? 

> ;;Or this...
> 
> (setq pathname (second (pathname-directory path))
> (append
>    (list :ABSOLUTE pathname))
>    (list "bin" (unique-directory-name))
>    (rest (rest (rest pathname))))

Well, this starts out being flawed because you set the variable to the
second element of the directory list rather than to the list as a
whole.  That will make taking the triple REST fail.  Also, for this you
would want to use a local variable binding form and not SETQ.

(let ((directory (pathname-directory path)))
  (list* :ABSOLUTE (second directory) "bin" (unique-directory-name)
         (cdddr directory)))

I would also tend to use CDDDR over (REST (REST (REST ... or perhaps
even NTH-CDR.

> You undestand my question? I'm not interested in this example only, I
> ask in a more general scenario.

See initial comments.
For the case you present here, it is more about readability (and
conciseness, which can help readability, especially if you choose
variable names wisely).  I find the second one is marginally simpler for
me to follow, although I might consider putting each argument on a
separate line, to make the individual elements of the list stand out more.

(let ((directory (pathname-directory path)))
  (list* :ABSOLUTE
         (second directory)
         "bin"
         (unique-directory-name)
         (cdddr directory)))

> I forget to tell you that I'm working with CLisp.

Should apply to any Lisp system.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Bourguignon
Subject: Re: functions vs. stored values
Date: 
Message-ID: <87pshkjheb.fsf@thalassa.informatimago.com>
···@sevak.isi.edu (Thomas A. Russ) writes:

> For the case you present here, it is more about readability (and
> conciseness, which can help readability, especially if you choose
> variable names wisely).  I find the second one is marginally simpler for
> me to follow, although I might consider putting each argument on a
> separate line, to make the individual elements of the list stand out more.
>
> (let ((directory (pathname-directory path)))
>   (list* :ABSOLUTE
>          (second directory)
>          "bin"
>          (unique-directory-name)
>          (cdddr directory)))

We could mention here destructuring-bind:

(destructuring-bind (abs-or-rel top-level-dir ignored &rest remaining-dirs)
      (pathname-directory path)
   (declare (ignore abs-or-rel ignored))
   (list* :ABSOLUTE
          top-level-dir
          "bin"
          (unique-directory-name)
          remaing-dirs))

This could be more efficient, since destructuring-bind has to walk the
list only once, instead of repeating seconds/cdddr, etc, calls.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
The mighty hunter
Returns with gifts of plump birds,
Your foot just squashed one.
From: Barry Margolin
Subject: Re: functions vs. stored values
Date: 
Message-ID: <barmar-662FC5.20214107062006@comcast.dca.giganews.com>
In article <························@y43g2000cwc.googlegroups.com>,
 "Darmac.uy" <········@gmail.com> wrote:

> Hi, I have some question in order to satisfy my curiosity.
> I don't know if it's better to call a function continously or store the
> result of it in a symbol and then operate with that symbol.

As a general rule, accessing variables is faster than calling functions.  
So saving the value of a function call will generally improve 
performance.  And if the value has a logical role, and replaces a 
complex expression, it can also make the code easier to read and 
understand.  I personally try never to write the same expression twice 
within a block of code if it's convenient to save the value the first 
time.

In some cases the compiler may be able to tell that two nearby 
expressions are identical and will always return the same result, so it 
will automatically save the value for you.  This is called "common 
subexpression elimination".  For instance, if you do something like:

(list (* x y) (* x y))

and have the compiler's optimization settings at their highest level, it 
will probably compile it as if you'd written:

(let ((temp (* x y)))
  (list temp temp))

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***