From: Brian Adkins
Subject: Porting Ruby snippet to Lisp
Date: 
Message-ID: <LzLKh.8089$B7.6250@bigfe9>
I'm early in the process of learning Lisp, but I wanted to get a feel 
for what a port of a snippet of Ruby code (part of a Rails controller) 
would look like down the road. It was chosen mostly at random, but it 
actually makes for a pretty good example IMO because of the language 
features represented.

I gave porting it a shot (see bottom), but my current knowledge is 
lacking, so it's quite a botched up job. One particular sticking point 
was the best way to handle the implicit creation of logged-in-user in 
line 19 of the Lisp version (line 10 of the Ruby version) (wrap the when 
in a let?). Is there a way to handle dealing with hash tables more 
concisely?

If an experienced Lisper could give me some pointers, that would be 
great. I know there has to be a much better way.

  1 class AuthenticateController < ApplicationController
  2   def register
  3     if request.get?
  4       logger.info session[:original_url]
  5     else
  6       @user = User.new(params[:user])
  7       if @user.save
  8         session[:user_id] = @user.id
  9         redirect_to_original
10       elsif (logged_in_user = User.login(
11           params[:user][:user_name], params[:user][:password]))
12         session[:user_id] = logged_in_user.id
13         redirect_to_original
14       end
15     end
16   end

17   def redirect_to_original
18     original_url = session[:original_url] ||
19       {:controller => 'account', :action => 'index'}
20     session[:original_url] = nil
21     redirect_to(original_url)
22   end
23 end

request is an accessor of the superclass returning a request object
logger is an accessor of the superclass returning a logger object
session is an accessor of the superclass returning a hash
session[:key] returns the value associated with the :key from the hash
params is an accessor of the superclass returning a hash
@user is an instance variable of AuthenticateController

1. Begin definition of class AuthenticateController with a superclass of 
ApplicationControler

2. Begin definition of method register

3. Invoke the get? predicate on request

4. Invoke the info method on logger passing the value associated with 
the :original_url key from the session hash

6. Construct an instance of User and assign to instance variable @user

7. Invoke save method on @user return true if successful

8. Store id attribute of @user in hash

9. method call

10/11. params[:user] returns a hash; invoke class method, login, with 
results from hash and assign boolean result to logged_in_user local 
which is implicitly created at this point

19. { ... } creates a hash object with :key => value

21. Invoke superclass method redirect_to

Here's my attempt:

  1 (defclass application-controller ()
  2   ((logger :reader logger)
  3    (params :reader params)
  4    (request :reader request)
  5    (session :reader session)))

  6 (defclass authenticate-controller (application-controller)
  7   ((user :accessor user)))

  8 (defmethod register ((x authenticate-controller))
  9   (if (getp (request x))
10     (info (logger x) (gethash :original-url (session x)))
11     (progn
12       (setf
13         (user x)
14         (make-instance 'user :user-name (gethash :user (params x))))
15       (if (save (user x))
16         (progn
17           (setf (gethash :user-id (session x)) (id (user x)))
18           (redirect-to-original x))
19         (when (setf logged-in-user ???)
20           (setf (gethash :user-id (session x)) (id logged-in-user))
21           (redirect-to-original))))))

22 (defmethod redirect-to-original ((x authenticate-controller))
23   (let ((original-url
24           (or
25             (gethash :original-url (session x))
26             (let ((temp (make-hash-table)))
27               (setf (gethash :controller "account"))
28               (setf (gethash :action "index"))))))
29     (setf (gethash :original-url (session x)))
30     (redirect-to x original-url)))

From: Dan Bensen
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <etgfj6$v3u$1@wildfire.prairienet.org>
Brian Adkins wrote:
> was the best way to handle the implicit creation of logged-in-user in 
> line 19 of the Lisp version (line 10 of the Ruby version) (wrap the when 
> in a let?).

Yes, that's the standard approach, as long as you don't need
logged-in-user afterward.

> Is there a way to handle dealing with hash tables more 
> concisely?

Just start the function with
   (let ((session (session x))
         (params  (params  x)))

If that's still too long, you could define your own sethash macro,
unless someone else knows a way to call the underlying function
directly.  It doesn't look like you're supposed to, though.

-- 
Dan
www.prairienet.org/~dsb
From: Matthias Benkard
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <1174158752.547339.285660@l77g2000hsb.googlegroups.com>
Hi,

> Just start the function with
>    (let ((session (session x))
>          (params  (params  x)))

Isn't that what WITH-ACCESSORS is for?

Matthias
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <ovXKh.18143$Wc.12113@bignews3.bellsouth.net>
Matthias Benkard wrote:
> Hi,
> 
>> Just start the function with
>>    (let ((session (session x))
>>          (params  (params  x)))
> 
> Isn't that what WITH-ACCESSORS is for?
> 
> Matthias
> 

Interesting thx. Had I made it through chapter 17 of PCL, I would've 
spotted that little gem :) I think I just need to progress through the 
texts that I have, and it will be much clearer - I'm just impatient.
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <nwUKh.5536$nV1.525@bignews6.bellsouth.net>
Dan Bensen wrote:
> Brian Adkins wrote:
>> was the best way to handle the implicit creation of logged-in-user in 
>> line 19 of the Lisp version (line 10 of the Ruby version) (wrap the 
>> when in a let?).
> 
> Yes, that's the standard approach, as long as you don't need
> logged-in-user afterward.
> 
>> Is there a way to handle dealing with hash tables more concisely?
> 
> Just start the function with
>   (let ((session (session x))
>         (params  (params  x)))
> 
> If that's still too long, you could define your own sethash macro,
> unless someone else knows a way to call the underlying function
> directly.  It doesn't look like you're supposed to, though.
> 

Thanks, that does reduce the verbosity a bit. I suppose the best I can 
do with respect to getting close to conciseness of hash[:key] = value 
would be something like (sethash :key hash value)

(defmacro sethash (key hash value)
   `(setf (gethash ,key ,hash) ,value))

I would think (sethash hash key value) would be more natural since the 
object being operated on is hash, but for consistency with gethash the 
above probably makes more sense. I imagine that macro has been defined 
by many individuals.

(setf (gethash :key hash) value)
(sethash :key hash value)
hash[:key] = value

The macro knocked 7 characters off, now if I can just knock 7 more off 
:) Actually 9, but I usually surround = with spaces for readability, so 
it's fair to leave them in for comparison.

I use hashes enough that it might warrant defining geth and seth macros.
From: Zach Beane
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m3lkhvhlkb.fsf@unnamed.xach.com>
Brian Adkins <·················@gmail.com> writes:

> Thanks, that does reduce the verbosity a bit. I suppose the best I can
> do with respect to getting close to conciseness of hash[:key] = value
> would be something like (sethash :key hash value)
> 
> (defmacro sethash (key hash value)
>    `(setf (gethash ,key ,hash) ,value))
> 
> I would think (sethash hash key value) would be more natural since the
> object being operated on is hash, but for consistency with gethash the
> above probably makes more sense. I imagine that macro has been defined
> by many individuals.

I doubt it. It's not a win to throw away the generality of the setf
form because it saves a few keystrokes.
 
> I use hashes enough that it might warrant defining geth and seth macros.

It seems like quite a few languages optimize their syntax to make hash
table manipulation concise. That's nice when hash tables are a good
fit for a specific problem, but it has the downside of making less
concise (but better fitting) solutions feel somehow excessively
verbose or unnatural.

That is, when your language has highly optimized syntax for regular
expressions and hash tables, there's a strong temptation to solve
most problems with regular expressions and hash tables, even when they
aren't a very good fit.

Zach
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <YoVKh.5542$nV1.733@bignews6.bellsouth.net>
Zach Beane wrote:
> Brian Adkins <·················@gmail.com> writes:
> 
>> Thanks, that does reduce the verbosity a bit. I suppose the best I can
>> do with respect to getting close to conciseness of hash[:key] = value
>> would be something like (sethash :key hash value)
>>
>> (defmacro sethash (key hash value)
>>    `(setf (gethash ,key ,hash) ,value))
>>
>> I would think (sethash hash key value) would be more natural since the
>> object being operated on is hash, but for consistency with gethash the
>> above probably makes more sense. I imagine that macro has been defined
>> by many individuals.
> 
> I doubt it. It's not a win to throw away the generality of the setf
> form because it saves a few keystrokes.

Why do you feel "the generality of the setf form" is being "thrown 
away"? The task at hand is a specific one - to associate a key and value 
in a hash. What do you feel the benefits of the following:

(setf (gethash :key hash) value)

are compared to:

(seth :key hash value)

given the task?

>  
>> I use hashes enough that it might warrant defining geth and seth macros.
> 
> It seems like quite a few languages optimize their syntax to make hash
> table manipulation concise. 

Why do you think that is?

> That's nice when hash tables are a good
> fit for a specific problem, but it has the downside of making less
> concise (but better fitting) solutions feel somehow excessively
> verbose or unnatural.
> 
> That is, when your language has highly optimized syntax for regular
> expressions and hash tables, there's a strong temptation to solve
> most problems with regular expressions and hash tables, even when they
> aren't a very good fit.

Possibly, but when you actually have a nail, a hammer is darn handy ;)

> Zach
> 
From: Juho Snellman
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <slrnevo997.n5b.jsnell@sbz-30.cs.Helsinki.FI>
Brian Adkins <·················@gmail.com> wrote:
> Why do you feel "the generality of the setf form" is being "thrown 
> away"? The task at hand is a specific one - to associate a key and value 
> in a hash. What do you feel the benefits of the following:
>
> (setf (gethash :key hash) value)
>
> are compared to:
>
> (seth :key hash value)
>
> given the task?

It doesn't extend to:

  (incf (gethash :key hash) value)
  (push (gethash :key hash) value)
  (rotatef (gethash :key hash)
           (gethash :other-key hash))
  (setf (values (gethash :key hash)
                (gethash :key other-hash))
	(something-returning-two-values))

etc.

-- 
Juho Snellman
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <XKVKh.5548$nV1.1130@bignews6.bellsouth.net>
Juho Snellman wrote:
> Brian Adkins <·················@gmail.com> wrote:
>> Why do you feel "the generality of the setf form" is being "thrown 
>> away"? The task at hand is a specific one - to associate a key and value 
>> in a hash. What do you feel the benefits of the following:
>>
>> (setf (gethash :key hash) value)
>>
>> are compared to:
>>
>> (seth :key hash value)
>>
>> given the task?
> 
> It doesn't extend to:
> 
>   (incf (gethash :key hash) value)
>   (push (gethash :key hash) value)
>   (rotatef (gethash :key hash)
>            (gethash :other-key hash))
>   (setf (values (gethash :key hash)
>                 (gethash :key other-hash))
> 	(something-returning-two-values))
> 
> etc.
> 

Thanks for the ideas on various ways to use (gethash), but I don't see 
how having a (seth) macro detracts from that. I expect I'll need to call 
  (seth) frequently enough that typing 22 chars instead of 32 chars each 
time will be useful.

I can see how introducing a proliferation of macros simply to save some 
typing has the disadvantage of introducing new semantic elements that 
have to either be memorized or looked up, but if they're used frequently 
enough, it would seem to be a benefit to me. Maybe I'll feel differently 
when I have more Lisp experience under my belt.
From: Richard M Kreuter
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <87mz2b8oyu.fsf@progn.net>
Brian Adkins <·················@gmail.com> writes:

> I expect I'll need to call (seth) frequently enough that typing 22
> chars instead of 32 chars each time will be useful.

You might do so less than you'd expect, but only if you stick with
Lisp.  The main issue, I think, is that you'll find yourself only
rarely manipulating hash tables explicitly in Lisp.

First, there's little no reason to use a hash table if you know in
advance all the keys the table will contain.  You should use a class
or maybe a structure for objects like this: your code will be clearer,
and maybe also faster.  In your program, for example, you seem to
represent the session as a hash table in which you only look up a
couple of keywords.  Why not make this a class?

Second, there are several ways of associating objects in CL: there are
hash tables, association lists, property lists, and so forth.  While
hash tables may have better performance in some cases, collections
built from conses tend to have some other nice properties: structure
sharing, multiple associations to a single key, printability,
independence of the collection from searching predicates, capacity to
be used as argument lists, etc.  Partly because of this variety of
association techniques, but mostly because it's just good style, most
Lispers will wrap the actual lookup routine in (maybe setf'able)
functions; if the collection to be operated on is locally "obvious",
the lookup functions might make the collection argument optional,
defaulting to a special variable.

Third, in some other languages it's common to see hash tables used as
global namespaces (global hash tables in which constant-valued keys
are looked up are a sign of this).  You can do this in Lisp, but it's
perhaps more idiomatic to have a setf'able lookup function of one
argument as an interface to the namespace; have a look at FIND-CLASS
for an example.  This can save a bit of keyboarding, but the real win
is the abstraction: programs that want to look things up in a
namespace will be insulated from changes to the namespace's
implementation.

As you can see, hash tables aren't the only game in town.  If you're
willing to believe that hash tables are manipulated directly more
seldomly in CL than elsewhere, then maybe you'll accept that many
Lispers don't find there to be a big win for such a shorthand.

--
RmK
From: Winston Smith
Subject: hot-hash macro (critism welcome)
Date: 
Message-ID: <slrnevogi1.v30.ga41h@localhost.localdomain>
On 2007-03-17, Brian Adkins <·················@gmail.com> wrote:
> Juho Snellman wrote:
>> Brian Adkins <·················@gmail.com> wrote:
>>> Why do you feel "the generality of the setf form" is being "thrown 
>>> away"? The task at hand is a specific one - to associate a key and value 
>>> in a hash. What do you feel the benefits of the following:
>>>
>>> (setf (gethash :key hash) value)
>>>
>>> are compared to:
>>>
>>> (seth :key hash value)
>>>
>>> given the task?
>> 
>> It doesn't extend to:
>> 
>>   (incf (gethash :key hash) value)
>>   (push (gethash :key hash) value)
>>   (rotatef (gethash :key hash)
>>            (gethash :other-key hash))
>>   (setf (values (gethash :key hash)
>>                 (gethash :key other-hash))
>> 	(something-returning-two-values))
>> 
>> etc.
>> 
>
> Thanks for the ideas on various ways to use (gethash), but I don't see 
> how having a (seth) macro detracts from that. I expect I'll need to call 
>   (seth) frequently enough that typing 22 chars instead of 32 chars each 
> time will be useful.
>
> I can see how introducing a proliferation of macros simply to save some 
> typing has the disadvantage of introducing new semantic elements that 
> have to either be memorized or looked up, but if they're used frequently 
> enough, it would seem to be a benefit to me. Maybe I'll feel differently 
> when I have more Lisp experience under my belt.

You'll want to wait for criticism from the experts before adopting this,
but I wrote this macro to save typing while preserving the functionality
of setf, incf, etc.

(defmacro hot-hash (name &key (destructive nil))
  (let ((name-setf (read-from-string 
					(concatenate 'string (write-to-string name) "-setf")))
	 (dv-or-dp (if destructive 'defparameter 'defvar)))
    `(progn 
      (,dv-or-dp ,name (make-hash-table :test #'equal))
      (defun ,name (k) (gethash k ,name))
      (defun ,name-setf (k v)
	(setf (gethash k ,name) v))
      (defsetf ,name ,name-setf))))

(hot-hash h) 
;; the variable h is now a hash, while the function h returns the value
;;for a key of the hash and is setf-able.

(setf (h 3) 4)         ;;like (setf (gethash 3 h) 4)
(setf (h "cat") "dog")
(setf (h 'a) 'b)

(h "cat") => "dog"
(incf (h 3)) => 5

(loop for k being the hash-key of h do (format t "~s -> ~s~%" k (h k)))
3 -> 5
"cat" -> "dog"
A -> B

There may be a better way to do this -- I haven't learned clos so I wonder
if it can be done more easily in that framework.  Also, I couldn't figure
out how to do it without defun-ing name-setf, which is disposable as far
as I'm concerned.

Win
From: Winston Smith
Subject: hot-hash macro (criticism welcome)
Date: 
Message-ID: <slrnevohjt.v30.ga41h@localhost.localdomain>
On 2007-03-17, Brian Adkins <·················@gmail.com> wrote:
> Juho Snellman wrote:
>> Brian Adkins <·················@gmail.com> wrote:
>>> Why do you feel "the generality of the setf form" is being "thrown 
>>> away"? The task at hand is a specific one - to associate a key and value 
>>> in a hash. What do you feel the benefits of the following:
>>>
>>> (setf (gethash :key hash) value)
>>>
>>> are compared to:
>>>
>>> (seth :key hash value)
>>>
>>> given the task?
>> 
>> It doesn't extend to:
>> 
>>   (incf (gethash :key hash) value)
>>   (push (gethash :key hash) value)
>>   (rotatef (gethash :key hash)
>>            (gethash :other-key hash))
>>   (setf (values (gethash :key hash)
>>                 (gethash :key other-hash))
>>     (something-returning-two-values))
>> 
>> etc.
>> 
>
> Thanks for the ideas on various ways to use (gethash), but I don't see 
> how having a (seth) macro detracts from that. I expect I'll need to call 
>   (seth) frequently enough that typing 22 chars instead of 32 chars each 
> time will be useful.
>
> I can see how introducing a proliferation of macros simply to save some 
> typing has the disadvantage of introducing new semantic elements that 
> have to either be memorized or looked up, but if they're used frequently 
> enough, it would seem to be a benefit to me. Maybe I'll feel differently 
> when I have more Lisp experience under my belt.

You'll want to wait for criticism from the experts before adopting this,
but I wrote this macro to save typing while preserving the functionality
of setf, incf, etc.

(defmacro hot-hash (name &key (destructive nil))
  (let ((name-setf (read-from-string 
                    (concatenate 'string (write-to-string name) "-setf")))
     (dv-or-dp (if destructive 'defparameter 'defvar)))
    `(progn 
      (,dv-or-dp ,name (make-hash-table :test #'equal))
      (defun ,name (k) (gethash k ,name))
      (defun ,name-setf (k v)
    (setf (gethash k ,name) v))
      (defsetf ,name ,name-setf))))

(hot-hash h) 
;; the variable h is now a hash, while the function h returns the value
;;for a key of the hash and is setf-able.

(setf (h 3) 4)         ;;like (setf (gethash 3 h) 4)
(setf (h "cat") "dog")
(setf (h 'a) 'b)

(h "cat") => "dog"
(incf (h 3)) => 5

(loop for k being the hash-key of h do (format t "~s -> ~s~%" k (h k)))
3 -> 5
"cat" -> "dog"
A -> B

There may be a better way to do this -- I haven't learned clos so I wonder
if it can be done more easily in that framework.  Also, I couldn't figure
out how to do it without defun-ing name-setf, which is disposable as far
as I'm concerned.

Win
From: Alan Crowe
Subject: Re: hot-hash macro (criticism welcome)
Date: 
Message-ID: <86bqiqv6vu.fsf@cawtech.freeserve.co.uk>
Winston Smith <·····@yahoo.com> writes:
> You'll want to wait for criticism from the experts before adopting this,
> but I wrote this macro to save typing while preserving the functionality
> of setf, incf, etc.
> 
> (defmacro hot-hash (name &key (destructive nil))
>   (let ((name-setf (read-from-string 
>                     (concatenate 'string (write-to-string name) "-setf")))
>      (dv-or-dp (if destructive 'defparameter 'defvar)))
>     `(progn 
>       (,dv-or-dp ,name (make-hash-table :test #'equal))
>       (defun ,name (k) (gethash k ,name))
>       (defun ,name-setf (k v)
>     (setf (gethash k ,name) v))
>       (defsetf ,name ,name-setf))))
> 
> (hot-hash h) 
> ;; the variable h is now a hash, while the function h returns the value
> ;;for a key of the hash and is setf-able.
> 
> (setf (h 3) 4)         ;;like (setf (gethash 3 h) 4)
> (setf (h "cat") "dog")
> (setf (h 'a) 'b)
> 
> (h "cat") => "dog"
> (incf (h 3)) => 5
> 
> (loop for k being the hash-key of h do (format t "~s -> ~s~%" k (h k)))
> 3 -> 5
> "cat" -> "dog"
> A -> B
> 
> There may be a better way to do this -- I haven't learned clos so I wonder
> if it can be done more easily in that framework.  Also, I couldn't figure
> out how to do it without defun-ing name-setf, which is disposable as far
> as I'm concerned.
> 

X3J13 adopted the proposal "Function-name: Large"

http://www.lisp.org/HyperSpec/Issues/iss174-writeup.html

which means that you can use (setf foo) as a function name
and setf will know to expand (setf (foo x y) z) so that (setf
foo) gets called with z as the new-value and x and y as
other arguments. This neatly avoids the need for the extra
name foo-setf.

CL-USER> (defmacro hot-hash (name &key (test ''eql))
           `(progn
             (defparameter ,name (make-hash-table :test ,test))
             (defun ,name (key)
               (gethash key ,name))
             (defun (setf ,name)(new-value key)
               (setf (gethash key ,name) new-value))))

I've put in a test argument. Since the default is eql, you
are heading for a terrible disappointment with hashing
strings. Contemplate

CL-USER> (eql "cat" "cat")
NIL

CL-USER> (equal "cat" "cat")
T

CL-USER> (eql #1="cat" #1#)
T

There is another worry, that the defparameter form makes all
the variables named by the name special variables, even when
you want them to be lexical. That is why you see
(defparameter *x* ...), (defparameter x ...) messes with
attempts to close over x. One crude fix is to put the
hashtable on the symbols property list.

CL-USER> (defmacro hot-hash (name &key (test ''eql))
           `(progn
             (setf (get ',name 'hash-table) (make-hash-table :test ,test))
             (defun ,name (key)
               (gethash key (get ',name 'hash-table)))
             (defun (setf ,name)(new-value key)
               (setf (gethash key (get ',name 'hash-table)) new-value))))

Alan Crowe
Edinburgh
Scotland
From: Rob St. Amant
Subject: Re: hot-hash macro (criticism welcome)
Date: 
Message-ID: <etjt4f$geo$1@blackhelicopter.databasix.com>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> There is another worry, that the defparameter form makes all
> the variables named by the name special variables, even when
> you want them to be lexical. That is why you see
> (defparameter *x* ...), (defparameter x ...) messes with
> attempts to close over x. One crude fix is to put the
> hashtable on the symbols property list.
>
> CL-USER> (defmacro hot-hash (name &key (test ''eql))
>            `(progn
>              (setf (get ',name 'hash-table) (make-hash-table :test ,test))
>              (defun ,name (key)
>                (gethash key (get ',name 'hash-table)))
>              (defun (setf ,name)(new-value key)
>                (setf (gethash key (get ',name 'hash-table)) new-value))))

Another locality issue is that sometimes it might be desirable to have
a local hash table.  For that, something like this might be useful
(untested):

(defmacro with-hot-hash ((name &key (test ''eql)) &body body)
  (let ((key-sym (gensym))
	(val-sym (gensym)))
    `(let ((,name (make-hash-table :test ,test)))
       (flet ((,name (,key-sym) (gethash ,key-sym ,name))
	      ((setf ,name) (,val-sym ,key-sym) (setf (gethash ,key-sym ,name) ,val-sym)))
	 ,@body))))
From: Winston Smith
Subject: Re: hot-hash macro (criticism welcome)
Date: 
Message-ID: <slrnevrdns.24a.ga41h@localhost.localdomain>
On 2007-03-18, Rob St. Amant <·······@ncsu.edu> wrote:
>
> Another locality issue is that sometimes it might be desirable to have
> a local hash table.  For that, something like this might be useful
> (untested):
>
> (defmacro with-hot-hash ((name &key (test ''eql)) &body body)
>   (let ((key-sym (gensym))
> 	(val-sym (gensym)))
>     `(let ((,name (make-hash-table :test ,test)))
>        (flet ((,name (,key-sym) (gethash ,key-sym ,name))
> 	      ((setf ,name) (,val-sym ,key-sym) (setf (gethash ,key-sym ,name) ,val-sym)))
> 	 ,@body))))

That's great. I realized the need for a with-hot-hash after Alan's post,
but I didn't realize you could use (setf ,name) even with flet. Thanks.

By the way, it tests OK for me on sbcl.

Win
From: Alan Crowe
Subject: Re: hot-hash macro (criticism welcome)
Date: 
Message-ID: <86wt1c0x70.fsf@cawtech.freeserve.co.uk>
·······@ncsu.edu (Rob St. Amant) writes:

> Another locality issue is that sometimes it might be desirable to have
> a local hash table.  For that, something like this might be useful
> (untested):
> 
> (defmacro with-hot-hash ((name &key (test ''eql)) &body body)
>   (let ((key-sym (gensym))
> 	(val-sym (gensym)))
>     `(let ((,name (make-hash-table :test ,test)))
>        (flet ((,name (,key-sym) (gethash ,key-sym ,name))
> 	      ((setf ,name) (,val-sym ,key-sym) (setf (gethash ,key-sym ,name) ,val-sym)))
> 	 ,@body))))

You don't need to gensym key-sym and val-sym. Think about

CL-USER> (let ((x 3))
           (flet ((f (y) (* 2 y)))
             (f x)))
=> 6

The parameter name y is local to the execution of
f. Is not visible at the call site (f x)

CL-USER> (let ((x 3))
           (flet ((f (y) (* 2 y)))
             (f y)))

gives an undefined variable error because y is not visible
from (f y)

So renaming y to x doesn't break the code

CL-USER> (let ((x 3))
           (flet ((f (x) (* 2 x)))
             (f x)))
=> 6

The parameter x doesn't get between (f x) and (let ((x 3))...)
Thus there is no risk of name capture and no need to genysm.

Alan Crowe
Edinburgh
Scotland
From: Rob St. Amant
Subject: Re: hot-hash macro (criticism welcome)
Date: 
Message-ID: <etp88v$e53$1@blackhelicopter.databasix.com>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

> ·······@ncsu.edu (Rob St. Amant) writes:
>
>> Another locality issue is that sometimes it might be desirable to have
>> a local hash table.  For that, something like this might be useful
>> (untested):
>> 
>> (defmacro with-hot-hash ((name &key (test ''eql)) &body body)
>>   (let ((key-sym (gensym))
>> 	(val-sym (gensym)))
>>     `(let ((,name (make-hash-table :test ,test)))
>>        (flet ((,name (,key-sym) (gethash ,key-sym ,name))
>> 	      ((setf ,name) (,val-sym ,key-sym) (setf (gethash ,key-sym ,name) ,val-sym)))
>> 	 ,@body))))
>
> You don't need to gensym key-sym and val-sym. Think about
>
> CL-USER> (let ((x 3))
>            (flet ((f (y) (* 2 y)))
>              (f x)))
> => 6
>
> The parameter name y is local to the execution of
> f. Is not visible at the call site (f x)
>
> CL-USER> (let ((x 3))
>            (flet ((f (y) (* 2 y)))
>              (f y)))
>
> gives an undefined variable error because y is not visible
> from (f y)
>
> So renaming y to x doesn't break the code
>
> CL-USER> (let ((x 3))
>            (flet ((f (x) (* 2 x)))
>              (f x)))
> => 6
>
> The parameter x doesn't get between (f x) and (let ((x 3))...)
> Thus there is no risk of name capture and no need to genysm.

Yes, thanks, I was on macro-writing autopilot.
From: Winston Smith
Subject: Re: hot-hash macro (criticism welcome)
Date: 
Message-ID: <slrnevrcol.24a.ga41h@localhost.localdomain>
On 2007-03-18, Alan Crowe <····@cawtech.freeserve.co.uk> wrote:
> Winston Smith <·····@yahoo.com> writes:
>> Also, I couldn't figure
>> out how to do it without defun-ing name-setf, which is disposable as far
>> as I'm concerned.
>> 
>
> X3J13 adopted the proposal "Function-name: Large"
>
> http://www.lisp.org/HyperSpec/Issues/iss174-writeup.html
>
> which means that you can use (setf foo) as a function name
> and setf will know to expand (setf (foo x y) z) so that (setf
> foo) gets called with z as the new-value and x and y as
> other arguments. This neatly avoids the need for the extra
> name foo-setf.
>
> CL-USER> (defmacro hot-hash (name &key (test ''eql))
>            `(progn
>              (defparameter ,name (make-hash-table :test ,test))
>              (defun ,name (key)
>                (gethash key ,name))
>              (defun (setf ,name)(new-value key)
>                (setf (gethash key ,name) new-value))))

Thanks! That is neat.

One thing I like about lisp is that I find everything I want to do
has been anticipated by The Great Ones.

Another possibility occurred to me, but it's less versatile:

(defmacro hot-hash (name &key (test #'equal))
    `(progn 
      (defparameter ,name (make-hash-table :test ,test))
      (defmacro ,name (k) `(gethash ,k ,',name)))

The point of using the inner defmacro instead of defun is
that it makes name setf-able.

But I wonder about performance. It's not clear to me what happens
to the inner defmacro when the outer one gets compiled. 

And though I somehow came up with ,',name, and vaugley understand it,
I mainly think it's right because I didn't get an error when I compiled
or used the macro, while ,,name caused a warning.

> I've put in a test argument. Since the default is eql, you
> are heading for a terrible disappointment with hashing
> strings. Contemplate
>
> CL-USER> (eql "cat" "cat")
> NIL
>
> CL-USER> (equal "cat" "cat")
> T
>
> CL-USER> (eql #1="cat" #1#)
> T

I thought I had that covered with:
>>       (,dv-or-dp ,name (make-hash-table :test #'equal))
Did you overlook my :test #'equal or am I still missing something?

Are there drawbacks to using #'equal? Performance?


> There is another worry, that the defparameter form makes all
> the variables named by the name special variables, even when
> you want them to be lexical. That is why you see
> (defparameter *x* ...), (defparameter x ...) messes with
> attempts to close over x. One crude fix is to put the
> hashtable on the symbols property list.
>
> CL-USER> (defmacro hot-hash (name &key (test ''eql))
>            `(progn
>              (setf (get ',name 'hash-table) (make-hash-table :test ,test))
>              (defun ,name (key)
>                (gethash key (get ',name 'hash-table)))
>              (defun (setf ,name)(new-value key)
>                (setf (gethash key (get ',name 'hash-table)) new-value))))

Interesting. Thanks.

Win
From: John Thingstad
Subject: Re: hot-hash macro (criticism welcome)
Date: 
Message-ID: <op.tpen5falpqzri1@pandora.upc.no>
On Sun, 18 Mar 2007 22:45:35 +0100, Winston Smith <·····@yahoo.com> wrote:

>
> But I wonder about performance. It's not clear to me what happens
> to the inner defmacro when the outer one gets compiled.
>

Well that depends. Obviously that outer macro must be evaluated before  
anything
that depends on the inner one. Apart from that macros can be nested in  
macros indefinitely.
The compiler will keep on expanding until it is resolved.
Consider case on LispWorks. case reduces to cond which reduces to if.

To be sure you might want to use eval-when.
(eval-when (:compile-toplevel :load-toplevel :execute)
  ...)
This will assert that it runs first.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Vassil Nikolov
Subject: Re: hot-hash macro (criticism welcome)
Date: 
Message-ID: <m3648v1fof.fsf@localhost.localdomain>
On Sun, 18 Mar 2007 21:45:35 GMT, Winston Smith <·····@yahoo.com> said:
| ...
| (defmacro hot-hash (name &key (test #'equal))
|     `(progn 
|       (defparameter ,name (make-hash-table :test ,test))
|       (defmacro ,name (k) `(gethash ,k ,',name)))

| The point of using the inner defmacro instead of defun is
| that it makes name setf-able.

  Use DEFUN and DEFSETF.  Or use DEFUN and (DEFUN (SETF #) ...).

  ---Vassil.


-- 
And nobody played macros... again...
From: James
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <1174274995.379774.247600@p15g2000hsd.googlegroups.com>
On Mar 17, 1:41 pm, Brian Adkins <·················@gmail.com> wrote:
> Juho Snellman wrote:
> > Brian Adkins <·················@gmail.com> wrote:
> >> Why do you feel "the generality of the setf form" is being "thrown
> >> away"? The task at hand is a specific one - to associate a key and value
> >> in a hash. What do you feel the benefits of the following:
>
> >> (setf (gethash :key hash) value)
>
> >> are compared to:
>
> >> (seth :key hash value)
>
> >> given the task?
>
> > It doesn't extend to:
>
> >   (incf (gethash :key hash) value)
> >   (push (gethash :key hash) value)
> >   (rotatef (gethash :key hash)
> >            (gethash :other-key hash))
> >   (setf (values (gethash :key hash)
> >                 (gethash :key other-hash))
> >    (something-returning-two-values))
>
> > etc.
>
> Thanks for the ideas on various ways to use (gethash), but I don't see
> how having a (seth) macro detracts from that. I expect I'll need to call
>   (seth) frequently enough that typing 22 chars instead of 32 chars each
> time will be useful.

Use a better editor (or use the editor you currently have more
efficiently).  That's what keyboard macros are for: creating code
templates to remove all the drudgery.  I'm sure there's an Emacs macro
somewhere that will allow you to just 'fill in the blanks' :)
From: Rob Warnock
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <Lsidnf1J4LgUU53bnZ2dnUVZ_vamnZ2d@speakeasy.net>
Juho Snellman  <······@iki.fi> wrote:
+---------------
| Brian Adkins <·················@gmail.com> wrote:
| > Why do you feel "the generality of the setf form" is being "thrown 
| > away"? The task at hand is a specific one - to associate a key and
| > value in a hash. What do you feel the benefits of the following:
| >   (setf (gethash :key hash) value)
| > are compared to:
| >   (seth :key hash value)
| > given the task?
| 
| It doesn't extend to:
|   (incf (gethash :key hash) value)
|   (push (gethash :key hash) value)
|   (rotatef (gethash :key hash)
|            (gethash :other-key hash))
|   (setf (values (gethash :key hash)
|                 (gethash :key other-hash))
| 	(something-returning-two-values))
+---------------

In particular, it doesn't extend to one of my *favorite* idioms:

    (incf (gethash :key hash 0))

where the hash table doesn't need to have been preloaded in advance
with zeros for all possible keys! [Yes, (INCF (GETHASH :KEY HASH 0) VALUE)
also works, but I haven't found myself using it as often as the
unitary version.]


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Luís Oliveira
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m17itfq0pb.fsf@deadspam.com>
Brian Adkins <·················@gmail.com> writes:
> Thanks, that does reduce the verbosity a bit. I suppose the best I can
> do with respect to getting close to conciseness of hash[:key] = value
> would be something like (sethash :key hash value)
>
> (defmacro sethash (key hash value)
>   `(setf (gethash ,key ,hash) ,value))

When all of the macro's arguments are evaluated, that's usually a sign
that you should be using a function instead:

  (defun sethash (key hash-table value)
    (setf (gethash key hash-table) value))

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <iqVKh.5543$nV1.1444@bignews6.bellsouth.net>
Luís Oliveira wrote:
> Brian Adkins <·················@gmail.com> writes:
>> Thanks, that does reduce the verbosity a bit. I suppose the best I can
>> do with respect to getting close to conciseness of hash[:key] = value
>> would be something like (sethash :key hash value)
>>
>> (defmacro sethash (key hash value)
>>   `(setf (gethash ,key ,hash) ,value))
> 
> When all of the macro's arguments are evaluated, that's usually a sign
> that you should be using a function instead:
> 
>   (defun sethash (key hash-table value)
>     (setf (gethash key hash-table) value))
> 

I'm confused. Doesn't that result in the same code *plus* an extra 
function call?
From: Luís Oliveira
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m13b43pwc6.fsf@deadspam.com>
Brian Adkins <·················@gmail.com> writes:
>>> (defmacro sethash (key hash value)
>>>   `(setf (gethash ,key ,hash) ,value))
[...]
>>   (defun sethash (key hash-table value)
>>     (setf (gethash key hash-table) value))
>
> I'm confused. Doesn't that result in the same code *plus* an extra
> function call?

Heh, you see the glass half empty (an extra function *call*), I see the
glass half full (an extra *function*)!  If sethash is a function, you
can pass it around, apply it, funcall it, etc...

If you're *really* worried about an extra function call, you can
(declaim (inline sethash)).

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <dEWKh.21368$68.20244@bignews8.bellsouth.net>
Luís Oliveira wrote:
> Brian Adkins <·················@gmail.com> writes:
>>>> (defmacro sethash (key hash value)
>>>>   `(setf (gethash ,key ,hash) ,value))
> [...]
>>>   (defun sethash (key hash-table value)
>>>     (setf (gethash key hash-table) value))
>> I'm confused. Doesn't that result in the same code *plus* an extra
>> function call?
> 
> Heh, you see the glass half empty (an extra function *call*), I see the
> glass half full (an extra *function*)!  If sethash is a function, you
> can pass it around, apply it, funcall it, etc...

Cool, thx. I was only concerned about the cost of the extra function 
call "all things being equal", but you've pointed out they aren't :)
> 
> If you're *really* worried about an extra function call, you can
> (declaim (inline sethash)).
> 
From: Dan Bensen
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <ethodm$c7b$1@wildfire.prairienet.org>
Luís Oliveira wrote:
> When all of the macro's arguments are evaluated, that's usually a sign
> that you should be using a function instead:
> 
>   (defun sethash (key hash-table value)
>     (setf (gethash key hash-table) value))

Oops, that's my fault.  I wasn't thinking about the definition,
and I had some troubles a while back with functions involving setf.

-- 
Dan
www.prairienet.org/~dsb
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <N_UKh.5539$nV1.1631@bignews6.bellsouth.net>
Dan Bensen wrote:
> Brian Adkins wrote:
>> was the best way to handle the implicit creation of logged-in-user in 
>> line 19 of the Lisp version (line 10 of the Ruby version) (wrap the 
>> when in a let?).
> 
> Yes, that's the standard approach, as long as you don't need
> logged-in-user afterward.
> 
>> Is there a way to handle dealing with hash tables more concisely?
> 
> Just start the function with
>   (let ((session (session x))
>         (params  (params  x)))

I suppose you mean, "start *every* method in the class that uses these 
attributes with ..." I would hope that code within a method of a class 
would be able to refer to attributes of the class more easily. To frame 
this in terms of languages I know, I guess Lisp's object model is closer 
to Python with respect to "explicitness" vs. Ruby/Java with an implicit 
self/this.

> 
> If that's still too long, you could define your own sethash macro,
> unless someone else knows a way to call the underlying function
> directly.  It doesn't look like you're supposed to, though.
> 
From: Zach Beane
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m3hcsjhkx1.fsf@unnamed.xach.com>
Brian Adkins <·················@gmail.com> writes:

> I would hope that code within a method of a class would be able to
> refer to attributes of the class more easily.

Methods do not belong to classes, they belong to generic functions.

> To frame this in terms of languages I know, I guess Lisp's object
> model is closer to Python with respect to "explicitness"
> vs. Ruby/Java with an implicit self/this.

No. 

I think you'll make progress more quickly if you stop framing things
in terms of languages you know, and learn Lisp on your own terms.

Zach
From: Zach Beane
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m3d537hkni.fsf@unnamed.xach.com>
Zach Beane <····@xach.com> writes:

> I think you'll make progress more quickly if you stop framing things
> in terms of languages you know, and learn Lisp on your own terms.

D'oh...meant "learn Lisp on *its* own terms" here.

Zach
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <vzVKh.5545$nV1.4822@bignews6.bellsouth.net>
Zach Beane wrote:
> Brian Adkins <·················@gmail.com> writes:
> 
>> I would hope that code within a method of a class would be able to
>> refer to attributes of the class more easily.
> 
> Methods do not belong to classes, they belong to generic functions.

Would it help if I replaced "of a class" with "specialized for a class" 
in the above?

>> To frame this in terms of languages I know, I guess Lisp's object
>> model is closer to Python with respect to "explicitness"
>> vs. Ruby/Java with an implicit self/this.
> 
> No. 

No? Can you provide an example of an implicit self/this then?

> I think you'll make progress more quickly if you stop framing things
> in terms of languages you know, and learn Lisp on your own terms.
> 
> Zach
From: Zach Beane
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m38xdvhgdx.fsf@unnamed.xach.com>
Brian Adkins <·················@gmail.com> writes:

> > Brian Adkins <·················@gmail.com> writes:
> >
> >> I would hope that code within a method of a class would be able to
> >> refer to attributes of the class more easily.
> > Methods do not belong to classes, they belong to generic functions.
> 
> Would it help if I replaced "of a class" with "specialized for a
> class" in the above?

Not if you still think there's a special object "this" that the method
has special access to.
 
> >> To frame this in terms of languages I know, I guess Lisp's object
> >> model is closer to Python with respect to "explicitness"
> >> vs. Ruby/Java with an implicit self/this.
> > No.
> 
> No? Can you provide an example of an implicit self/this then?

There is no self/this.

Zach
From: Brian Adkins
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <SmXKh.18140$Wc.6489@bignews3.bellsouth.net>
Zach Beane wrote:
> Brian Adkins <·················@gmail.com> writes:
> 
>>> Brian Adkins <·················@gmail.com> writes:
>>>
>>>> I would hope that code within a method of a class would be able to
>>>> refer to attributes of the class more easily.
>>> Methods do not belong to classes, they belong to generic functions.
>> Would it help if I replaced "of a class" with "specialized for a
>> class" in the above?
> 
> Not if you still think there's a special object "this" that the method
> has special access to.
>  
>>>> To frame this in terms of languages I know, I guess Lisp's object
>>>> model is closer to Python with respect to "explicitness"
>>>> vs. Ruby/Java with an implicit self/this.
>>> No.
>> No? Can you provide an example of an implicit self/this then?
> 
> There is no self/this.

Sure there is, it just doesn't have to be named self or this. Consider 
the following contrived example:

(defclass my-class () (my-attr))

(defmethod my-method1 ((self my-class))
   (my-method2 self 7))

(defmethod my-method2 ((this my-class) value)
   (setf (slot-value this 'my-attr) value))

(setf obj (make-instance 'my-class))

(my-method1 obj)

(format t "~A~%" (slot-value obj 'my-attr))

When my-method1 calls my-method2 it passes the object reference (self in 
this case) to it. This *is* similar to how Python implements method 
calls. Other languages don't require an explicit object reference, but 
allow access to the object referrence e.g. via self in Ruby or this in 
Java/C++. Consider this Ruby snippet:

class MyClass
   attr_accessor :my_attr

   def my_method1
     my_method2 7
   end

   def my_method2 value
     self.my_attr = value
   end
end

obj = MyClass.new
obj.my_method1
puts obj.my_attr

See how my_method1 can call my_method2 w/o passing self? If I made the 
call explicit e.g. self.my_method(7) it would be closer (not the same) 
to the Python/Lisp mechanism. This also demonstrates a quirkiness in 
Ruby, my_method2 must prepend self. to my_attr to avoid implicitly 
creating a local var named my_attr.

I wasn't commenting on the pros/cons of either approach just trying to 
determine if I misunderstood something. I see a lot of power in the 
generic function model over the message passing model (being able to 
specialize for multiple params), it just makes some things less 
convenient when only specializing for one param - a reasonable tradeoff.

> 
> Zach
From: Dan Bensen
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <etjcef$98k$1@wildfire.prairienet.org>
Brian Adkins wrote:
> Zach Beane wrote:
>> Brian Adkins <·················@gmail.com> writes:
>>>> Brian Adkins <·················@gmail.com> writes:
>>>>> I would hope that code within a method of a class would be able to
>>>>> refer to attributes of the class more easily.

Why?  The method is just a function.  The object is just an argument.
Your next couple of posts on this topic are pointless, because this
comment is the one the other posters are (correctly) disagreeing with.

>>>> Methods do not belong to classes, they belong to generic functions.
>>> Would it help if I replaced "of a class" with "specialized for a
>>> class" in the above?
>>
>> Not if you still think there's a special object "this" that the method
>> has special access to.
>>  
>>>>> To frame this in terms of languages I know, I guess Lisp's object
>>>>> model is closer to Python with respect to "explicitness"
>>>>> vs. Ruby/Java with an implicit self/this.
>>>> No.
>>> No? Can you provide an example of an implicit self/this then?
>>
>> There is no self/this.
> 
> Sure there is, it just doesn't have to be named self or this.
> (defmethod my-method1 ((self my-class))
>   (my-method2 self 7))

They're not saying you can't name the method's first argument "self"
or "this", or that the object doesn't have to be passed as an argument.
They're only saying there's no special syntax for it, which is what
you suggested above.

-- 
Dan
www.prairienet.org/~dsb
From: Patrick May
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m2vegy7jc7.fsf@spe.com>
Brian Adkins <·················@gmail.com> writes:
> Zach Beane wrote:
>> There is no self/this.
>
> Sure there is, it just doesn't have to be named self or
> this. Consider the following contrived example:

[ single dispatch example elided ]

     Methods in Common Lisp are not tightly coupled to a single type
as they are in many popular OO languages.  This allows multiple
dispatch to be supported in a straightforward way.  Consider this,
equally contrived, example:

(defclass square (shape) (upper-left))

(defclass circle (shape) (center radius))

(defmethod overlap-p ((this-square square) (self-circle circle))
  . . .)

The concept of 'self' or 'this' just doesn't apply in CLOS.

Regards,

Patrick

------------------------------------------------------------------------
S P Engineering, Inc.  | Large scale, mission-critical, distributed OO
                       | systems design and implementation.
          ···@spe.com  | (C++, Java, Common Lisp, Jini, middleware, SOA)
From: Alain Picard
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <87abyb2f6x.fsf@memetrics.com>
Brian Adkins <·················@gmail.com> writes:

> Zach Beane wrote:
>> There is no self/this.
>
> Sure there is, it just doesn't have to be named self or this. Consider
> the following contrived example:
>
[SNIP]

> I wasn't commenting on the pros/cons of either approach just trying to
> determine if I misunderstood something. 

You did.  the bit you misunderstood is
 "There is no self/this."

Now you have had two experienced lispers say this, so instead
of retorting once more with an example that shows we're wrong,
try to kick you thinking into a different plane, to see if you
can understand what it is we're saying, and why we're saying it.

You might discover something useful.

I don't mean to be snipy or obnoxious here --- this is a common
"failure to learn" symptom.  I'm honestly encouraging you to
look at this again from a fresh perspective.  

                                --ap
From: ·····@evins.net
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <1175199283.682705.101810@n76g2000hsh.googlegroups.com>
On Mar 17, 1:32 pm, Brian Adkins <·················@gmail.com> wrote:
> Zach Beane wrote:
> > Brian Adkins <·················@gmail.com> writes:
>
> >>> Brian Adkins <·················@gmail.com> writes:
>
> >>>> I would hope that code within a method of a class would be able to
> >>>> refer to attributes of the class more easily.
> >>> Methods do not belong to classes, they belong to generic functions.
> >> Would it help if I replaced "of a class" with "specialized for a
> >> class" in the above?
>
> > Not if you still think there's a special object "this" that the method
> > has special access to.
>
> >>>> To frame this in terms of languages I know, I guess Lisp's object
> >>>> model is closer to Python with respect to "explicitness"
> >>>> vs. Ruby/Java with an implicit self/this.
> >>> No.
> >> No? Can you provide an example of an implicit self/this then?
>
> > There is no self/this.
>
> Sure there is, it just doesn't have to be named self or this.

No, there really isn't.

The concept of "this" just doesn't make sense in CLOS, because there
is no object that a method "lives in". A generic function has a number
of parameters; maybe zero, maybe a thousand. Each method of the
generic function knows the types of its parameters. That's all.

"This" (or "self") means "the object this function lives in." The
closest thing in CLOS to that concept is the generic function that a
method belongs to--but that's not going to help you.

You can contrive *special cases* in which "this" could refer to a
particular argument that you want to treat specially for some reason,
and that's just exactly what you did in the example you gave. Even in
your contrived example, though, it's bad style to use those names,
because they are misleading about the relationship of the function to
the parameter (they hint--wrongly--that the function lives in that
particular object), and because those names don't document the
parameter's intended role.
From: George Neuner
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <2dcp0319dd0a7048bddk2m4m8q4k7kqjmq@4ax.com>
On 29 Mar 2007 13:14:43 -0700, ······@evins.net"
<···········@gmail.com> wrote:

>On Mar 17, 1:32 pm, Brian Adkins <·················@gmail.com> wrote:
>> Zach Beane wrote:
>> > Brian Adkins <·················@gmail.com> writes:
>>
>> >>> Brian Adkins <·················@gmail.com> writes:
>>
>> >>>> To frame this in terms of languages I know, I guess Lisp's object
>> >>>> model is closer to Python with respect to "explicitness"
>> >>>> vs. Ruby/Java with an implicit self/this.
>> >>> No.
>> >> No? Can you provide an example of an implicit self/this then?
>>
>> > There is no self/this.
>>
>> Sure there is, it just doesn't have to be named self or this.
>
>No, there really isn't.
>
>The concept of "this" just doesn't make sense in CLOS, because there
>is no object that a method "lives in". 

In most popular OO language, methods don't "live" in objects, they
live in classes - conceptually at least.  We can debate endlessly
whether, conceptually, a class is itself an object.


>"This" (or "self") means "the object this function lives in." 

No.  OO languages encourage associating functions and data through
many small namespaces (aka classes).  A computation typically passes
through many such namespaces so there must be a way to designate both
the current namepace and the one to which the computation should
proceed.  "this" and "self" are just ways of designating the current
namespace.  Lisp uses its package system for this purpose.  Though
packages are typically used at a larger granularity than classes, they
need not be.

A method call in an OO language - including a "self" method call - is
just syntactic sugar for calling a function defined in the namespace
denoted by the object's class with the current object as a parameter

   object.fun( ... ) => classOf(object)::fun( object, ... ) 
   <this.>fun( ... ) => classOf(this)::fun( this, ... )

OO languages routinely hide method expansion from the programmer, but
fully expanded calls look suspiciously similar to generic function
calls in Lisp.  Most(all?) of the differences in Lisp can be hidden by
judicious use of macros.

George

--
for email reply remove "/" from address
From: ················@gmail.com
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <1175275046.105886.268150@e65g2000hsc.googlegroups.com>
On Mar 30, 4:03 am, George Neuner <·········@comcast.net> wrote:
> On 29 Mar 2007 13:14:43 -0700, ·····@evins.net"
>
> >"This" (or "self") means "the object this function lives in."
>
> No.  OO languages encourage associating functions and data through
> many small namespaces (aka classes).  A computation typically passes
> through many such namespaces so there must be a way to designate both
> the current namepace and the one to which the computation should
> proceed.  "this" and "self" are just ways of designating the current
> namespace.

Yes, Mikel should have written "'This' (or 'self') means 'the *class*
this function lives in',"[1] but I think you gloss over the larger,
and in this discussion, more important point, that in CLOS, "this" or
"self" is inherently ambiguous because generic functions dispatch on
*all* arguments, not just on a specially distinguished first "self" or
"this" parameter.

[1] as long as we're not talking about prototype based oo languages.

Consider this - pun intended ;^)

CL-USER 1 > (defclass vehicle nil nil)
#<STANDARD-CLASS VEHICLE 210B4FFF>

CL-USER 2 > (defclass truck (vehicle) nil)
#<STANDARD-CLASS TRUCK 210D9897>

CL-USER 3 > (defmethod collide ((vehicle1 vehicle) (vehicle2 vehicle))
              (format t "~a just collided with ~a.~%" vehicle1
vehicle2))
#<STANDARD-METHOD COLLIDE NIL (VEHICLE VEHICLE) 210DD487>

CL-USER 4 > (defmethod collide ((this vehicle) (that truck))
                      (format t "I wonder why ~a is called 'this' and
~a is called 'that'
when both can be instances  of the same class and the class of the
latter
is specified more precisely than the class of the former in the method
definition?~%" this that)
                      (call-next-method))
#<STANDARD-METHOD COLLIDE NIL (VEHICLE TRUCK) 200A183F>

CL-USER 5 > (collide (make-instance 'truck) (make-instance 'truck))
I wonder why #<TRUCK 200CEEC7> is called 'this' and #<TRUCK 200CEEB3>
is called 'that'
when both can be instances  of the same class and the class of the
latter
is specified more precisely than the class of the former in the method
definition?
#<TRUCK 200CEEC7> just collided with #<TRUCK 200CEEB3>.
NIL

imho, using the term 'this' or 'self' in clos defmethods is only
apropriate when clos is being used to interface to some object system
where these terms have a well defined meaning.
From: Rainer Joswig
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <joswig-A899D9.19541430032007@news-europe.giganews.com>
In article <························@e65g2000hsc.googlegroups.com>,
 ················@gmail.com wrote:

> On Mar 30, 4:03 am, George Neuner <·········@comcast.net> wrote:
> > On 29 Mar 2007 13:14:43 -0700, ·····@evins.net"
> >
> > >"This" (or "self") means "the object this function lives in."
> >
> > No.  OO languages encourage associating functions and data through
> > many small namespaces (aka classes).  A computation typically passes
> > through many such namespaces so there must be a way to designate both
> > the current namepace and the one to which the computation should
> > proceed.  "this" and "self" are just ways of designating the current
> > namespace.
> 
> Yes, Mikel should have written "'This' (or 'self') means 'the *class*
> this function lives in',"[1] but I think you gloss over the larger,
> and in this discussion, more important point, that in CLOS, "this" or
> "self" is inherently ambiguous because generic functions dispatch on
> *all* arguments, not just on a specially distinguished first "self" or
> "this" parameter.
> 
> [1] as long as we're not talking about prototype based oo languages.
> 
> Consider this - pun intended ;^)
> 
> CL-USER 1 > (defclass vehicle nil nil)
> #<STANDARD-CLASS VEHICLE 210B4FFF>
> 
> CL-USER 2 > (defclass truck (vehicle) nil)
> #<STANDARD-CLASS TRUCK 210D9897>
> 
> CL-USER 3 > (defmethod collide ((vehicle1 vehicle) (vehicle2 vehicle))
>               (format t "~a just collided with ~a.~%" vehicle1
> vehicle2))
> #<STANDARD-METHOD COLLIDE NIL (VEHICLE VEHICLE) 210DD487>
> 
> CL-USER 4 > (defmethod collide ((this vehicle) (that truck))
>                       (format t "I wonder why ~a is called 'this' and
> ~a is called 'that'
> when both can be instances  of the same class and the class of the
> latter
> is specified more precisely than the class of the former in the method
> definition?~%" this that)
>                       (call-next-method))
> #<STANDARD-METHOD COLLIDE NIL (VEHICLE TRUCK) 200A183F>
> 
> CL-USER 5 > (collide (make-instance 'truck) (make-instance 'truck))
> I wonder why #<TRUCK 200CEEC7> is called 'this' and #<TRUCK 200CEEB3>
> is called 'that'
> when both can be instances  of the same class and the class of the
> latter
> is specified more precisely than the class of the former in the method
> definition?
> #<TRUCK 200CEEC7> just collided with #<TRUCK 200CEEB3>.
> NIL
> 
> imho, using the term 'this' or 'self' in clos defmethods is only
> apropriate when clos is being used to interface to some object system
> where these terms have a well defined meaning.


Note also:

Shorter notation for accessing slots is possible via WITH-SLOTS and/or
WITH-ACCESSORS.

-- 
http://lispm.dyndns.org
From: George Neuner
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <ponr03dabtra3dc2igqbk2qsm1pvoa1f19@4ax.com>
On 30 Mar 2007 10:17:26 -0700, ················@gmail.com wrote:

>On Mar 30, 4:03 am, George Neuner <·········@comcast.net> wrote:
>> On 29 Mar 2007 13:14:43 -0700, ·····@evins.net"
>>
>> >"This" (or "self") means "the object this function lives in."
>>
>> No.  OO languages encourage associating functions and data through
>> many small namespaces (aka classes).  A computation typically passes
>> through many such namespaces so there must be a way to designate both
>> the current namepace and the one to which the computation should
>> proceed.  "this" and "self" are just ways of designating the current
>> namespace.
>
>Yes, Mikel should have written "'This' (or 'self') means 'the *class*
>this function lives in',"[1] but I think you gloss over the larger,
>and in this discussion, more important point, that in CLOS, "this" or
>"self" is inherently ambiguous because generic functions dispatch on
>*all* arguments, not just on a specially distinguished first "self" or
>"this" parameter.

Multiple dispatch is an important difference but I wasn't addressing
how generic functions differ from class functions - I was pointing out
what "this" and "self" actually represent in an OO language and in
reality how similar are the actual method calls in an OO language (as
opposed to their visible syntax) to generic function calls in Lisp.

George
--
for email reply remove "/" from address
From: ················@gmail.com
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <1175389811.210528.177970@d57g2000hsg.googlegroups.com>
On Mar 31, 12:44 am, George Neuner <·········@comcast.net> wrote:
>
> Multiple dispatch is an important difference but I wasn't addressing
> how generic functions differ from class functions - I was pointing out
> what "this" and "self" actually represent in an OO language and in
> reality how similar are the actual method calls in an OO language (as
> opposed to their visible syntax) to generic function calls in Lisp.
>

Actual method calls in a single dispatch language may be *similar* to
clos generic function calls, but they differ precisely in that there
really *is* one special parameter which can therfore justifiably be
called "this" or "self" in a single dispatch language. The "self"
parameter in single dispatch languages is specially distinguished
because it is the sole parameter on which the method call is
dispatched. (In this context, see Vasil's point about "self" being a
runtime designation of execution context and not just a namespace
designation).

Multiple dispatch is not just *a* difference, it is *the* crucial
difference that makes "self" meaningless in a clos method. In Common
Lisp  it is inappropriate to consider any one of the parameters as
being the distinguished "self" parameter because generic functions are
not dispatched on any *one* distinguished parameter.
From: Andrew Reilly
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <pan.2007.04.01.13.08.25.765369@areilly.bpc-users.org>
On Sat, 31 Mar 2007 18:10:11 -0700, raffaelcavallaro wrote:

> Multiple dispatch is not just *a* difference, it is *the* crucial
> difference that makes "self" meaningless in a clos method. In Common
> Lisp  it is inappropriate to consider any one of the parameters as
> being the distinguished "self" parameter because generic functions are
> not dispatched on any *one* distinguished parameter.

How much milage does lisp get from multiple dispatch, in practice?  And
what is the cost (runtime, space) compared to single-dispatch systems?

I admit that I came to obects via abstract data types and object pascal
and smalltalk.  In that context an object (or at least a class) *is* its
methods.  If a class doesn't have methods, then in what sense is it a
class?  CLOS has classes, right?

(I'm still very much a newbie: I'm having lots of fun with my first
real piece of lisp code (in MzScheme), but have avoided introducing
objects yet, since there seems to be more than one alternative approach,
and I haven't really needed them yet.)

PS: I discovered, last week, that MzScheme/MzLib doesn't seem to have a
general "set" data structure.  It's the work of half a dozen lines to
build the relevant operations around hash tables, but it seemed a bit odd
that there wasn't one as standard, or even in user-contributed libraries.
Does CL have a Set collection class?  Maybe I've been using the wrong
search terms...  (SET-DIFFERENCE isn't quite what I was looking for, but
it's in the ballpark.)

Cheers,

-- 
Andrew
From: ················@gmail.com
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <1175443905.131339.265210@q75g2000hsh.googlegroups.com>
On Apr 1, 9:08 am, Andrew Reilly <···············@areilly.bpc-
users.org> wrote:
>
> How much milage does lisp get from multiple dispatch, in practice?

That depends entirely on the application the programmer designs. You
can code what amounts to a single dispatch application if you want
using clos - just never write any generic functions whose args other
than the first differ in class. You can also make extensive use of
multiple dispatch which would be using more of the full power of clos
imho.

> And
> what is the cost (runtime, space) compared to single-dispatch systems?

A question better answered by an implementor than me.

>
> I admit that I came to obects via abstract data types and object pascal
> and smalltalk.  In that context an object (or at least a class) *is* its
> methods.  If a class doesn't have methods, then in what sense is it a
> class?  CLOS has classes, right?



A clos class is a class in the sense that it has superclasses and
slots. The superclasses define slot inheritance and method dispatch. A
clos object can be thought of as a collection of slots, some inherited
from various superclasses, some new to the object's class, which
collection of data can be specialized on by generic functions to
varying degrees of specificty - from the most distant ancestor class
at one extreme (i.e., methods specializing on t) down to methods that
specialize on a particular *object* - note, not a particular *class*
but methods that specialize on a particular *instance* of a class.


>
> (I'm still very much a newbie: I'm having lots of fun with my first
> real piece of lisp code (in MzScheme), but have avoided introducing
> objects yet, since there seems to be more than one alternative approach,
> and I haven't really needed them yet.)

Note that scheme and common lisp are not generally considered the same
language. Any questions you have about scheme are probably better
addressed to comp.lang.scheme, (or an mzscheme mailing list if the
question is particular to that implementation). fwiw, I understand
that mzscheme's swindle object system is quite similar to clos in many
ways.
From: ················@gmail.com
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <1175444777.863380.185650@n59g2000hsh.googlegroups.com>
On Apr 1, 12:11 pm, ················@gmail.com wrote:
> note, not a particular *class*
> but methods that specialize on a particular *instance* of a class.

probably clearer to say "not *just* a particular *class*" because clos
defmethods can of course specialize on a particular class as well.
From: Andrew Reilly
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <pan.2007.04.02.02.06.17.721762@areilly.bpc-users.org>
On Sun, 01 Apr 2007 09:11:45 -0700, raffaelcavallaro wrote:

> Note that scheme and common lisp are not generally considered the same
> language. Any questions you have about scheme are probably better
> addressed to comp.lang.scheme, (or an mzscheme mailing list if the
> question is particular to that implementation). fwiw, I understand
> that mzscheme's swindle object system is quite similar to clos in many
> ways.

Oh, I'm aware of that.  I'm reading c.l.l to make sure that I'm
absorbing the right amount of perspective :-)  MzScheme seems to have at
least two flavours of tiny-CLOS, as well as "class.ss", which seems to be
a single-dispatch system that is used in their GUI library.  If one looks
on the contributed source web sites, there are several other alternatives
(as there is with common lisp, if recent discussions of historical code
are to be believed: flavours et al).  I suppose that it doesn't really
matter: it's problbly possible to use Swindle CLOS (or Tiny CLOS) in the
same program as a MrEd GUI, but since I'm not doing a GUI at the moment,
I'm keeping my distance...  Certainly scheme doesn't seem to have any
pretence that "everything is an object" the way CL does (sort of).

Cheers,

-- 
Andrew
From: Alan Crowe
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <868xdcw0je.fsf@cawtech.freeserve.co.uk>
Andrew Reilly <···············@areilly.bpc-users.org> writes:

> On Sat, 31 Mar 2007 18:10:11 -0700, raffaelcavallaro wrote:
> 
> > Multiple dispatch is not just *a* difference, it is *the* crucial
> > difference that makes "self" meaningless in a clos method. In Common
> > Lisp  it is inappropriate to consider any one of the parameters as
> > being the distinguished "self" parameter because generic functions are
> > not dispatched on any *one* distinguished parameter.
> 
> How much milage does lisp get from multiple dispatch, in practice?  And
> what is the cost (runtime, space) compared to single-dispatch systems?

I find single dispatch distressing. I posted about my first
encounter with it

http://tinyurl.com/2huok7

Alan Crowe
Edinburgh
Scotland
From: Andrew Reilly
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <pan.2007.04.02.02.21.32.431158@areilly.bpc-users.org>
On Sun, 01 Apr 2007 16:56:53 +0100, Alan Crowe wrote:

> Andrew Reilly <···············@areilly.bpc-users.org> writes:
> 
>> On Sat, 31 Mar 2007 18:10:11 -0700, raffaelcavallaro wrote:
>> 
>> > Multiple dispatch is not just *a* difference, it is *the* crucial
>> > difference that makes "self" meaningless in a clos method. In Common
>> > Lisp  it is inappropriate to consider any one of the parameters as
>> > being the distinguished "self" parameter because generic functions are
>> > not dispatched on any *one* distinguished parameter.
>> 
>> How much milage does lisp get from multiple dispatch, in practice?  And
>> what is the cost (runtime, space) compared to single-dispatch systems?
> 
> I find single dispatch distressing. I posted about my first
> encounter with it
> 
> http://tinyurl.com/2huok7

I suppose that one's first encounters are determined by background and
context.  Abstract data types are usually introduced with things like
stacks or trees, where it's "push, pop, empty?" etc that matter.
Those are pretty clearly methods or properties of the stack, so it is
perfectly fine to be focussed on it. I admit that abstract data types
isn't the only (or even the main) thing that object-orientation is used
for.

I'm not sure that your mod example was particularly sensible, either
though: what happens when you (add 5mod7 6mod12)?  That makes no sense,
mathematically, whereas the single dispatch version (add-mod7 5mod7 6)
works fine, for any value of six.  Still not particularly sensible,
because (add-mod7 x y) should work for any integer values of x and y,
shouldn't it?

Eiffel has a single-dispatch object system, but it also has "conformal"
parameters, where non-dispatching arguments and results can be defined to
be "like (the class)", rather than being a specific class.  That
supposedly helps as methods are inherited.

I guess I don't like OO much, as a rule...

Cheers,

-- 
Andrew
From: Christian Haselbach
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <euotdc$fq0$1@online.de>
Andrew Reilly wrote:
> I admit that I came to obects via abstract data types and object pascal
> and smalltalk.  In that context an object (or at least a class) *is* its
> methods.  If a class doesn't have methods, then in what sense is it a
> class?  CLOS has classes, right?

CLOS has classes, of course. Even in a single dispatch (or message 
passing) OO system a class is not really its methods, but methods and 
classes are bound more tightly. For example, in Java you can define 
class A and B where B extends A, but does nothing else. Hence A and B 
have the same methods and fields but they are not the same class. The 
set of objects that are an instance of A is a subset of the set of 
objects that are an instance of B.

In that sense classes are not defined by their methods, but denote a 
classification of all objects. The methods are merely associated with 
the classes.

In a single dispatch OO system, this association only uses one of the 
function arguments (often written in a syntax that emphasis this fact, 
like a.f(b, c) rather than f(a, b, c)).

Lets Assume you have classes A, B, C, and D, where B extends A and D 
extends C. If you want to implement a function f with two arguments, 
first argument of type A (i.e., it is an instance of A) and second 
argument of type B. In a single dispatch system like Java you would 
implement

public Object f(C y) {
   return y instanceof D ? f_AD((D) y) : f_AC(y);
}

in class A (and analogous in B). In a multiple dispatch OO system like 
CLOS you can write

(defmethod f ((x A) (y C)) ...)
(defmethod f ((x A) (y D)) ...)
(defmethod f ((x B) (y C)) ...)
(defmethod f ((x B) (y D)) ...)

Regards,
Christian
From: George Neuner
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <j3v013hetjgfc9t6lcatmm889iadulnumq@4ax.com>
On Sun, 01 Apr 2007 23:08:27 +1000, Andrew Reilly
<···············@areilly.bpc-users.org> wrote:

>what is the cost (runtime, space) compared to single-dispatch systems?

It depends on the implementation.  Dispatch proceeds in 2 steps: first
determine the class of the object, then find the function.

Some OO languages directly tag each object with a pointer to its class
information, others use a runtime hash on the object's address or a
hash or index on a suitable identity tag (if e.g., the object may be
relocated).

The function dispatch table for the class may be an array, a hash, or
even a tree of arrays - one for each class with links describing
inheritance - depending on the implementation.

C++, for example, requires an O(1) function dispatch mechanism -
necessitating that the compiler reduce the object's class hierarchy to
a single array or use a hash implementation.  Most languages make no
Big-O guarantees about function dispatch.

In terms of performance, the best case would be an indirection through
the class pointer, index into the dispatch table, and an indirect
function call (well optimized C++).  The worst case for a commercial
OO compiler would likely be an access to retrieve a class identifier,
a hash on the identifier to find the class descriptor, a hash on a
function descriptor to get the function address, and an indirect
function call.


Generic functions are generally implemented as a discrimination tree
where each decision point requires a class determination for the
relevant parameter.  Depending on the implementation and the objects
involved, at each decision point, that could mean just a tag
comparison (for an immediate object), a tag access and comparison or
address range comparison (for a heap object), or as much as a hash on
the object's address.  Once the tree walk reaches a leaf, the function
is known and may be called directly (which is somewhat faster than
indirect calls on most processors).

Performance of a generic function call is thus O(n) in the number of
discriminant parameters (ie. the depth of the tree) plus the overhead
of retrieving and comparing the object tag.  I am away from my
references and I can't remember just now whether Lisp is required to
consider the parameters left to right or is allowed to optimize the
tree.

Lisp also complicates the matter in two ways.  First GC may relocate
objects, requiring an implementation that identifies objects by
address to rehash or modify address range comparisons.  Second, the
set of classes is not fixed at compile time - classes can be created
or redefined at runtime.  Doing either requires generic functions to
be recompiled at runtime.


A generic function with a few parameters and fast tag access can be
about quick as optimized single dispatch.  But if your Lisp identifies
objects by address (heavier range comparison or hash) or you have more
than a few discriminant parameters, or you mess with the class
hierarchy necessitating runtime recompilations - then you quickly
degrade their overall performance.

George
--
for email reply remove "/" from address
From: Rainer Joswig
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <joswig-39D24B.15433302042007@news-europe.giganews.com>
In article <······························@areilly.bpc-users.org>,
 Andrew Reilly <···············@areilly.bpc-users.org> wrote:

> On Sat, 31 Mar 2007 18:10:11 -0700, raffaelcavallaro wrote:
> 
> > Multiple dispatch is not just *a* difference, it is *the* crucial
> > difference that makes "self" meaningless in a clos method. In Common
> > Lisp  it is inappropriate to consider any one of the parameters as
> > being the distinguished "self" parameter because generic functions are
> > not dispatched on any *one* distinguished parameter.
> 
> How much milage does lisp get from multiple dispatch, in practice?  And
> what is the cost (runtime, space) compared to single-dispatch systems?
> 
> I admit that I came to obects via abstract data types and object pascal
> and smalltalk.  In that context an object (or at least a class) *is* its
> methods.  If a class doesn't have methods, then in what sense is it a
> class?  CLOS has classes, right?

In a more abstract sense there is the message passing paradigm.
With message passing you have objects with identity and one
can send messages to objects. These messages get executed
in the context of the object (this/self). This message
passing paradigm then comes in several 'flavors':
* classless / prototype based (Self, Object Lisp, ...)
* concurrent classless / prototype based (ABCL, ....)
* class-based (Smalltalk, ...)

The class-based system has a different organizing principle than
the protype based systems. Classes mostly join objects with
similar behaviour and allow 'blueprints' for new objects.

Some Lisp systems have followed the class-based message passing
route (for example: Flavors). After some time the message sending
seemed to be just another mechanism to invoke functions on data.
So 'Message sending' got replaced with 'Function Calling' in
New Flavors. Still there was this single dispatch thing.
That got extended to multiple dispatch with CLOS.

So in Common Lisp with CLOS we no longer have the message passing
paradigm. It got replaced with 'multiple dispatch functions
over class-based objects'. So the function invocation now
is more prominent. In a way it frees us from the limitations
of message passing: messages that have one sender and one receiver.
In CLOS this is no longer useful. The generic function is not a message,
but represents a computation ('printing a document', 'sending an email',
...), the computation takes a number of arguments and based of
the actual arguments the computation is configured
(:before, :after, :around, ...) and invoked.


> 
> (I'm still very much a newbie: I'm having lots of fun with my first
> real piece of lisp code (in MzScheme), but have avoided introducing
> objects yet, since there seems to be more than one alternative approach,
> and I haven't really needed them yet.)
> 
> PS: I discovered, last week, that MzScheme/MzLib doesn't seem to have a
> general "set" data structure.  It's the work of half a dozen lines to
> build the relevant operations around hash tables, but it seemed a bit odd
> that there wasn't one as standard, or even in user-contributed libraries.
> Does CL have a Set collection class?  Maybe I've been using the wrong
> search terms...  (SET-DIFFERENCE isn't quite what I was looking for, but
> it's in the ballpark.)
> 
> Cheers,

-- 
http://lispm.dyndns.org
From: Robert Uhl
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m38xd6dalw.fsf@latakia.dyndns.org>
Rainer Joswig <······@lisp.de> writes:
>
> Some Lisp systems have followed the class-based message passing route
> (for example: Flavors). After some time the message sending seemed to
> be just another mechanism to invoke functions on data.  So 'Message
> sending' got replaced with 'Function Calling' in New Flavors. Still
> there was this single dispatch thing.  That got extended to multiple
> dispatch with CLOS.

To elaborate, a first-try Lispy message dispatching system might use
this sort of syntax:

  (dispatch object message &rest args)

e.g.

  (dispatch foo 'my-print "1 2 3")

A second-generation Lispy message dispatcher might realise that this
could be simplified to:

  (my-print foo "1 2 3")

It'd this be a function calling OO system.  And then one day some-one
would realise that this is just a special case of specialising on _all_
arguments.  Which brings us to be able to do different things based on
the class of the first argument (as ever), but also on the rest of the
arguments too (which is pretty cool).

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
All parts should go together without forcing.  You must remember that the
parts you are reassembling were disassembled by you.  Therefore, if you
can't get them together again, there must be a reason.  By all means, do
not use a hammer.                         --IBM maintenance manual, 1925
From: Holger Schauer
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <yxz648euas6.fsf@gmx.de>
On 4960 September 1993, Andrew Reilly wrote:
> I admit that I came to obects via abstract data types and object pascal
> and smalltalk.  In that context an object (or at least a class) *is* its
> methods.  If a class doesn't have methods, then in what sense is it a
> class?  CLOS has classes, right?

It's the question of "have" that's at the core of the matter. For
instance, it's typical for CLOS classes to define accessors for slots,
like so:

(defclass artist ()
  ((name :accessor name)))

You can use them like what you would expect in single dispatch
classes:

CL-USER> (let ((miles (make-instance 'artist)))
	   (setf (name miles) "Miles Davis")
	   (name miles))
"Miles Davis"

However, this sort of setter/getter functions/methods, as they are
specifically provided by defclass:

CL-USER> (describe 'name)
NAME is an internal symbol in #<PACKAGE "COMMON-LISP-USER">.
#<STANDARD-GENERIC-FUNCTION NAME (1)> is a generic function.
Its lambda-list is:
  (ARTIST)
Its method-combination is:
  #<SB-PCL::STANDARD-METHOD-COMBINATION STANDARD NIL {91C7E99}>
Its methods are:
  (NAME (ARTIST))
    Method documentation: automatically generated reader method
; No value
CL-USER> 

I happen to see multiple dispatch as a dramatically more elegant way
to describe the *behaviour* of objects (which to me seems to be what
you're after with your "a class is its methods"). Multiple dispatch
allows one to define which objects *collaborate*, rather than to
define ownership of some particular behaviour.

Holger

-- 
---          http://hillview.bugwriter.net/            ---
"You see, when you upload, the computer has to push the bits upward,
 and let me tell you, when you're talking millions of bits, it gets
 heavy. When you download, the bits just fall by gravity, so it's much
 faster (we provided you with some remarkable cushioning functions that
 prevent damage to your data). Non-ADSL? They use helium. That's why
 it's more expensive." -- seen on WTF
%
From: Holger Schauer
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <yxz3b3iu91o.fsf@gmx.de>
[Supersede, the original version was so unreadable that it was misleading]

On 4960 September 1993, Andrew Reilly wrote:
> I admit that I came to obects via abstract data types and object pascal
> and smalltalk.  In that context an object (or at least a class) *is* its
> methods.  If a class doesn't have methods, then in what sense is it a
> class?  CLOS has classes, right?

It's the question of "have" that's at the core of the matter. For
instance, it's typical for CLOS classes to define accessors for slots,
like so:

(defclass artist ()
  ((name :accessor name)))

You can use them like what you would expect in single dispatch
oop:

CL-USER> (let ((miles (make-instance 'artist)))
	   (setf (name miles) "Miles Davis")
	   (name miles))
"Miles Davis"

So, one might say that CLOS objects do have methods. However, this
sort of setter/getter functions/methods is a special case, as they are
specifically provided generic functions by defclass, dispatching on
the class argument:

CL-USER> (describe 'name)
NAME is an internal symbol in #<PACKAGE "COMMON-LISP-USER">.
#<STANDARD-GENERIC-FUNCTION NAME (1)> is a generic function.
Its lambda-list is:
  (ARTIST)
Its method-combination is:
  #<SB-PCL::STANDARD-METHOD-COMBINATION STANDARD NIL {91C7E99}>
Its methods are:
  (NAME (ARTIST))
    Method documentation: automatically generated reader method
; No value
CL-USER> 

Now, if you just define methods that take no argument or dispatch
solely on the one argument for your class, you could equally argue
that your class somehow has these methods. However, I don't think that
makes sense. Even more so, whenever I'm programming in some other
non-clos OO system, I stumble quite inevitably about some behaviour
that I can't really attribute to one object or the other. In CLOS, I
would simply use a generic method specializing one both involved. In a
single dispatch system, I have the choice to either split up the
behaviour in several distinct methods for the participating objects
and make an arbitrary decision which of those takes the controlling
part or to introduce some awkward ControllsBothObjectsAandB
class/interface. 

I happen to see multiple dispatch as a dramatically more elegant way
to describe the behaviour of objects (which to me seems to be what
you're after with your "a class is its methods") and their
collaboration. Method definition in CLOS is not about specifying
ownership (most single dispatch OO languages also take a bondage and
discipline approach to OO, why is that? Ruby seems to be a notable
exception).

Holger

-- 
---          http://hillview.bugwriter.net/            ---
"You see, when you upload, the computer has to push the bits upward,
 and let me tell you, when you're talking millions of bits, it gets
 heavy. When you download, the bits just fall by gravity, so it's much
 faster (we provided you with some remarkable cushioning functions that
 prevent damage to your data). Non-ADSL? They use helium. That's why
 it's more expensive." -- seen on WTF
From: Luís Oliveira
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m1abxuv6h1.fsf@deadspam.com>
George Neuner <·········@comcast.net> writes:
> In most popular OO language, methods don't "live" in objects, they
> live in classes - conceptually at least.  We can debate endlessly
> whether, conceptually, a class is itself an object.

What's there to debate?

  * (describe (make-instance 'standard-class))

  #<STANDARD-CLASS NIL> is a class. It is an instance of STANDARD-CLASS.
  It has no name (the name is NIL).
  ...

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/
From: George Neuner
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <kclr03hoi3ou4othvd0pj7880i4h7m3rr8@4ax.com>
On Fri, 30 Mar 2007 21:09:30 +0100, ·············@deadspam.com (Lu�s
Oliveira) wrote:

>George Neuner <·········@comcast.net> writes:
>> In most popular OO language, methods don't "live" in objects, they
>> live in classes - conceptually at least.  We can debate endlessly
>> whether, conceptually, a class is itself an object.
>
>What's there to debate?
>
>  * (describe (make-instance 'standard-class))
>
>  #<STANDARD-CLASS NIL> is a class. It is an instance of STANDARD-CLASS.
>  It has no name (the name is NIL).
>  ...

I said "conceptually" - asking whether a class is an object is similar
to asking whether a set can be an member of itself.  The answer
depends on how you look at it.

Lisp does implement classes as objects but that is only one possible
implementation.

George
--
for email reply remove "/" from address
From: Vassil Nikolov
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m3abxugg6j.fsf@localhost.localdomain>
On Fri, 30 Mar 2007 04:03:58 -0400, George Neuner <·········@comcast.net> said:
| On 29 Mar 2007 13:14:43 -0700, ······@evins.net"
| <···········@gmail.com> wrote:
| ...
|| "This" (or "self") means "the object this function lives in." 

| No.  OO languages encourage associating functions and data through
| many small namespaces (aka classes).  A computation typically passes
| through many such namespaces so there must be a way to designate both
| the current namepace and the one to which the computation should
| proceed.  "this" and "self" are just ways of designating the current
| namespace.  Lisp uses its package system for this purpose.  Though
| packages are typically used at a larger granularity than classes, they
| need not be.

  "this" or "self" is not (just) a namespace---it is a (runtime)
  environment, i.e. an execution context.

  ---Vassil.


-- 
The truly good code is the obviously correct code.
From: Rob St. Amant
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <etgmt3$edm$2@blackhelicopter.databasix.com>
Brian Adkins <·················@gmail.com> writes:

> 19         (when (setf logged-in-user ???)
> 20           (setf (gethash :user-id (session x)) (id logged-in-user))
> 21           (redirect-to-original))))))

In this situation some people like anaphoric macros:

(defmacro awhen (test-form &body body)
  `(let ((it ,test-form))
     (when it ,@body)))

. . .
19         (awhen <something that computes a logged-in-user>
20           (setf (gethash :user-id (session x)) (id it))
21           (redirect-to-original x))))))
From: Luís Oliveira
Subject: Re: Porting Ruby snippet to Lisp
Date: 
Message-ID: <m1bqisou68.fsf@deadspam.com>
·······@ncsu.edu (Rob St. Amant) writes:
> In this situation some people like anaphoric macros:
>
> (defmacro awhen (test-form &body body)
>   `(let ((it ,test-form))
>      (when it ,@body)))

Others prefer LET-WHEN:

  (defmacro let-when ((var test-form) &body body)
    `(let ((,var ,test-form))
        (when ,var ,@body)))

> 19         (awhen <something that computes a logged-in-user>
> 20           (setf (gethash :user-id (session x)) (id it))
> 21           (redirect-to-original x))))))

  (let-when (user <something that computes a logged-in-user>)
    (setf (gethash :user-id (session x)) (id user))
    (redirecto-to-original x))

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/