all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* RFC: make maphash return a list
@ 2013-05-03 17:59 Wilfred Hughes
  2013-05-03 23:12 ` Pascal J. Bourguignon
  2013-05-04  5:29 ` Stephen J. Turnbull
  0 siblings, 2 replies; 7+ messages in thread
From: Wilfred Hughes @ 2013-05-03 17:59 UTC (permalink / raw)
  To: emacs-devel

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

I've been using Emacs hash tables a lot recently, and I would find
several operations much easier if maphash returned a list. For
example, I'd like to be able to do:

(maphash (lambda (key value) key) some-table)

to obtain the list of keys present in some-table. I would guess elisp
is influenced by Common Lisp here, where maphash returns nil
unconditionally. However, unlike elisp, Common Lisp's loop macro
supports iterating over keys directly with (loop for key being
hash-key of some-table ...) which helps considerably.

I can't see any obvious way this would break backwards compatibility,
so I threw together a trivial patch that makes maphash return a list
of the results. I've attached the patch.

Is there interest in this?

Wilfred

[-- Attachment #2: fns.c.diff --]
[-- Type: text/x-patch, Size: 423 bytes --]

4513c4513
<        doc: /* Call FUNCTION for all entries in hash table TABLE.
---
>        doc: /* Call FUNCTION for all entries in hash table TABLE, and make a list of the results.
4519a4520,4521
>   Lisp_Object ret = Qnil;
>   Lisp_Object current_result;
4527c4529,4530
< 	Ffuncall (3, args);
---
> 	current_result = Ffuncall (3, args);
> 	ret = Fcons(current_result, ret);
4530c4533
<   return Qnil;
---
>   return ret;

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

* Re: RFC: make maphash return a list
  2013-05-03 17:59 RFC: make maphash return a list Wilfred Hughes
@ 2013-05-03 23:12 ` Pascal J. Bourguignon
  2013-05-04  5:29 ` Stephen J. Turnbull
  1 sibling, 0 replies; 7+ messages in thread
From: Pascal J. Bourguignon @ 2013-05-03 23:12 UTC (permalink / raw)
  To: emacs-devel

Wilfred Hughes <me@wilfred.me.uk> writes:

> I've been using Emacs hash tables a lot recently, and I would find
> several operations much easier if maphash returned a list. For
> example, I'd like to be able to do:
>
> (maphash (lambda (key value) key) some-table)
>
> to obtain the list of keys present in some-table. I would guess elisp
> is influenced by Common Lisp here, where maphash returns nil
> unconditionally. However, unlike elisp, Common Lisp's loop macro
> supports iterating over keys directly with (loop for key being
> hash-key of some-table ...) which helps considerably.
>
> I can't see any obvious way this would break backwards compatibility,
> so I threw together a trivial patch that makes maphash return a list
> of the results. I've attached the patch.
>
> Is there interest in this?

maphash is nice because it doesn't cons a list.

(setq lexical-binding t)
(defun hashmap (fun hash)
  "Returns a list of the results of fun called on each key value entry.
No defined order."
  (let ((result '()))
    (maphash (lambda (k v) (push (funcall fun k v) result)) hash)
    result))

(let ((h (make-hash-table)))
  (setf (gethash :u h) 1
        (gethash :d h) 2
        (gethash :t h) 3
        (gethash :q h) 4
        (gethash :c h) 5
        (gethash :s h) 6)
  (hashmap (function cons) h))
--> ((:s . 6) (:c . 5) (:q . 4) (:t . 3) (:d . 2) (:u . 1))

        

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.




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

* RFC: make maphash return a list
  2013-05-03 17:59 RFC: make maphash return a list Wilfred Hughes
  2013-05-03 23:12 ` Pascal J. Bourguignon
@ 2013-05-04  5:29 ` Stephen J. Turnbull
  2013-05-05  0:06   ` Wilfred Hughes
  1 sibling, 1 reply; 7+ messages in thread
From: Stephen J. Turnbull @ 2013-05-04  5:29 UTC (permalink / raw)
  To: Wilfred Hughes; +Cc: emacs-devel

Wilfred Hughes writes:

 > I've been using Emacs hash tables a lot recently, and I would find
 > several operations much easier if maphash returned a list. For
 > example, I'd like to be able to do:
 > 
 > (maphash (lambda (key value) key) some-table)

(defun choose-name-to-taste (callable table)
  "Left as an exercise for the reader."
  (let ((retlist nil))
    (maphash (lambda (key value)
               (setq retlist (cons (funcall callable key value) retlist)))
             table))
    retlist))

 > Is there interest in this?

Please don't, for the reasons given in other replies.

 > However, unlike elisp, Common Lisp's loop macro supports iterating
 > over keys directly with (loop for key being hash-key of some-table
 > ...) which helps considerably.

Isn't this the right place to improve elisp?




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

* Re: RFC: make maphash return a list
  2013-05-04  5:29 ` Stephen J. Turnbull
@ 2013-05-05  0:06   ` Wilfred Hughes
  2013-06-18  8:17     ` Klaus-Dieter Bauer
  0 siblings, 1 reply; 7+ messages in thread
From: Wilfred Hughes @ 2013-05-05  0:06 UTC (permalink / raw)
  To: Stephen J. Turnbull; +Cc: emacs-devel

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

> maphash is nice because it doesn't cons a list.

So you're saying that maphash returning nil is a desirable property because
it doesn't build a list if you don't want it? OK, I understand. I think it
might be helpful for the docstring of maphash to say 'for side effects
only' the same way mapc does. My (incorrect) intuition was that any mapFOO
function would return a sequence unless otherwise stated.

> (defun choose-name-to-taste (callable table)
>   "Left as an exercise for the reader."
>   (let ((retlist nil))
>    (maphash (lambda (key value)
>               (setq retlist (cons (funcall callable key value) retlist)))
>             table))
>    retlist))

Yep, exactly. I don't want to turn this into bikeshedding -- I only felt it
was a nice to have, and of course I can build a list myself. Since both
mapcar and mapc exist in core Emacs, would it be worthwhile to have a
blessed chose-name-to-taste implementation in core?

> Isn't this [adding functionality to loop] the right place to improve
elisp?

That's an excellent idea, I'll try to put together a patch for that.

Thanks for your feedback, I appreciate it.

Wilfred

[-- Attachment #2: Type: text/html, Size: 1409 bytes --]

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

* Re: RFC: make maphash return a list
  2013-05-05  0:06   ` Wilfred Hughes
@ 2013-06-18  8:17     ` Klaus-Dieter Bauer
  2013-06-18 15:11       ` Davis Herring
  0 siblings, 1 reply; 7+ messages in thread
From: Klaus-Dieter Bauer @ 2013-06-18  8:17 UTC (permalink / raw)
  To: emacs-devel

Wilfred Hughes <me <at> wilfred.me.uk> writes:

> 
> 
> 
> 
> > maphash is nice because it doesn't cons a list.
> So you're saying that maphash returning nil is a desirable property 
because it doesn't build a list if you don't want it? OK, I understand. I 
think it might be helpful for the docstring of maphash to say 'for side 
effects only' the same way mapc does. My (incorrect) intuition was that any 
mapFOO function would return a sequence unless otherwise stated.> (defun 
choose-name-to-taste (callable table)
> >   "Left as an exercise for the reader."
> >   (let ((retlist nil))>    (maphash (lambda (key value)
> >               (setq retlist (cons (funcall callable key value) 
retlist)))>             table))>    retlist))
> 
> Yep, exactly. I don't want to turn this into bikeshedding -- I only felt 
it was a nice to have, and of course I can build a list myself. Since both 
mapcar and mapc exist in core Emacs, would it be worthwhile to have a 
blessed chose-name-to-taste implementation in core?> Isn't this [adding 
functionality to loop] the right place to improve elisp?
> 
> That's an excellent idea, I'll try to put together a patch for that.
> 
> Thanks for your feedback, I appreciate it.
> Wilfred
> 


> “maphash is nice because it doesn't cons a list.”

While I understand the performance considerations (regarding possibly
high memory use in some cases), I find having some variant that DOES
return values producing less readable code. If all “map...” functions
returned values unless explicitly told not to this would allow for a
more consistently functional style of programming. I'm not sure how
style conventions usually are for emacs lisp, but personally I find
code much more readable that avoids changing the value of variables.

E.g. I found my own code easiert to read and expand if I can do a
list-operation like

  (mapcar 'modification-2 (mapcar 'modifification-1 (maphash (lambda
    (k v) (return-something k v)))))

compared to

  (let (mapped-hash) (maphash (lambda (k v) (push (return-something k
    v) mapped-hash))) (mapcar 'modification-2 (mapcar 'modification-1
    mapped-hash)))

For full backward compatibility (some code may depend on maphash
returning nil) and preserving the performance advantage, why not
introduce an optional argument to all those builtin “map...” functions
or an alternative version that returns the values (sort of like the
mapc, mapcar pair).

As for cl-loop: I use that macro alot. However, it is unnecessarily
limiting, as there isn't a corespondence for all “map...” functions
that don't return values. Then you're back to some

  (let (x) (map... (lambda (..) (push .. x))) x)

again in order to get the input-value for the loop. Also, when I see
“mapcar” I know a list will be returned -- with “cl-loop” there is no
such clarity. Also, unlike general “map...” functions, cl-loop is like
a separate language to be learned.

While of course everyone can define a “hashmap” function as described
or similiarily a “atommap” or “keymapmap”, I'd expect code-readability
to suffer from having custom functions for such things, unless they
are implemented in a widely used package like “cl-lib”, though then
again, such functions wouldn't have anything todo with common lisp.

To be fair though, the standard indentation scheme doesn't promote
this style of programming either. In standard indentation, the above
example would read either (ignoring that maphash doesn't return the
list of values)

  (mapcar 'modification-2 
          (mapcar 'modifification-1 
                  (maphash (lambda (k v) (return-something k v)))))

or

  (mapcar 
   'modification-2 
   (mapcar 
    'modifification-1 
    (maphash (lambda (k v) (return-something k v)))))

kind regards, Klaus




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

* Re: RFC: make maphash return a list
  2013-06-18  8:17     ` Klaus-Dieter Bauer
@ 2013-06-18 15:11       ` Davis Herring
  2013-06-18 20:06         ` Klaus-Dieter Bauer
  0 siblings, 1 reply; 7+ messages in thread
From: Davis Herring @ 2013-06-18 15:11 UTC (permalink / raw)
  To: Klaus-Dieter Bauer; +Cc: emacs-devel

>   (let (mapped-hash) (maphash (lambda (k v) (push (return-something k
>     v) mapped-hash))) (mapcar 'modification-2 (mapcar 'modification-1
>     mapped-hash)))

For what it's worth, you can at least here write

(let (mapped-hash)
  (maphash
   (lambda (k v)
     (push (modification-2 (modification-1 (return-something k v)))
	   mapped-hash))
   hash)
  mapped-hash)

(so long as the various functions are pure enough to allow the
reordering).  Indentation makes it longer than

(let (mapped-hash)
  (maphash (lambda (k v) (push (return-something k v) mapped-hash))
	   hash)
  (mapcar 'modification-2 (mapcar 'modification-1 mapped-hash)))

(which in 80 columns can even have the tiny line appended to the
previous), but I think it is conceptually simpler.

Davis

-- 
This product is sold by volume, not by mass.  If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.



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

* Re: RFC: make maphash return a list
  2013-06-18 15:11       ` Davis Herring
@ 2013-06-18 20:06         ` Klaus-Dieter Bauer
  0 siblings, 0 replies; 7+ messages in thread
From: Klaus-Dieter Bauer @ 2013-06-18 20:06 UTC (permalink / raw)
  To: Davis Herring; +Cc: emacs-devel

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

What is easier to read... that would probably be a matter of taste.
Granted, it was a bad example. If find the "nested mapcar" approach easier
to read (though probably not with unmodified indentation rules) when
single-element functions with mapcar and functions operating on lists
alternate, e.g.

  (append
    (mapcar 'function-that-returns-list
      (function-taking-and-returning-lists
        (mapcar 'something-else input-list))))

Basically I find emacs lisp that contains mostly of such "diagonals" the
easiest to read in terms of structure (but this goes beyond the original
topic and to some degree more into indentation conventions).

But subjectively the actually important point is the avoidance of
variables, whose value changes after declaration (preserving a 1-on-1
relation between name and value during execution of the function). Then I
have to find only the let form that declared the variable in order to know
its intended contents rather than scan through the whole function. With
maphash and similiar that style (would that be functional style?) is not
possible.

That said, I have just written a little private-use library for such
things. Bottomline, if I want to program more functionally it doesn't even
take much bending of elisp to do so.

kind regards, Klaus


2013/6/18 Davis Herring <herring@lanl.gov>

> >   (let (mapped-hash) (maphash (lambda (k v) (push (return-something k
> >     v) mapped-hash))) (mapcar 'modification-2 (mapcar 'modification-1
> >     mapped-hash)))
>
> For what it's worth, you can at least here write
>
> (let (mapped-hash)
>   (maphash
>    (lambda (k v)
>      (push (modification-2 (modification-1 (return-something k v)))
>            mapped-hash))
>    hash)
>   mapped-hash)
>
> (so long as the various functions are pure enough to allow the
> reordering).  Indentation makes it longer than
>
> (let (mapped-hash)
>   (maphash (lambda (k v) (push (return-something k v) mapped-hash))
>            hash)
>   (mapcar 'modification-2 (mapcar 'modification-1 mapped-hash)))
>
> (which in 80 columns can even have the tiny line appended to the
> previous), but I think it is conceptually simpler.
>
> Davis
>
> --
> This product is sold by volume, not by mass.  If it appears too dense or
> too sparse, it is because mass-energy conversion has occurred during
> shipping.
>

[-- Attachment #2: Type: text/html, Size: 3752 bytes --]

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

end of thread, other threads:[~2013-06-18 20:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-03 17:59 RFC: make maphash return a list Wilfred Hughes
2013-05-03 23:12 ` Pascal J. Bourguignon
2013-05-04  5:29 ` Stephen J. Turnbull
2013-05-05  0:06   ` Wilfred Hughes
2013-06-18  8:17     ` Klaus-Dieter Bauer
2013-06-18 15:11       ` Davis Herring
2013-06-18 20:06         ` Klaus-Dieter Bauer

Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.