From: joswig on
On 2 Feb., 09:39, "W. James" <w_a_x_...(a)yahoo.com> wrote:
> jos...(a)corporate-world.lisp.de wrote:
> > > So my question is: how can I inspect functions to find out how
> > > many arguments it has, for example?
>
> > If we talk about Common Lisp, the standard does not really give you
> > that
> > functionality. There is the function 'function-lambda-expression',
> > which
> > may work or not.
>
> Matzlisp:
>
> f = lambda{|a,b,c| }
>     ==>#<Proc:0x00000000@(irb):22>
> f.arity
>     ==>3

arity is not the argument list.


My Symbolics Lisp Machine:

Command: (arglist #'(lambda (a b c)))
(A B C)
From: Pillsy on
On Feb 1, 5:45 pm, slash dot <tynty...(a)gmail.com> wrote:
[...]
> The caller does this with a lambda retrieved by index:

>     (funcall my-lambda (next-item))  ; note the call to 'next-item'
>                                      ; this is the argument we are
>                                      ; talking about

> However, there is a problem: the caller traverses
> a sequence, calling lambdas for processing data items in packs that
> are of various length. The caller leaves maintaining the iterator to
> other parts of the system. If the caller fetches a value, passes it
> to the lambda, and the lambda does not need it, the system gets
> out of sync. If the called lambda does not consume the passed value,
> it is supposed to be process by a subsequent call to a (potentially
> other) lambda.

Well, here's one possible solution which carries the first-class
function thing a tiny bit further. Right now, presumably, you have
some anonymous functions that look like this:

(lambda ()
(do-stuff-without-consuming-an-item))

and other anonymous functions that look like this:

(lambda (item)
(do-stuff-with item))

However, if you change the place these functions are called to look
like this:

(funcall my-lambda #'next-item)

you can rewrite those anonymous functions to have a uniform argument
list without having to take extra care to keep things synchronized.
Like so:

(lambda (next-item-thunk)
(declare (ignore next-item-thunk))
(do-stuff-without-consuming-an-item)))

(lambda (next-item-thunk)
(let ((item (funcall next-item-thunk)))
(do-stuff-with item)))

This allows you to push all the responsibility for "knowing" whether a
given function in the array consumes an item in the sequence onto that
function itself, which could be a worthwhile simplification, all
issues of introspection aside.

HTH,
Pillsy
From: Duane Rettig on
On Feb 2, 12:10 am, p...(a)informatimago.com (Pascal J. Bourguignon)
wrote:
> "jos...(a)corporate-world.lisp.de" <jos...(a)lisp.de> writes:
> > The function 'function-lambda-expression' is not in ANSI CL,
> > to provide the mental equivalent of 'buffer overflows'.
> > It is meant to provide a stable interface to a functionality
> > that might be there or might not be there - depending on
> > the development environment or deployment situation.
>
> It is  good that an API be defined for when the feature is present,
> but what happens when the feature is not present?

You complain to your CL vendor. If the CL vendor is you (i.e. you use
an open-source CL), you fix it yourself.

> You proposed a first approach, to abort and signal to the user that
> the action cannot be carried on with the current implementation.
>
> But if this is not acceptable, what you have to do anyways, is to
> provide an alternative implementation.  
>
> That is, you have to do the work anyways.
>
>     (if (feature-exist-p)
>        (use-feature)
>        (implement-feature-yourself))
>
> Well, for me, it's simplier to just do:
>
>    (implement-feature-yourself)
>
> > I wish Common Lisp would specify more like this. Functions that
> > are standardized, but their working is optional - like
> > the ability to retrieve arglists, which usually every
> > development environment will provide, but which
> > in a deployment/delivery situation might not work,
> > for example when during delivery debug information
> > has been removed from the application.
>
> It may be acceptable to allow for optional API when there's a human
> programmer or debugger at the other end of the stick.  But not when
> it's a program.  See above.
>
> I wish there wouldn't be optional APIs in a language standard.

How about missing ones? If you took on this attitude consistently
with CL, then you would never call out to C functions (there is no
standard for Foreign Function intreface) nor would you ever open a
socket (for which there is also no standard).

> > For example in Allegro CL the function BUILD-LISP-IMAGE
> > has the option :DISCARD-ARGLISTS . So it is
> > under programmer control whether in Allegro CL
> > arglists are available in an image or not.
> > There is nothing random or dangerous about it.
> > This really has nothing to do with 'buffer overflows'.
>
> Using function-lambda-expression may or may not give the expected
> result.  

Of course not. It is implementation-dependent. But if you look at
the bigger picture, as to _why_ this information is optional (space
savings) or what the liklihood of the information being there is,
you'd find that most CLs have their arglist function because the
argument list is more likely to be worth saving, and it would be a
much safer function (in terms of portability) to use.

> Similarly, writing:
>
>    char* buffer=malloc(10);
>    buffer[11]='a';
>
> may or may not give the expected result.

This is incorrect code, and thus not the equivalent of "implementation-
dependent" behavior, but of "undefined behavior" - not an appropriate
analogy.

> If you're running with an implementation of the C language where
> malloc rounds the size to the next multiple of 8, the above code would
> work perfectly well.  

Yes, an implementation can choose to assign reasonable behaviors for
undefined situations.

> However, there are good reasons why to ostracize it.

The main reason is because the resultant behavior is undefined.

> If your application depends on the availability of the list of
> arguments, then you cannot count on function-lambda-expression any
> more than you can count on buffer overflows working.

Neither do you put your head in the sand. You start by trying to stay
within the spec. You stay away from undefined behaviors. If you must
work with implementation-dependent behaviors, you try to understand
your vendors' implementations, and stay within their guidelines,
possibly choosing extended functionalities over standard-but-less-
likely situations.

Duane
From: joswig on
On 2 Feb., 09:10, p...(a)informatimago.com (Pascal J. Bourguignon)
wrote:

(some parts of the original message are removed ... sorry)

> "jos...(a)corporate-world.lisp.de" <jos...(a)lisp.de> writes:
> > The function 'function-lambda-expression' is not in ANSI CL,
> > to provide the mental equivalent of 'buffer overflows'.
> > It is meant to provide a stable interface to a functionality
> > that might be there or might not be there - depending on
> > the development environment or deployment situation.
>
> It is  good that an API be defined for when the feature is present,
> but what happens when the feature is not present?

Don't use it. Work around it. Implement it. Use another Lisp.
Whatever.

>
> You proposed a first approach, to abort and signal to the user that
> the action cannot be carried on with the current implementation.
>
> But if this is not acceptable, what you have to do anyways, is to
> provide an alternative implementation.  
>
> That is, you have to do the work anyways.
>
>     (if (feature-exist-p)
>        (use-feature)
>        (implement-feature-yourself))

No.

1) make sure the feature exists, for example choosing a specific Lisp
implementation
2) use it

> Well, for me, it's simplier to just do:
>
>    (implement-feature-yourself)

Sure, if it does not exist. But then use the name that the
standard proposes. Done.

> It may be acceptable to allow for optional API when there's a human
> programmer or debugger at the other end of the stick.  But not when
> it's a program.  See above.

The programmer configures the environment, the program is running it.
Done.


> If your application depends on the availability of the list of
> arguments, then you cannot count on function-lambda-expression any
> more than you can count on buffer overflows working.

I can count on what the implementation I use does.
Maybe I have even chosen this implementation because it
provides that feature. Once I use that, the feature
will not be there or absent by random. It's just
a question of configuration.

What some other implementations might do or not - I don't care unless
I need to run my software there.

>
> (Of course, I don't say that you cannot write an application that will
> behave correctly, even conformingly, using function-lambda-expression,
> or overflowing buffers (as long as you catch segv signals, or specify
> the program crash)).

'overflowing buffers' is some other totally unrelated problem.
Sorry, Pascal.

It is the case that some implementations offer more than the standard,
some implementations implement parts of the standard differently,
some don't implement optional behavior. ROOM could print
'memory is fine, management, too. hello, pascal, how are you?'
and be fine. Some implementation prints useful information with ROOM.
You can't depend on it. So what?



From: Pascal J. Bourguignon on

Rainier, Duane, I agree that I could have choosen a better analogy
than buffer overflow. I'm a little lazy.



"joswig(a)corporate-world.lisp.de" <joswig(a)lisp.de> writes:

>> If your application depends on the availability of the list of
>> arguments, then you cannot count on function-lambda-expression any
>> more than you can count on buffer overflows working.
>
> I can count on what the implementation I use does.
> Maybe I have even chosen this implementation because it
> provides that feature. Once I use that, the feature
> will not be there or absent by random. It's just
> a question of configuration.
>
> What some other implementations might do or not - I don't care unless
> I need to run my software there.

Well, it depends on the circumstances.


For my scripts, (what goes in ~/bin and starts with #!/usr/bin/clisp,
I've made indeed this choice of an implementation, and I use freely
enough stuff in the EXT packages (I still prefix it by #+clisp most of
the time, with #-clisp(error "How to do ~S" 'that) alternatives).


However, for the rest of my lisp code, I try to target Common Lisp,
not a specific implementation.




Now more specifically for FUNCTION-LAMBDA-EXPRESSION and ARGLIST, I
maintain my objections, given this later mind set of writing Common
Lisp, and not SBCL or clisp (or a set of implementation) code.


The objection to FUNCTION-LAMBDA-EXPRESSION is that it results depends
on choices orthogonals to the purpose stated in this thread: the
result of this function depends on size optimizations that vary from
implementations or system construction phases. See my example with
clisp, where different results are obtained when loading compiled than
when not compiling the function. In general I would object of
depending on any semantic behavior that would change when going thru
the compiler. The choice of an implementations for me is of the same
order as the choice of using or not COMPILE or COMPILE-FILE. I may:

- run and debug interpreted code in clisp,
- use compile-file in clisp if I'm in a hurry,
- use compile-file in sbcl if I'm in a hurry and have a bigger data set,
- (hypothetically) use compile-file in Sciener CL on a multicore
plateform if my customer were in a hurry had have an enormous
dataset.
- perhaps even use another implementation of other constraints
emerge, such as a need for embedding in an application, or
targetting a specific virtual machine or whatever.

The requirements on introspection doesn't depend on the size or speed
constraints so definitely FUNCTION-LAMBDA-EXPRESSION whose result is
linked to this size constraint doesn't fit the bill.


As for ARGLIST, while I agree that it would be nice if it was standard
(CDR) and implemented by all implementations, this is not the case,
and since I want to be able to escalate the choice of the target
implementation at a later time, I cannot depend on it either
(without, as I explained, providing myself an implementation which
would hten work everywhere).


Of course, it it was only for a small clisp script, or other
implementation specific code, there'd be no problem in using the
implementation specific API.



The difference is in the investment, on the order of minutes or hours
for an implementation specific script, on the order of months or years
of a Common Lisp application.

--
__Pascal Bourguignon__
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13
Prev: Do as the Romans do
Next: managing large table of data