{"action":"created","issue":{"url":"https://api.github.com/repos/JuliaLang/julia/issues/12157","labels_url":"https://api.github.com/repos/JuliaLang/julia/issues/12157/labels{/name}","comments_url":"https://api.github.com/repos/JuliaLang/julia/issues/12157/comments","events_url":"https://api.github.com/repos/JuliaLang/julia/issues/12157/events","html_url":"https://github.com/JuliaLang/julia/issues/12157","id":95103068,"number":12157,"title":"julep/rfc: proposal for unified Dict get/insert/has interface","user":{"login":"vtjnash","id":330950,"avatar_url":"https://avatars.githubusercontent.com/u/330950?v=3","gravatar_id":"","url":"https://api.github.com/users/vtjnash","html_url":"https://github.com/vtjnash","followers_url":"https://api.github.com/users/vtjnash/followers","following_url":"https://api.github.com/users/vtjnash/following{/other_user}","gists_url":"https://api.github.com/users/vtjnash/gists{/gist_id}","starred_url":"https://api.github.com/users/vtjnash/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vtjnash/subscriptions","organizations_url":"https://api.github.com/users/vtjnash/orgs","repos_url":"https://api.github.com/users/vtjnash/repos","events_url":"https://api.github.com/users/vtjnash/events{/privacy}","received_events_url":"https://api.github.com/users/vtjnash/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":9,"created_at":"2015-07-15T04:21:17Z","updated_at":"2015-07-15T04:45:09Z","closed_at":null,"body":"#### problem statement:\r\n\r\na common idiom when working with Associative objects is to do a set of has / insert / lookup operations:\r\n```julia\r\nd = Dict()\r\nif !(key in keys(d))\r\n  d[key] = initial_value\r\nend\r\nvalue = d[key]\r\n```\r\nthis syntax has the advantage of only using basic operations, for clarity, but it's also 3x slower than necessary since the dict lookup gets repeated three times. that concern has lead to the introduction of a `get!` method that accepts either an object or function, to insert a value if the lookup fails, so that the above code can be rewritten as:\r\n```julia\r\nd = Dict()\r\nvalue = get!(d, key, initial_value)\r\n```\r\nor\r\n```julia\r\nd = Dict()\r\nvalue = get!(d, key, () -> initial_value)\r\n```\r\n\r\nhowever, this implementation is still not necessarily faster, since it involves precomputing initial_value (fine it it's just a constant, but bad if it expensive to compute or creates unnecessary garbage) or invoking a lambda.\r\n\r\nthe code to support this one code pattern isn't exactly short, requires a fair amount of code duplication, and even a macro definition is provided (https://github.com/JuliaLang/julia/blob/master/base/dict.jl#L632-L690)\r\n\r\n#### proposal\r\n\r\ndefine the `Ref` operation on a Dict to return an intelligent indexer object. the above code pattern could then be written as:\r\n```julia\r\nd = Dict()\r\nbp = Ref(d, key)\r\nif isempty(bp)\r\n  bp[] = initial_value\r\nend\r\nvalue = bp[]\r\n```\r\n\r\n#### implementation sketch\r\n\r\n```julia\r\ntype RefDict{K, V, D <: Dict} <: Ref{V}\r\n  d::D\r\n  k::K\r\n  last_htindex::Int\r\n  last_state::Int\r\nend\r\nfunction RefDict{K,V}(d::Dict{K,V}, k)\r\n  key = convert(K, k)\r\n  isequal(key, k) || throw(ArgumentError(\"k is not a usable key\"))\r\n  return RefDict{K,V,typeof(d)}(d, k, 0, 0)\r\nend\r\nfunction isempty(r::RefDict)\r\n  if (d.last_state != d.changecounter)\r\n    r.last_htindex = ht_keyindex2(d, key)\r\n    r.last_state = d.changecounter\r\n  end\r\n  return r.last_htindex > 0\r\nend\r\n```\r\n\r\n\r\nref https://github.com/JuliaLang/julia/pull/12035#issuecomment-120614758"},"comment":{"url":"https://api.github.com/repos/JuliaLang/julia/issues/comments/121486196","html_url":"https://github.com/JuliaLang/julia/issues/12157#issuecomment-121486196","issue_url":"https://api.github.com/repos/JuliaLang/julia/issues/12157","id":121486196,"user":{"login":"JeffBezanson","id":744556,"avatar_url":"https://avatars.githubusercontent.com/u/744556?v=3","gravatar_id":"","url":"https://api.github.com/users/JeffBezanson","html_url":"https://github.com/JeffBezanson","followers_url":"https://api.github.com/users/JeffBezanson/followers","following_url":"https://api.github.com/users/JeffBezanson/following{/other_user}","gists_url":"https://api.github.com/users/JeffBezanson/gists{/gist_id}","starred_url":"https://api.github.com/users/JeffBezanson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JeffBezanson/subscriptions","organizations_url":"https://api.github.com/users/JeffBezanson/orgs","repos_url":"https://api.github.com/users/JeffBezanson/repos","events_url":"https://api.github.com/users/JeffBezanson/events{/privacy}","received_events_url":"https://api.github.com/users/JeffBezanson/received_events","type":"User","site_admin":false},"created_at":"2015-07-15T04:45:09Z","updated_at":"2015-07-15T04:45:09Z","body":"Related: #2108"}}