The Go implementation of Starlark, following Python2 and 3, rejects a dictionary operation in which the key is unhashable:
$ starlark -c '{}.get([])'
Traceback (most recent call last):
cmdline:1:7: in <toplevel>
<builtin>: in get
Error: get: unhashable type: list
$ python2 -c '{}.get([])'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: unhashable type: 'list'
$ python3 -c '{}.get([])'
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: unhashable type: 'list'
By contrast, the Java implementation permits a lookup with any value, including unhashable ones. The lookup fails, though it is not necessarily an error, so execution may continue:
$ blaze-bin/third_party/bazel/src/main/java/com/google/devtools/starlark/Starlark
>> {}.get([])
None
(This behavior occurs even when the dict is non-empty, so it can't be explained as the implementation taking a shortcut for empty dicts.)
Clearly, the Java implementation is in fact hashing the key, so the error message ("unhashable type") issued by an update operation such as {}.update([([], 1)]) seems not to tell the whole story.
I think the spec should state that all dict operations attempt to hash the key (even when unnecessary, such as {}.get(k)) and fail if the key is unhashable.
The Go implementation of Starlark, following Python2 and 3, rejects a dictionary operation in which the key is unhashable:
By contrast, the Java implementation permits a lookup with any value, including unhashable ones. The lookup fails, though it is not necessarily an error, so execution may continue:
(This behavior occurs even when the dict is non-empty, so it can't be explained as the implementation taking a shortcut for empty dicts.)
Clearly, the Java implementation is in fact hashing the key, so the error message ("unhashable type") issued by an update operation such as
{}.update([([], 1)])seems not to tell the whole story.I think the spec should state that all dict operations attempt to hash the key (even when unnecessary, such as {}.get(k)) and fail if the key is unhashable.