# Listable functions thread over Associations; is this documented?

Thanks to a somewhat misapplied use of MapThread I learned of this behavior:

<|a -> 1, b -> 2|> + <|a -> 5, b -> 6|>

<|a -> 6, b -> 8|>


Furthermore this applies to all Listable functions:

SetAttributes[foo, Listable]

foo[<|a -> 1, b -> 2|>, <|a -> 5, b -> 6|>]
foo[<|a -> 1, b -> 2|>, bar]
foo[<|a -> 1, b -> 2|>]

<|a -> foo[1, 5], b -> foo[2, 6]|>

<|a -> foo[1, bar], b -> foo[2, bar]|>

<|a -> foo[1], b -> foo[2]|>


I do not recall seeing this is the documentation for Association. Is this documented behavior?

The documentation for Association offers the following tantalizing (and frustrating) remarks...

Typical list operations (such as Map, Select, and Sort) apply to the values in an association, leaving the keys unchanged.

... and ...

Keys are "transparent" for many operations

... but it remains silent on the identity of those "many operations" beyond a few examples.

My impression is that the consequences of this transparency are still being worked out. Membership in the set of "many operations" seems to be arbitrary at the moment, causing some surprising behaviour (example). My hope is that a principle will emerge that will allow us to make an a priori determination as to whether a given piece of functionality is one of the "many operations", without having to experiment.

• I have mixed feelings about this whole Association-masquerading-as-a-list business. On the one hand, I can see the benefits for interactive, ad hoc use. But I also fear that the non-determinism it introduces is a fertile source for bugs in library code. I have the same misgivings about the heuristics in Dataset/Query. – WReach Oct 16 '14 at 14:36
• To which heuristics do you refer? (+1 btw) – Mr.Wizard Oct 16 '14 at 17:18
• @Mr.Wizard This is the subject of one of my unposted responses ;D In brief, an example is that Query execution is sensitive to the TypeSystem data types inferred for Dataset elements. Those data types are presently inferred using heuristic methods, with magic threshold numbers relating to tuple sizes, key types and value types. This leads to surprising behaviour sometimes -- mostly for display, but sometimes for execution as well (the subject of my wayward post, which may never become fit enough to publish). – WReach Oct 16 '14 at 20:31
• Speak of the devil... ACL just ran into this one again. – WReach Oct 21 '14 at 22:21
• @WReach, I do hope your "wayward post" becomes fit enough to publish. The Dataset approach seems powerful, but I struggle to understand its design rationale or coherence. I would appreciate any steps towards that principle you refer to. – Simplex Oct 22 '14 at 4:45

To me your question boils down to whether or not Listable functions are supposed to act as wrapped in Thread or MapThread. According to the documentation, Thread has not changed since V1 and, indeed,

 Thread[f[<|a -> 1, b -> 2|>, <|a -> 5, b -> 6|>]]

f[<|a -> 1, b -> 2|>, <|a -> 5, b -> 6|>]


However, the documentation to MapThread has a note: Updated in 2014 (10.0), and that update appears under Details and says

MapThread works on Association objects.

And it does

MapThread[f, {<|a -> 1, b -> 2|>, <|a -> 5, b -> 6|>}]

<|a -> f[1, 5], b -> f[2, 6]|>


I think something should be said about associations under Listable, but that article hasn't changed in V10.

• The behavior illustrated in my Question is clearly not the result of MapThread. (1) MapThread fail to evaluate the RHS and (2) it does not distribute singletons. – Mr.Wizard Oct 16 '14 at 17:16