unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Keyword args (was: Return)
@ 2010-12-12  4:49 MON KEY
  2010-12-12  8:34 ` Keyword args Helmut Eller
  0 siblings, 1 reply; 8+ messages in thread
From: MON KEY @ 2010-12-12  4:49 UTC (permalink / raw)
  To: eller.helmut; +Cc: emacs-devel

> Since we have destructuring-bind parsing plists is not very hard.

No, we have _some_ of dbind...

Following is the CL specs cannonical `destructuring-bind' example:

,----
|
| Examples:
|
|  (defun iota (n) (loop for i from 1 to n collect i))       ;helper
|
|  (destructuring-bind ((a &optional (b 'bee)) one two three)
|      `((alpha) ,@(iota 3))
|    (list a b three two one)) → (ALPHA BEE 3 2 1)
|
`----

Does evaluating the above two forms in elisp land you in *Backtrace*
with something like this at beginning-of-buffer:

 Debugger entered--Lisp error: (void-variable bind-enquote)

If so, I would argue that the current elisp's implementation fo
`destructuring-bind' isn't exactly the panacea to keyword parsing you
claim it is.

By way of comparison this is what a recent SBCL returns:

CL-USER> (format nil "~a ~a" (lisp-implementation-type)
		             (lisp-implementation-version))
;=> "SBCL 1.0.45.3"

CL-USER> (defun iota (n) (loop for i from 1 to n collect i))
;=> IOTA

CL-USER> (destructuring-bind ((a &optional (b 'bee)) one two three)
	     `((alpha) ,@(iota 3))
	   (list a b three two one))
;=> (ALPHA BEE 3 2 1)

--
/s_P\



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Keyword args
  2010-12-12  4:49 Keyword args (was: Return) MON KEY
@ 2010-12-12  8:34 ` Helmut Eller
  0 siblings, 0 replies; 8+ messages in thread
From: Helmut Eller @ 2010-12-12  8:34 UTC (permalink / raw)
  To: emacs-devel

* MON KEY [2010-12-12 04:49] writes:

>> Since we have destructuring-bind parsing plists is not very hard.
>
> No, we have _some_ of dbind...
>
> Following is the CL specs cannonical `destructuring-bind' example:
>
> ,----
> |
> | Examples:
> |
> |  (defun iota (n) (loop for i from 1 to n collect i))       ;helper
> |
> |  (destructuring-bind ((a &optional (b 'bee)) one two three)
> |      `((alpha) ,@(iota 3))
> |    (list a b three two one)) ’ (ALPHA BEE 3 2 1)
> |
> `----
>
> Does evaluating the above two forms in elisp land you in *Backtrace*
> with something like this at beginning-of-buffer:
>
>  Debugger entered--Lisp error: (void-variable bind-enquote)
>
> If so, I would argue that the current elisp's implementation fo
> `destructuring-bind' isn't exactly the panacea to keyword parsing you
> claim it is.

This bug was fixed quite some time ago: 
http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6408

Helmut




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Keyword args
@ 2010-12-12 17:01 MON KEY
  0 siblings, 0 replies; 8+ messages in thread
From: MON KEY @ 2010-12-12 17:01 UTC (permalink / raw)
  To: emacs-devel

> This bug was fixed quite some time ago:
> http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6408

Well not all _that_ long ago.
But yes, applying that patch fixes things here. Thanks.
Did this make it into the current pretest?

So, apparently it is true what you say, dbind is a panacea!

"Got &keys? destructuring-bind em.
 dbind - the elixir for all ones elisp ails." ™

--
/s_P\



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Keyword args
  2010-12-10  8:53                 ` Keyword args (was: Return) Helmut Eller
@ 2010-12-13  2:10                   ` Daniel Colascione
  2010-12-13  8:30                     ` Helmut Eller
  2010-12-13 20:00                     ` Andy Wingo
  0 siblings, 2 replies; 8+ messages in thread
From: Daniel Colascione @ 2010-12-13  2:10 UTC (permalink / raw)
  To: Helmut Eller; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3712 bytes --]

On 12/10/10 12:53 AM, Helmut Eller wrote:
> * Daniel Colascione [2010-12-10 07:42] writes:
> 
>> On 12/7/10 8:30 AM, Stephen J. Turnbull wrote:
>>> David Kastrup writes:
>>>
>>>  > I don't think anybody minds the features.
>>>
>>> IIRC rms has recently declared his dislike for CL-style keyword
>>> arguments.  I suppose that's part of the "syntactic complexity" you
>>> mention, but MON KEY OTOH points out cases where he'd like to use
>>> them.  So there are some fundamental disagreements here.
>>
>> I'd just like to add my support for keyword arguments. Functions like
>> write-region are both horrible and brittle because their parameters are
>> both numerous and overloaded; specific functionality can be more simply
>> expressed with using keyword arguments. 
> 
> You always have the option to make a macro with keyword arguments which
> expands to a call to the "raw" function.

How many forwarder macros do you need to sufficiently cover the problem
space? Combinatorial explosion is a problem when the set of possible
inputs is large.

> The only disadvantage of this approach is that macros can't be used with
> higher order functions, ala mapcar.  But keyword arguments a rarely
> useful in that case.

You're mostly right, though it's not impossible to imagine a situation
in which it's useful to APPLY a keyword-argument-parsing function.

>> Precedent can be seen in play-sound, defcustom, and elsewhere.
> 
> For a bad example see make-network-process.  That takes keyword
> arguments but the keyword parsing is done in C and it doesn't do a good
> job.  It doesn't detect invalid keywords; doesn't detect conflicting
> keys; some keys are documented to be ignored when some other keys are
> supplied.  It's very difficult to use.  Correct keyword parsing in C is
> difficult so I would vote against it.

Clearly, the solution is more uniform keyword argument parsing; either
library functions in C could be provided, or make-network-process could
be made a Lisp keyword-parsing front-end for some horrible
%make-network-process that implements the functionality.

Still, most functions aren't written in C, and keyword parsing is easier
in Lisp.

> Also note that defcustom is a macro and play-sound takes a plist.  The
> plist idiom is IMO superior to keywords.  In particular passing
> arguments along gets easier.  E.g.
> 
> (defun foo (x y plist) 
>   (bar x y) 
>   (baz plist))
> 
> is IMO more readable than:
> 
> (defun* foo (x y &key key1 key2 key3)    
>   (bar x y) 
>   (baz :key1 key1 :key2 key2 :key3 key3))
> 
> or the rather silly
> 
> (defun* foo (x y &rest plist &key key1 key2 key3)
>   (bar x y) 
>   (apply #'baz plist))

The apply example isn't that bad in my book, and most of the time, you
don't need to forward an arbitrary subset of keyword parameters to
another function anyway.

> 
> Since we have destructuring-bind parsing plists is not very hard.

Sure, but putting them in the lambda-list is even easier for most cases,
especially when there aren't that many arguments. It's also easier to
document functions written with &key than it is to document equivalent
functions that do ad-hoc parsing.

> 
>> The performance arguments opposing
>> keyword arguments don't seem to be supported by benchmarks, and in any
>> case, most functions, especially ones with rich functionality, aren't on
>> the fast path.
> 
> The sequence functions find, position, assoc*, member* etc. are on the
> fast path.  Ironically those are the functions where keyword args are
> very useful because the meaning is relatively consistent.

Compiler macros can eliminate the pain in this case.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Keyword args
  2010-12-13  2:10                   ` Keyword args Daniel Colascione
@ 2010-12-13  8:30                     ` Helmut Eller
  2010-12-13 20:00                     ` Andy Wingo
  1 sibling, 0 replies; 8+ messages in thread
From: Helmut Eller @ 2010-12-13  8:30 UTC (permalink / raw)
  To: emacs-devel

* Daniel Colascione [2010-12-13 02:10] writes:

> On 12/10/10 12:53 AM, Helmut Eller wrote:
>> * Daniel Colascione [2010-12-10 07:42] writes:
>> 
>>> On 12/7/10 8:30 AM, Stephen J. Turnbull wrote:
>>>> David Kastrup writes:
>>>>
>>>>  > I don't think anybody minds the features.
>>>>
>>>> IIRC rms has recently declared his dislike for CL-style keyword
>>>> arguments.  I suppose that's part of the "syntactic complexity" you
>>>> mention, but MON KEY OTOH points out cases where he'd like to use
>>>> them.  So there are some fundamental disagreements here.
>>>
>>> I'd just like to add my support for keyword arguments. Functions like
>>> write-region are both horrible and brittle because their parameters are
>>> both numerous and overloaded; specific functionality can be more simply
>>> expressed with using keyword arguments. 
>> 
>> You always have the option to make a macro with keyword arguments which
>> expands to a call to the "raw" function.
>
> How many forwarder macros do you need to sufficiently cover the problem
> space? Combinatorial explosion is a problem when the set of possible
> inputs is large.

Exactly as many macros as you would be need keyword argument parsing
functions.  Whether keywords are used for functions or macros makes no
difference to cover the "problem space" (which I presume is a better
interface to write-region).

Helmut




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Keyword args
  2010-12-13  2:10                   ` Keyword args Daniel Colascione
  2010-12-13  8:30                     ` Helmut Eller
@ 2010-12-13 20:00                     ` Andy Wingo
  2010-12-14  5:03                       ` Miles Bader
  1 sibling, 1 reply; 8+ messages in thread
From: Andy Wingo @ 2010-12-13 20:00 UTC (permalink / raw)
  To: Daniel Colascione; +Cc: Helmut Eller, emacs-devel

On Mon 13 Dec 2010 03:10, Daniel Colascione <dan.colascione@gmail.com> writes:

> Clearly, the solution is more uniform keyword argument parsing; either
> library functions in C could be provided, or make-network-process could
> be made a Lisp keyword-parsing front-end for some horrible
> %make-network-process that implements the functionality.

FWIW, Guile supports keyword arguments natively. IMO the proper way to
do things is to keep a uniform calling convention, and allow procedures
to parse arguments themselves, with low-level support.

    scheme@(guile-user)> (lambda* (#:key (foo 42)) foo)
    $1 = #<procedure 1c2f080 at standard input:1:0 (#:key foo)>
    scheme@(guile-user)> ,disassemble $1
    Disassembly of #<procedure 1c2f080 at standard input:1:0 (#:key foo)>:

Here we have some instructions that aren't disassembled quite as
perspicaciously as one might like, but they take the args on the stack,
and shuffle the non-positional args up:

       0    (assert-nargs-ge 0 0)           
       3    (bind-optionals/shuffle 0 0 0 0 0 1)

And here we bind keywords. This says "fetch the keywords from the
constant table at index 1, and scan the non-positional args for one
keyword, disallowing other keywords.

      10    (bind-kwargs 0 1 0 1 0)         

It's somewhat complicated code, but it's a const only borne by keyword
arguments. Here we have the code that initializes `foo' if it's not
given:

      16    (reserve-locals 0 1)            
      19    (local-bound? 0)                
      21    (br-if :L111)                   ;; -> 29
      25    (make-int8 42)                  ;; 42
      27    (local-set 0)                   ;; `foo'

And finally (!) the main body:

      29    (local-ref 0)                   ;; `foo'
      31    (return)                        

Some tests:

    > (define (fib n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))
    > ,time (fib 35)
    $1 = 14930352
    clock utime stime cutime cstime gctime
     2.99  2.99  0.01   0.00   0.00   0.00
    > (define* (fibk #:key (n 0)) (if (< n 2) 1 (+ (fibk #:n (- n 1)) (fibk #:n (- n 2)))))
    > ,time (fibk 35)
    <stdin>:5:6: warning: possibly wrong number of arguments to `fibk'
    While executing meta-command:
    ERROR: Odd length of keyword argument list
    > ,time (fibk #:n 35)
    $2 = 14930352
    clock utime stime cutime cstime gctime
     5.01  4.99  0.00   0.00   0.00   0.00

FWIW on this machine a byte-compiled elisp (fib 35) on emacs takes about
6 seconds.

I wrote more about this sort of thing here:

    http://wingolog.org/archives/2009/11/07/case-lambda-in-guile
    http://wingolog.org/archives/2009/11/08/optionals-keywords-oh-my

Our elisp support uses this native infrastructure for keywords and
optionals, but there obviously are some differences regarding
implementation of dynamic scope.  Lexical binding is a lot cheaper, for
Guile, but we hope to get dynamic binding cheap too.

Anyway, I would like to discourage complicated implementations in
"user-space" for keyword arguments. They should be a core language
feature, for all the reasons I gave in my first article.

Happy hacking,

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Keyword args
  2010-12-13 20:00                     ` Andy Wingo
@ 2010-12-14  5:03                       ` Miles Bader
  2010-12-14  7:43                         ` Helmut Eller
  0 siblings, 1 reply; 8+ messages in thread
From: Miles Bader @ 2010-12-14  5:03 UTC (permalink / raw)
  To: Andy Wingo; +Cc: Helmut Eller, Daniel Colascione, emacs-devel

Andy Wingo <wingo@pobox.com> writes:
> Anyway, I would like to discourage complicated implementations in
> "user-space" for keyword arguments. They should be a core language
> feature, for all the reasons I gave in my first article.

well... I agree, mostly (though that doesn't mean I agree that many
primitives in elisp should _use_ keywords, e.g. to the extent that CL
does).

Another perhaps-useful concept is alternate function entry points for an
"already handled" argument form (my vague memory is that CMUCL does
this).  In many cases the compiler could then do argument parsing at
compile time and generate a call to the "simple" entry point.

-Miles

-- 
Consult, v.i. To seek another's disapproval of a course already decided on.



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Keyword args
  2010-12-14  5:03                       ` Miles Bader
@ 2010-12-14  7:43                         ` Helmut Eller
  0 siblings, 0 replies; 8+ messages in thread
From: Helmut Eller @ 2010-12-14  7:43 UTC (permalink / raw)
  To: emacs-devel

* Miles Bader [2010-12-14 05:03] writes:

> Another perhaps-useful concept is alternate function entry points for an
> "already handled" argument form (my vague memory is that CMUCL does
> this).  In many cases the compiler could then do argument parsing at
> compile time and generate a call to the "simple" entry point.

CMUCL does compile-time keyword parsing only for the local-call
convention, i.e. if the callee is known and doesn't change.  It's not
done for a normal call to a named global function; that uses the generic
slow entry point.  If all call-sites were known (say recorded in a
linkage table) and could be patched on redefintion a more direct entry
point could be used more often, but CMUCL doesn't do that.  So, I think
compile-time keyword parsing is rarely done in practice.

Helmut




^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-12-14  7:43 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-12  4:49 Keyword args (was: Return) MON KEY
2010-12-12  8:34 ` Keyword args Helmut Eller
  -- strict thread matches above, loose matches on Subject: below --
2010-12-12 17:01 MON KEY
2010-12-05 23:55 Return MON KEY
2010-12-06  1:48 ` Return Stephen J. Turnbull
2010-12-06  5:50   ` Return MON KEY
2010-12-06  7:20     ` Return Stephen J. Turnbull
2010-12-07  2:42       ` Return MON KEY
2010-12-07 14:34         ` Return Stephen J. Turnbull
2010-12-07 15:54           ` Return David Kastrup
2010-12-07 16:30             ` Return Stephen J. Turnbull
2010-12-10  7:42               ` Return Daniel Colascione
2010-12-10  8:53                 ` Keyword args (was: Return) Helmut Eller
2010-12-13  2:10                   ` Keyword args Daniel Colascione
2010-12-13  8:30                     ` Helmut Eller
2010-12-13 20:00                     ` Andy Wingo
2010-12-14  5:03                       ` Miles Bader
2010-12-14  7:43                         ` Helmut Eller

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).