-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
spec: "unhashable" #64
Comments
What do you think needs clarifying here? I was assuming unhashable = not hashable, and hashable seems fairly well defined throughout the spec. |
The spec contains contradictory statements:
Would be helpful it the spec was more precise in definitions. |
Yes, the intention changed at some point in the past so that lists were hashable-only-if-frozen but now are always unhashable; the text of the spec was not brought to consistency. In the Go implementation, lists are unhashable. In the Java implementation, lists may not be used as keys of a dict, but structures (like structs) that indirectly contain lists may be used as keys of a dict if frozen, and sadly this is widely relied upon. It's hard even just to understand exactly what the Java implementation permits. |
This has been a long-standing issue that I've unfortunately wavered back and forth on. On the one hand, I've always found it odd that freezing a value could allow you to do more things with it (hash it), rather than strictly fewer (no mutations). It breaks my mental model that freezing is sort of like up-casting to a base type with fewer operations, and where Liskov substitution says you can always pass the derived type to a method accepting the base type. That's why we find ourselves in odd situations like code breaking when it gets refactored into the same file as where its value is consumed. For instance, the example given in #272. On the other hand, if we don't allow hashing of formerly-mutable objects, that creates a need for separate frozen-from-birth types. Lists already have this in the form of tuples, but for the recently added (Digression warning) We've also thought about possible interactions with a Starlark type system. A key invariant of any type system is that the static type of a variable/expression is a superset of the dynamic types of the possible values it may refer to at runtime. So if you write x = set()
freeze(x) # assuming Go-interperter-style freeze() primitive
x.add("abc") Is the Another, more reasonable semantics is that x = set()
x = freeze(x) # uses of x hereon have type `frozenset`
x.add("abc") (If So perhaps it's better to keep frozen-ness entirely out of scope for the type system. But then that raises questions about what did we really gain by banning hashing of frozen values. If we undo that, then we could add Ideally I'd like us to reach a decision on this sometime soon, e.g. in Q1 before the proposed Starlark type system is too mature. |
@comius FYI, some thoughts above about mutability w.r.t. types. Tl;dr: It seems hard to work mutability information (both mutation safety and hashability safety) into the type system without creating a lot more work for users (and us) than it's probably worth. If we don't try, and instead keep them as purely dynamic errors, then we may avoid the need for a distinct |
No description provided.
The text was updated successfully, but these errors were encountered: