# KeyDrop does not respect Key in V11

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.

• Which version of V11? Oct 7, 2016 at 20:54
• I don't have V11.0.1, but I get the same results as you on Linux x86 64 bit Oct 7, 2016 at 21:01
• (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}}]. Oct 7, 2016 at 22:28
• @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.
– Kuba
Oct 8, 2016 at 7:14
• @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.
– Kuba
Oct 8, 2016 at 14:27

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.

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".

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 *)

• +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? :)
– Kuba
Oct 8, 2016 at 23:21
• 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).
– user31159
Oct 9, 2016 at 0:54
• 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"]]
– Kuba
Oct 9, 2016 at 8:45
• 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.
– user31159
Oct 9, 2016 at 13:45