-
Notifications
You must be signed in to change notification settings - Fork 17
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
Fix #161: Implement == and hash for IndexLens and ComposedLens #162
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot @phipsgabler for looking into this.
That could be solved by using a magic constant instead, but is that a good idea?
Do you have any specific drawbacks in mind with the magic constant approach? If not I would prefer to have one. (Also for ComposedLens). Possible definition for the constant:
const SALT_IndexLens = objectid(IndexLens)
None other than me having no idea whether this is accepted good practice. The only objection I could remotely think of is: is it guaranteed that If it's OK with you, I'll go ahead with it. |
I don't know the answer to these either. To be safer, let's just hardcode the following values: julia> using Setfield
julia> objectid(Setfield.IndexLens)
0x8aa710fd8cb95e7e
julia> objectid(Setfield.ComposedLens)
0x1c9765b995720e93 |
I also asked about this on discourse. |
If by hardcode you mean
|
Thanks a lot @JeffreySarnoff for the clarification. By hardcoding I meant const value = 0x8aa710fd8cb95e7e # objectid(Setfield.IndexLens)
But the default |
not for all things -- Strings, Tuples of Ints and other bitstypes for example keep their objectids |
struct S{T}
value::T
end
function hash_cheat(obj, h::UInt)
hash(obj.value, h)
end
const SALT = 0x8aa710fd8cb95e7e
function hash1(obj, h::UInt)
hash(obj.value, hash(SALT, h))
end
function hash2(obj, h::UInt)
hash(obj.value, h+SALT)
end
obj = S((1,))
seed = UInt(1)
using BenchmarkTools
@btime hash_cheat($(Ref(obj))[], $(Ref(seed))[])
@btime hash1($(Ref(obj))[], $(Ref(seed))[])
@btime hash2($(Ref(obj))[], $(Ref(seed))[])
# 1.833 ns (0 allocations: 0 bytes)
# 1.813 ns (0 allocations: 0 bytes)
# 1.833 ns (0 allocations: 0 bytes) I think we should incorporate some type specific salt into our hash and based on the above benchmark, function Base.hash(o::IndexLens, h::UInt)
salt = 0x8aa710fd8cb95e7e #objectid(Setfield.IndexLens)
hash(o.indices, hash(salt, h))
end |
There is under heavy use (Base knows best); simple benchmarking will not reveal that. You should define your salt constant outside of and just above the hash function (better practice) and you must provide both a 64bit and a 32bit constant as |
Base operates under many constraints like generality and backward compatibility, so "Base knows best" is not obvious to me in this case. But anyway lets do it the Base way: function make_salt(s64::UInt64)::UInt
if UInt === UInt64
return s64
else
return UInt32(s64 >> 32) ^ UInt32(s64 & 0x00000000ffffffff)
end
end
const SALT_IndexLens = make_salt(0x8aa710fd8cb95e7e) # objectid(Setfield.IndexLens)
Base.hash(o::IndexLens, h::UInt) = hash(o.indices, SALT_IndexLens + h) |
Cool. Point taken. Base knows best about hashing Julia constructs (I should have been more explicit). A great deal of effort has gone into the hashing approach and its most efficient implementation. |
Thanks again @JeffreySarnoff for all your patience and explanations, I appreciate them. |
Great! I'll update to the latest version in the next couple of days, plus a few more tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Can you increase the minor version number @phipsgabler, since this is technically breaking? I will then tag a release immediately.
@phipsgabler thanks again! This is now available in Setfield 0.8. |
Faster hashes for index lens. See jw3126/Setfield.jl#162
@jw3126 Sorry if you've already thought through this, but, I think this is actually technically non-breaking. The only documented public interface we need to satisfy is (I just thought to ramble this, since I noticed JuliaObjects/Accessors.jl#31) |
Thanks @tkf So for this PR we already tagged a breaking release. But in the case of Accessors your advise is to only bump the patch version? |
Yeah, I think Setfield.jl is good as-is. But I don't think Accessors.jl needs a breaking release. |
Faster hashes for index lens. See jw3126/Setfield.jl#162
Now I'm not an expert in these matters, but is seems the bottleneck is not hashing the tuples, but the types or symbols (since
hash(::Symbol)
falls back toobjectid
, too). In the commit without adding type symbols tohash
(2ca5404):With the symbols (880daf4):
Without the symbol, an index lens hashes to the same as the underlying tuple, though:
That could be solved by using a magic constant instead, but is that a good idea?
CC @torfjelde