f



Python's __getattr__, Perl's autoload, Ruby's method_missing, and Smalltalk's #doesNotUnderstand

I'm still new here, and I just completed reading CLTL's documentation
on packages and On Lisp's documentation on CLOS.

It doesn't appear that Lisp has the equivalent of Python's
__getattr__, Perl's autoload, Ruby's method_missing, and Smalltalk's
#doesNotUnderstand. That is, there is no way I can do this (without
new-function being defined):

  (new-function)

and have it call some other function like this:

  (missing-symbol 'new-function)

whose returning value will be evaluated as the value of new-function.

Or did I miss something?
0
jgardner (198)
4/2/2008 6:20:59 PM
comp.lang.lisp 16861 articles. 5 followers. Post Follow

27 Replies
5974 Views

Similar Articles

[PageSpeed] 6

Jonathan Gardner <jgardner@jonathangardner.net> writes:

> I'm still new here, and I just completed reading CLTL's documentation
> on packages and On Lisp's documentation on CLOS.
>
> It doesn't appear that Lisp has the equivalent of Python's
> __getattr__, Perl's autoload, Ruby's method_missing, and Smalltalk's
> #doesNotUnderstand. That is, there is no way I can do this (without
> new-function being defined):
>
>   (new-function)
2>
> and have it call some other function like this:
>
>   (missing-symbol 'new-function)
>
> whose returning value will be evaluated as the value of new-function.
>
> Or did I miss something?

Yes.


CL:UNDEFINED-FUNCTION
CL:NO-APPLICABLE-METHOD

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

"Specifications are for the weak and timid!"
0
pjb (7869)
4/2/2008 6:38:49 PM
Jonathan Gardner <jgardner@jonathangardner.net> writes:

> I'm still new here, and I just completed reading CLTL's documentation
> on packages and On Lisp's documentation on CLOS.
>
> It doesn't appear that Lisp has the equivalent of Python's
> __getattr__, Perl's autoload, Ruby's method_missing, and Smalltalk's
> #doesNotUnderstand. That is, there is no way I can do this (without
> new-function being defined):
>
>   (new-function)
>
> and have it call some other function like this:
>
>   (missing-symbol 'new-function)
>
> whose returning value will be evaluated as the value of new-function.
>
> Or did I miss something?

No, there's nothing quite like you describe.

In CLOS, there are a few generic functions to handle missing things,
like NO-APPLICABLE-METHOD, SLOT-MISSING, NO-NEXT-METHOD, SLOT-UNBOUND,
and perhaps others. You can hang methods on them to customize
behavior; I use UNBOUND-SLOT pretty often to lazily initialize
instances.

Zach
0
xach (899)
4/2/2008 6:44:04 PM
Jonathan Gardner <jgardner@jonathangardner.net> writes:

>  [..] (new-function) and have it call some other function like this:> 
>  (missing-symbol 'new-function)

Firstly, what would you use this for? I mean, either you know the name
of new-function a priori, in which case you can just define it to do
whatever. If you don't know it, I don't quite have the imagination to
see what you could do. Some sort of autoloading, perhaps?

Anyways, what happens when an undefined function is called, is that an
"undefined-function" condition is signaled, and you can handle it
however you see fit, possibly taking advantage of the use-value or
store-value restarts.

-- 
Frode Vatvedt Fjeld
0
frodef (343)
4/2/2008 6:55:32 PM
On Apr 2, 11:55=A0am, Frode Vatvedt Fjeld <fro...@cs.uit.no> wrote:
> Jonathan Gardner <jgard...@jonathangardner.net> writes:
> > =A0[..] (new-function) and have it call some other function like this:>
> > =A0(missing-symbol 'new-function)
>
> Firstly, what would you use this for? I mean, either you know the name
> of new-function a priori, in which case you can just define it to do
> whatever. If you don't know it, I don't quite have the imagination to
> see what you could do. Some sort of autoloading, perhaps?
>

In this case, there is this C++ library, Qt, which is truly massive.
Rather than take all the header files and compile them into Lisp
wrappers, I'd rather take the approach that PerlQt and RubyQt take
with Smoke: Just pretend like the users know what they are doing and
if they name an object or a method, go look it up.

Yes, this is a horrible way, and it defeats a lot of optimizations,
and it is not nice nor pretty. Well, maybe it is pretty compared to
the alternative, considering the fact that it is the app developers
and not the binding developer who has to update their code.

> Anyways, what happens when an undefined function is called, is that an
> "undefined-function" condition is signaled, and you can handle it
> however you see fit, possibly taking advantage of the use-value or
> store-value restarts.
>

I'm going to read about exception handling now. It looks like you can
do more in Lisp with an exception than you can in Python.

0
jgardner (198)
4/2/2008 9:58:29 PM
On Apr 2, 11:44=A0am, Zach Beane <x...@xach.com> wrote:
>
> In CLOS, there are a few generic functions to handle missing things,
> like NO-APPLICABLE-METHOD, SLOT-MISSING, NO-NEXT-METHOD, SLOT-UNBOUND,
> and perhaps others. You can hang methods on them to customize
> behavior; I use UNBOUND-SLOT pretty often to lazily initialize
> instances.
>

I'll take a look at these. It sounds like it may be sufficient.

0
jgardner (198)
4/2/2008 9:59:10 PM
On Apr 2, 2:55 pm, Frode Vatvedt Fjeld <fro...@cs.uit.no> wrote:
> Jonathan Gardner <jgard...@jonathangardner.net> writes:
> >  [..] (new-function) and have it call some other function like this:>
> >  (missing-symbol 'new-function)
>
> Firstly, what would you use this for? I mean, either you know the name
> of new-function a priori, in which case you can just define it to do
> whatever. If you don't know it, I don't quite have the imagination to
> see what you could do. Some sort of autoloading, perhaps?

One application would be dynamic SQL queries such as the following
using Ruby syntax:

User.find_by_email('foo@bar.com')

the 'find_by_email' method doesn't exist, but the correct SQL can be
generated from the name and a reconstituted User can be returned.

select * from users where email = 'foo@bar.com';

Brian Adkins
0
lojicdotcom (362)
4/5/2008 4:01:13 PM
Brian Adkins <lojicdotcom@gmail.com> writes:

> One application would be dynamic SQL queries such as the following
> using Ruby syntax:
> 
> User.find_by_email('foo@bar.com')

How would this be an improvement over something obvious like
User.query("email = foo@bar.com") ?

-- 
Frode Vatvedt Fjeld
0
frodef (343)
4/5/2008 10:12:21 PM
Frode Vatvedt Fjeld <frodef@cs.uit.no> writes:

> Brian Adkins <lojicdotcom@gmail.com> writes:
>
>> One application would be dynamic SQL queries such as the following
>> using Ruby syntax:
>> 
>> User.find_by_email('foo@bar.com')
>
> How would this be an improvement over something obvious like
> User.query("email = foo@bar.com") ?

Because you need to take care of quoting yourself in your
alternative. Much better to let the database abstraction take care of it
automatically.

Anyway, the find_by_email stuff could just as easily be generated from
the database schema, I think, which means you don't need to wait for it
to be called and catch the method call.

-- 
Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
0
joost1 (187)
4/5/2008 10:17:33 PM
Then user.find_by(field, value) and have find_by deal with it.
0
jeffober (108)
4/5/2008 10:42:11 PM
Joost Diepenmaat <joost@zeekat.nl> writes:

>
> Because you need to take care of quoting yourself in your
> alternative. Much better to let the database abstraction take care of it
> automatically.
>
> Anyway, the find_by_email stuff could just as easily be generated from
> the database schema, I think, which means you don't need to wait for it
> to be called and catch the method call.
>

Then when you read the database schema you can generate at runtime all
the find-by-*, without the need of catching a missing method. Then I
agree with what others said: email is a parameter, not a part of the
name of the function.

> -- 
> Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/

-- 
Luigi Panzeri aka Matley

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Quotes on Lisp: http://lispers.org/
0
matley (20)
4/8/2008 10:23:50 PM
Luigi Panzeri <matley@muppetslab.org> writes:

> Joost Diepenmaat <joost@zeekat.nl> writes:
>
>>
>> Because you need to take care of quoting yourself in your
>> alternative. Much better to let the database abstraction take care of it
>> automatically.
>>
>> Anyway, the find_by_email stuff could just as easily be generated from
>> the database schema, I think, which means you don't need to wait for it
>> to be called and catch the method call.
>>
>
> Then when you read the database schema you can generate at runtime all
> the find-by-*, without the need of catching a missing method. Then I
> agree with what others said: email is a parameter, not a part of the
> name of the function.

If you want to look at it that way, yes. You could also look at it as a
(probably useless in this simple case) optimization, though I suspect if
the queries get more complex it could win you some thinking. Or you
could just see it as a way to have auto-completion DWIM for simple
queries in your Lisp editor environment. I don't think it's a big issue
in general, either way.

-- 
Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
0
joost1 (187)
4/9/2008 12:03:55 AM
On Apr 5, 6:17 pm, Joost Diepenmaat <jo...@zeekat.nl> wrote:
> Frode Vatvedt Fjeld <fro...@cs.uit.no> writes:
>
> > Brian Adkins <lojicdot...@gmail.com> writes:
>
> >> One application would be dynamic SQL queries such as the following
> >> using Ruby syntax:
>
> >> User.find_by_email('...@bar.com')
>
> > How would this be an improvement over something obvious like
> > User.query("email = f...@bar.com") ?
>
> Because you need to take care of quoting yourself in your
> alternative. Much better to let the database abstraction take care of it
> automatically.
>
> Anyway, the find_by_email stuff could just as easily be generated from
> the database schema, I think, which means you don't need to wait for it
> to be called and catch the method call.

Do you want to generate finders for all combinations of n attributes
when you might only use a small fraction of them? I believe 10
attributes limited to combination of no more than 3 is 820 functions.
0
lojicdotcom (362)
4/11/2008 12:36:49 AM
Brian Adkins <lojicdotcom@gmail.com> writes:

> On Apr 5, 6:17 pm, Joost Diepenmaat <jo...@zeekat.nl> wrote:
>> Anyway, the find_by_email stuff could just as easily be generated from
>> the database schema, I think, which means you don't need to wait for it
>> to be called and catch the method call.
>
> Do you want to generate finders for all combinations of n attributes
> when you might only use a small fraction of them? I believe 10
> attributes limited to combination of no more than 3 is 820 functions.

Even if so, so what? 820 methods isn't exactly a lot, at least not if
you don't have to type them yourself.

But let's just assume that most queries limit themselves to 1 or 2
columns, and leave the rest to be hand-written (or auto-generated when
requested in some way), if you're so concerned.

-- 
Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
0
joost1 (187)
4/11/2008 1:05:31 AM
Brian Adkins <lojicdotcom@gmail.com> writes:

> On Apr 2, 2:55 pm, Frode Vatvedt Fjeld <fro...@cs.uit.no> wrote:
>> Jonathan Gardner <jgard...@jonathangardner.net> writes:
>> >  [..] (new-function) and have it call some other function like this:>
>> >  (missing-symbol 'new-function)
>>
>> Firstly, what would you use this for? I mean, either you know the name
>> of new-function a priori, in which case you can just define it to do
>> whatever. If you don't know it, I don't quite have the imagination to
>> see what you could do. Some sort of autoloading, perhaps?
>
> One application would be dynamic SQL queries such as the following
> using Ruby syntax:
>
> User.find_by_email('foo@bar.com')
>
> the 'find_by_email' method doesn't exist, but the correct SQL can be
> generated from the name and a reconstituted User can be returned.
>
> select * from users where email = 'foo@bar.com';

Wouldn't (find-user :email "foo@bar.com") work just as well?

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
From my cold dead hands, my ass.  I'll be taking their issue weapons
from their cold dead hands.  I fight to win.              --KBarrett
0
eadmund42 (519)
4/14/2008 6:14:06 PM
On Apr 14, 2:14 pm, Robert Uhl <eadmun...@NOSPAMgmail.com> wrote:
> Brian Adkins <lojicdot...@gmail.com> writes:
> > On Apr 2, 2:55 pm, Frode Vatvedt Fjeld <fro...@cs.uit.no> wrote:
> >> Jonathan Gardner <jgard...@jonathangardner.net> writes:
> >> >  [..] (new-function) and have it call some other function like this:>
> >> >  (missing-symbol 'new-function)
>
> >> Firstly, what would you use this for? I mean, either you know the name
> >> of new-function a priori, in which case you can just define it to do
> >> whatever. If you don't know it, I don't quite have the imagination to
> >> see what you could do. Some sort of autoloading, perhaps?
>
> > One application would be dynamic SQL queries such as the following
> > using Ruby syntax:
>
> > User.find_by_email('...@bar.com')
>
> > the 'find_by_email' method doesn't exist, but the correct SQL can be
> > generated from the name and a reconstituted User can be returned.
>
> > select * from users where email = '...@bar.com';
>
> Wouldn't (find-user :email "f...@bar.com") work just as well?

That depends - do you have something in place to automatically convert
that into code, or would you have to implement the find-user function
yourself? This facility is from the Rails framework and it includes
querying on multiple attributes and retrieving single or multiple
values. For example:

User.find_all_by_state_and_status('NY', STATUS_ACTIVE)

the alternative in Rails would be:

User.find(:all,
  conditions => ['state = ? and status = ?', 'NY', STATUS_ACTIVE])

so it's a bit shorter and more convenient in this case to use the
dynamic queries for simple retrieval.

0
lojicdotcom (362)
4/15/2008 1:52:19 PM
Frode Vatvedt Fjeld wrote:
> Jonathan Gardner <jgardner@jonathangardner.net> writes:
> 
>>  [..] (new-function) and have it call some other function like this:> 
>>  (missing-symbol 'new-function)
> 
> Firstly, what would you use this for? 

The one I have most often used it for...

It makes generic delegation really easy...

you just forward unhandled methods to the delegate, let it worry about
whether it responds or not.

and in perl it makes encapsulation easier by allowing for really easy getter/setters
that are easy to override.
0
sean6182 (11)
4/16/2008 7:43:56 PM
Frode Vatvedt Fjeld wrote:
> Jonathan Gardner <jgardner@jonathangardner.net> writes:
> 
>>  [..] (new-function) and have it call some other function like this:> 
>>  (missing-symbol 'new-function)
> 
> Firstly, what would you use this for? 

The one I have most often used it for...

It makes generic delegation really easy...

you just forward unhandled methods to the delegate, let it worry about
whether it responds or not.

and in perl it makes encapsulation easier by allowing for really easy getter/setters
that are easy to override.
0
sean6182 (11)
4/16/2008 7:44:33 PM
Sean T Allen <sean@monkeysnatchbanana.com> writes:
> and in perl it makes encapsulation easier by allowing for really
> easy getter/setters that are easy to override.

     Proliferation of accessors and mutators violates encapsulation.
Objects should have behavior that is invoked, not effectively public
state that is manipulated.  If you find yourself needing to manipulate
the innards of another object, you probably need to repartition your
behaviors.

Regards,

Patrick

------------------------------------------------------------------------
S P Engineering, Inc.  | Large scale, mission-critical, distributed OO
                       | systems design and implementation.
          pjm@spe.com  | (C++, Java, Common Lisp, Jini, middleware, SOA)
0
pjm (703)
4/17/2008 1:32:14 PM
On Apr 2, 2:59 pm, Jonathan Gardner <jgard...@jonathangardner.net>
wrote:
> On Apr 2, 11:44 am, Zach Beane <x...@xach.com> wrote:
> > In CLOS, there are a few generic functions to handle missing things,
> > like NO-APPLICABLE-METHOD, SLOT-MISSING, NO-NEXT-METHOD, SLOT-UNBOUND,
> > and perhaps others. You can hang methods on them to customize
> > behavior; I use UNBOUND-SLOT pretty often to lazily initialize
> > instances.
>
> I'll take a look at these. It sounds like it may be sufficient.

Here's what I found. Reading some of the posts below, I have now come
to conclude that Python, perl, Ruby and smalltalk are all wrong when
it comes to this kind of behavior.

Then why do those languages have this kind of feature?

It is because manually specifying all of the possible ways you can
interact with the object is difficult. You cannot take advantages of
the patterns evident in such code, so you must write a routine that
effectively acts as the eval operation in trying to take a symbol or
an expression and discover its real meaning, evaluate what value it
should have right now, and return that.

In Lisp, you can write a macro to eliminate the need for this kind of
thing. The language is not a barrier since the language (the syntax at
least) doesn't exist. Any programming concept you can imagine is
simply expressed almost exactly the way it is thought of.

As far as lazily loading things, that is not what Python and perl et
al are doing. Lazily loading things is like saying, "I have this code
over here that describes the behavior that you might need, but since
you probably don't need it right now (or ever), I won't load it--yet."

Lazily loading is a good thing. It makes a modern OS that has programs
and libraries that extend way beyond the capacity of memory possible
by loading only what is needed and no more.

What Python, perl, et al authors are saying when they use this feature
is, "I know how to do this thing, but I am too lazy to write it out so
that the language can find it, compile it, and optimize it. Instead, I
am going to pretend I know better than the language and implement my
own version of eval."

So this is another feature that was invented because the languages do
not support macros. It is, in a way, a poor-man's macro.
0
jgardner (198)
4/17/2008 4:56:20 PM
On 2008-04-17 09:32:14 -0400, Patrick May <pjm@spe.com> said:

> Sean T Allen <sean@monkeysnatchbanana.com> writes:
>> and in perl it makes encapsulation easier by allowing for really
>> easy getter/setters that are easy to override.
> 
>      Proliferation of accessors and mutators violates encapsulation.
> Objects should have behavior that is invoked, not effectively public
> state that is manipulated.  If you find yourself needing to manipulate
> the innards of another object, you probably need to repartition your
> behaviors.
> 

I think you might have misunderstood or arent familiar with perl.
You can use perls AUTOLOAD to make encapsulation easier.

Usually a perl object stores its state in a 'blessed' hash.
Anyone can access this state.

However if you have say

name
phone

as attributes you can use AUTOLOAD to automatically create
name and phone get/set attributes w/o coding them which can
then be overriden if something more than

return name

or

name = new_name is needed

In this way, it becomes a perl-ish version of :accessor

You cant in perl keep someone out of your innards but if you have 10-15 
attributes,
you can save coding basic get/set operations by using AUTOLOAD and only
overriding the couple that have complicated interactions. Then instead of
directly accesing the attribute by

$object->{ 'attribute' } and violating encapsulation, the caller does 
$object->attribute()





0
sean6182 (11)
4/17/2008 8:58:41 PM
Sean T Allen <sean@monkeysnatchbanana.com> writes:
> On 2008-04-17 09:32:14 -0400, Patrick May <pjm@spe.com> said:
>> Sean T Allen <sean@monkeysnatchbanana.com> writes:
>>> and in perl it makes encapsulation easier by allowing for really
>>> easy getter/setters that are easy to override.
>>
>>      Proliferation of accessors and mutators violates
>> encapsulation.  Objects should have behavior that is invoked, not
>> effectively public state that is manipulated.  If you find yourself
>> needing to manipulate the innards of another object, you probably
>> need to repartition your behaviors.
>
> I think you might have misunderstood or arent familiar with perl.

     I'm trying to keep it that way.  I've learned Perl three or four
times now.  If I don't use it for six months it doesn't stick in my
head.

> Usually a perl object stores its state in a 'blessed' hash.
> Anyone can access this state.
>
> However if you have say
>
> name
> phone
>
> as attributes you can use AUTOLOAD to automatically create
> name and phone get/set attributes w/o coding them which can
> then be overriden if something more than
>
> return name
>
> or
>
> name = new_name is needed
>
> In this way, it becomes a perl-ish version of :accessor
>
> You cant in perl keep someone out of your innards but if you have
> 10-15 attributes,
> you can save coding basic get/set operations by using AUTOLOAD and only
> overriding the couple that have complicated interactions. Then instead of
> directly accesing the attribute by

     This is the point I with which I was taking issue.  Getters and
setters should not be generated by default.  They are a code smell.
In a well-designed OO application there will be very few accessors and
even fewer mutators.  Objects should tell other objects what needs to
be done, not pull data out of them ("Tell, don't ask.").

Regards,

Patrick

------------------------------------------------------------------------
S P Engineering, Inc.  | Large scale, mission-critical, distributed OO
                       | systems design and implementation.
          pjm@spe.com  | (C++, Java, Common Lisp, Jini, middleware, SOA)
0
pjm (703)
4/18/2008 3:44:54 PM
>> 
>> You cant in perl keep someone out of your innards but if you have
>> 10-15 attributes,
>> you can save coding basic get/set operations by using AUTOLOAD and only
>> overriding the couple that have complicated interactions. Then instead of
>> directly accesing the attribute by
> 
>      This is the point I with which I was taking issue.  Getters and
> setters should not be generated by default.  They are a code smell.
> In a well-designed OO application there will be very few accessors and
> even fewer mutators.  Objects should tell other objects what needs to
> be done, not pull data out of them ("Tell, don't ask.").
> 
> 
> I

I understand but given the alternative in perl, this is a better alternative.
I've seen tons of code where it is standard operating procedure for
programmers to go directly into the internal state of an object to get 
what they
need. At least this idiom prevents that horrid sin with a lesser sin.

Perl's OO is nasty but the question people asked was 'what would you 
use that for'
not in an ideal world should the idiom you are going to describe even exist.

I've hacked at lots of perl, python and ruby code over the years and 
they all have idioms
which are idiotic compared to features from other languages but that is why
they are idioms, they are there to make up for a 'missing' feature. And with
that statement, I open myself up to people who think enforcing object 
encapsulation at the
language level is bad.

-Sean-

p.s. you should see what the idioms to provide 'private' instance state 
look like in perl.
lord o lord. still it makes my brain hurt less than some other languages.


0
sean6182 (11)
4/18/2008 4:42:10 PM
Brian Adkins <lojicdotcom@gmail.com> writes:
>
>> > One application would be dynamic SQL queries such as the following
>> > using Ruby syntax:
>>
>> > User.find_by_email('...@bar.com')
>>
>> > the 'find_by_email' method doesn't exist, but the correct SQL can be
>> > generated from the name and a reconstituted User can be returned.
>>
>> > select * from users where email = '...@bar.com';
>>
>> Wouldn't (find-user :email "f...@bar.com") work just as well?
>
> That depends - do you have something in place to automatically convert
> that into code, or would you have to implement the find-user function
> yourself?

CLSQL provides some :where facilities which I think could be used to
do this kind of thing with very little effort, to the point that a macro
which generated find-FOO functions could be written.

I do it with the framework I use for my Tasting Notes app: every class
support a FIND-OBJECT function which Does the Right Thing.

> This facility is from the Rails framework and it includes
> querying on multiple attributes and retrieving single or multiple
> values. For example:
>
> User.find_all_by_state_and_status('NY', STATUS_ACTIVE)
>
> the alternative in Rails would be:
>
> User.find(:all,
>   conditions => ['state = ? and status = ?', 'NY', STATUS_ACTIVE])
>
> so it's a bit shorter and more convenient in this case to use the
> dynamic queries for simple retrieval.

I thinks it's kinda un-Lispy to do that.

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
Yes, truly it is the purple Dodge Neon of single malts.
                     --Malcolm Ray, rating Glenfiddich
0
eadmund42 (519)
4/21/2008 6:16:41 PM
> 
>> This facility is from the Rails framework and it includes
>> querying on multiple attributes and retrieving single or multiple
>> values. For example:
>> 
>> User.find_all_by_state_and_status('NY', STATUS_ACTIVE)
>> 
>> the alternative in Rails would be:
>> 
>> User.find(:all,
>> conditions => ['state = ? and status = ?', 'NY', STATUS_ACTIVE])
>> 
>> so it's a bit shorter and more convenient in this case to use the
>> dynamic queries for simple retrieval.
> 
> I thinks it's kinda un-Lispy to do that.

as I am making my first serious plunge into Common Lisp after only
really using lisp for emacs customizations etc that I needed.

What would be the lisp way to do that?

macros are what immediately jumps into my mind but perhaps there
are others. I've been having eureka moments the past few days,
so I'd love to pile still more on there while the brain is hot ( yes,
that was some serious metaphor abuse )

-S-

0
sean6182 (11)
4/21/2008 6:48:40 PM
Robert Uhl wrote:
> Brian Adkins <lojicdotcom@gmail.com> writes:
>>>> One application would be dynamic SQL queries such as the following
>>>> using Ruby syntax:
>>>> User.find_by_email('...@bar.com')
>>>> the 'find_by_email' method doesn't exist, but the correct SQL can be
>>>> generated from the name and a reconstituted User can be returned.
>>>> select * from users where email = '...@bar.com';
>>> Wouldn't (find-user :email "f...@bar.com") work just as well?
>> That depends - do you have something in place to automatically convert
>> that into code, or would you have to implement the find-user function
>> yourself?
> 
> CLSQL provides some :where facilities which I think could be used to
> do this kind of thing with very little effort, to the point that a macro
> which generated find-FOO functions could be written.
> 
> I do it with the framework I use for my Tasting Notes app: every class
> support a FIND-OBJECT function which Does the Right Thing.

My own invented-here hack:

http://uint32t.blogspot.com/2008/01/some-useful-clsql-helper-functions.html

CL-USER> (find-one 'user :user-login "sohail"
                          :user-password "myhashedpassword")
#<USER {B47D0C9}>
CL-USER> (find-all 'user :user-site-id 3)
(#<USER {B729209}> #<USER {B72AD81}>)

Done in about 5 minutes so missing some stuff like :where <random clause 
here> but I think this is much less magic and more penetrable than the 
equivalent Rails.
0
sohail1 (186)
4/21/2008 8:41:47 PM
Sean T Allen <sean@monkeysnatchbanana.com> writes:

>>
>>> This facility is from the Rails framework and it includes
>>> querying on multiple attributes and retrieving single or multiple
>>> values. For example:
>>>
>>> User.find_all_by_state_and_status('NY', STATUS_ACTIVE)
>>>
>>> the alternative in Rails would be:
>>>
>>> User.find(:all,
>>> conditions => ['state = ? and status = ?', 'NY', STATUS_ACTIVE])
>>>
>>> so it's a bit shorter and more convenient in this case to use the
>>> dynamic queries for simple retrieval.
>>
>> I thinks it's kinda un-Lispy to do that.
>
> as I am making my first serious plunge into Common Lisp after only
> really using lisp for emacs customizations etc that I needed.
>
> What would be the lisp way to do that?

(find-user :state "NY" :status 'active)

In some of the work I was doing for my roguelike (now back-burnered
because Real Life(tm) has interfered), I started out expanding
(define-weapon foo ...) into (defclass weapon-foo) and that kind of
thing.  I liked it at first, but as I used it more I realised that it
just didn't feel right.  (intern (concatenate 'string "FOO-"
(symbol-name))) just didn't seem 'normal'; doing similar stuff with
function names (catching undefined functions and decomposing their names
to figure out their arguments and so forth) just seems _ugly_.

Any code which can break down a function name into argument names and
associate those with positional arguments could do the same with
&rest (or whatever).  And it wouldn't require cluttering up the function
namespace, or trying to figure out what every undefined function means.

> macros are what immediately jumps into my mind but perhaps there
> are others.

In the case of my Tasting Notes code, there's just this:

  (defgeneric get-by-key (class &rest key)
    (:documentation "GET-BY-KEY
  
  Look up an object in CLASS."))
  
  (defmethod get-by-key (class &rest key)
    (first (select class :where [= [name] (first key)] :flatp t)))
  
  (defmethod get-by-key ((class (eql 'beer)) &rest key)
    (first (select 'beer :where [and [= [brewer] (first key)] [= [name] (second key)]] :flatp t)))

So one can write (get-by-key 'bar "Falling Rock Taphouse") and
(get-by-key "New Belgium" "La Folie") alike.  It's not ideal for every
case, but it works for me.  In my schema keys have an implicit order, so
I can just use ordered params; in a more general solution keywords would
be where it's at (e.g. (get-by-key 'beer :brewer "Rockies Brewing Co."
"Hazed & Infused")).  I do like having the function name free of the
thing being found (e.g. GET-BY-KEY) instead of including it
(e.g. GET-BAR-BY-KEY) because there might be multiple find metaphors in
play, and that it makes more sense to have GET-BY-KEY and GET-LATEST and
GET-MOST-POPULAR and whatever instead of GET-FOO.  Also, as previously
noted, hacking the symbol table gives me a bad feeling.

The code isn't really very pretty (I hate hate
hate CLSQL's syntax, and I probably should have used DESTRUCTURING-BIND
instead of FIRST and SECOND), but it gets the job done.

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
I call these twits pseudo-literate.  That is, they can read but won't.
                                                           --Joe Zeff
0
eadmund42 (519)
4/23/2008 3:26:30 PM
Sohail Somani <sohail@taggedtype.net> writes:
>
> My own invented-here hack:
>
> http://uint32t.blogspot.com/2008/01/some-useful-clsql-helper-functions.html
>
> CL-USER> (find-one 'user :user-login "sohail"
>                          :user-password "myhashedpassword")
> #<USER {B47D0C9}>
> CL-USER> (find-all 'user :user-site-id 3)
> (#<USER {B729209}> #<USER {B72AD81}>)
>
> Done in about 5 minutes so missing some stuff like :where <random clause
> here> but I think this is much less magic and more penetrable than the
> equivalent Rails.

Exactly right.  It's kind of a pity that FIND already exists in CL, but
OTOH it's probably a good thing, since it forces explicit
differentiation between FIND-ONE and FIND-ALL.

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
Govern a great nation as you would cook a small fish.  Don't overdo it.
                                               --attributed to Lao Tzu
0
eadmund42 (519)
4/23/2008 3:27:38 PM
Reply: