13
$\begingroup$
KeyDrop[<|a -> 1|>, Key[a]]
<|a -> 1|>
KeyTake[<|a -> 1|>, Key[a]]
<||>

closely related but not the same: Unexpected behavior of KeyTake

Are there any consistent rules about using Key?

Win 7 V11.0.0 V11.0.1

Cloud V11.0.1

Worked as expected in V10.4


This leads to problems like how to extract {a,b}->3:

KeyTake[<|a -> 1, b -> 2, {a, b} -> 3|>, {a, b}]
KeyTake[<|a -> 1, b -> 2, {a, b} -> 3|>, Key[{a, b}]]
<|a -> 1, b -> 2|>

<||>

Not to mention backward compatibility.


A support case with the identification [CASE:3733760] was created.

$\endgroup$
  • $\begingroup$ Which version of V11? $\endgroup$ – mikado Oct 7 '16 at 20:54
  • $\begingroup$ I don't have V11.0.1, but I get the same results as you on Linux x86 64 bit $\endgroup$ – mikado Oct 7 '16 at 21:01
  • 4
    $\begingroup$ (1) The second argument of KeyDrop and KeyTake is taken literally as a single key or a list of keys. KeyDrop[assoc, Key[a]] will not work unless there is a Key[a] as an actual key. (2) You could do KeyTake[<|a -> 1, b -> 2, {a, b} -> 3|>, {{a, b}}]. $\endgroup$ – ilian Oct 7 '16 at 22:28
  • 1
    $\begingroup$ @ilian Sorry but I see that. The point is: it wasn't the case, your comment does not explain whether it was intended change, documentation doesn't reflect this, what is a possible motivation behind that change, was Key handling changed somewhere else, what is the big picture with respect to Key and associations. $\endgroup$ – Kuba Oct 8 '16 at 7:14
  • 1
    $\begingroup$ @ilian I see, I hope I will get more info from Support. I'm surprised that this way was choosen to achieve consistency in linked topic. The more that Lookup and Part are honoring Keys. Nevertheless such change should be emphasized in documentation. $\endgroup$ – Kuba Oct 8 '16 at 14:27
7
$\begingroup$

TL;DR

The wrapper Key is interpreted verbatim by all ?Key* and Association-related functions, the current exception being Lookup which strips one level of Key.

Other symbols prior to the introduction of associations, that act on expressions of any head and have a position-related argument, ask for the wrapper Key in order to be used in a special way on associations, except for keys specified as strings.


About consistency

Are there any consistent rules about using Key?

Proposition. When the syntax of a function explicitly asks for a key as an argument, wrapping this key key in the symbol Key defines a different key, the expression of which is Key[key].

Leaving aside the symbols KeyDrop and Lookup which I address further down, this rule seems to apply on all ?Key* symbols and other Association-related functions, in the mentioned versions 10.4.1, 11.0.0 and 11.0.1.

As examples about this rule and its constancy, consider KeyExistsQ and KeyMemberQ. We have in all three versions:

KeyExistsQ[<|a -> 1|>, a]
(* True *)

KeyExistsQ[<|a -> 1|>, Key[a]]
(* False *)

KeyMemberQ[<|a -> 1|>, a]
(* True *)

KeyMemberQ[<|a -> 1|>, Key[a]]
(* False *)

which shows that the keys key and Key[key] are different. Note that the last input used to give True in 10.2 and earlier, so the change made in 10.3 seems to support the proposed rule.

About the change of behavior in KeyDrop

What is a possible motivation behind that change? [from OP's comment]

In versions 10.4.1 and earlier, KeyDrop fails to make the distinction between the arguments key and Key[key]. One level of Key was stripped:

$Version
(* "10.4.1 for Microsoft Windows (64-bit) (April 11, 2016)" *)

KeyDrop[<|a -> 1|>, a]
(* <||> *)

KeyDrop[<|a -> 1|>, Key[a]]
(* <||> *)

KeyDrop[<|Key[a] -> 1|>, Key[a]]
(* <|Key[a] -> 1|> *)

KeyDrop[<|Key[a] -> 1|>, Key[Key[a]]]
(* <||> *)

This wrong behavior is fixed as of 11.0.1 and solves the inconsistency with all other ?Key* symbols.

Special cases

About Lookup

Lookup explicitly asks for a key,

Lookup[assoc, key] looks up the value associated with key in the association assoc

so it should satisfied the proposed rule, but this is not the case:

Lookup[<|a -> 1, b -> 2|>, a]
(* 1 *)

Lookup[<|a -> 1, b -> 2|>, Key[a]]
(* 1 *)

Lookup could be seen as an exception to the rule, and its particular behavior is documented in the sections "Properties & Relations" and "Possible Issues".

About other symbols

There are symbols that need the keys to be wrapped into Key in order to be correctly interpreted. These symbols all have definitions prior to the introduction of associations, which probably explain why a particular syntax is needed to get an unambiguous additional definition.

For instance, prior to 10.0, Part accepts only integers or valid Span specifications. Using the wrapper Key allow to distinguish between the position in the association and the corresponding key, stripping one level of Key in the process:

assoc = <|a -> x, 1 -> y, Key[1] -> z|>;

assoc[[1]]
(* x *)

assoc[[Key[1]]]
(* y *)

assoc[[Key[Key[1]]]]
(* z *)

Similarly, we have for other symbols with a position-related argument:

Extract[assoc, 1]
(* x *)

Extract[assoc, Key[1]]
(* y *)

ReplacePart[assoc, 1 -> 0]
(* <|a -> 0, 1 -> y, Key[1] -> z|> *)

ReplacePart[assoc, Key[1] -> 0]
(* <|a -> x, 1 -> 0, Key[1] -> z|> *)

MapAt[f, assoc, 1]
(* <|a -> f[x], 1 -> y, Key[1] -> z|> *)

MapAt[f, assoc, Key[1]]
(* <|a -> x, 1 -> f[y], Key[1] -> z|> *)

For all these symbols, as mentioned by Kuba in a comment below, a key specified as a string need not to be wrapped in Key. This shortcut is unambiguously defined, and therefore distinguishable from other available syntaxes. Taking the example of Part:

<|"a" -> 1|>[[Key["a"]]]
(* 1 *)

<| "a" -> 1 |>[["a"]]
(* 1 *)
|improve this answer|||||
$\endgroup$
  • $\begingroup$ +1 that was my concussion too at the end but I didn't want to talk to myself ;) Please consider moving summary to the top so that the point is clear. Would you call my initial confusion natural or was your impression that I should've read docs more carefully? :) $\endgroup$ – Kuba Oct 8 '16 at 23:21
  • $\begingroup$ I'm not sure the documentation helps to find out a general rule here. The docs for KeyTake, KeyDrop, KeyExistsQ, KeyMemberQ, ... do not mention the symbol Key, and the ref page of the latter is not really exhaustive. All this, plus the recent changes in KeyDrop and KeyMemberQ (perhaps others), do not help. I had the same initial confusion (and "concussion" :p). $\endgroup$ – user31159 Oct 9 '16 at 0:54
  • $\begingroup$ Yeah, sorry, I make many typos and some of them escapte the review :) p.s. worth to mention special handling of string keys by "old" functions: <|"a" -> 1|>[["a"]] $\endgroup$ – Kuba Oct 9 '16 at 8:45
  • $\begingroup$ Re concussion - I thought it was a nice typo as we were talking about confusion :-) Re string keys. Good point, I am going to update the answer. $\endgroup$ – user31159 Oct 9 '16 at 13:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.