It would be convenient to have the ability to retrieve Dict
values with dot syntax. Seems like methods could be added to getproperty
for Dict{String, <:Any}
and Dict{Symbol, <:Any}
so that values could be accessed the same way you would a DataFrame column:
Dict("key" => "value")."key" == "value"
Dict(:key => "value").key == "value"
1 Like
Personally, I think it should be, but there were some objections during the 1.0 release process. Now it might be considered breaking to change the existing meaning of d.keys
and d.values
, etc. Of course it can also be argued that fields of types are conventionally private, but that could break quite a lot of code out there.
Not all keys can be properties. For example Dict(1=>2)
is fine, but x.1
is not.
1 Like
But it could at least work when keys are symbols, so d.foo
would mean d[:foo]
which would be extremely useful in many contexts.
And x.:1
is totally fine: it calls getproperty(x, 1)
.
Ehh, programming styles that only work for a special cases (or require some ānon-standard tricksā like @aplavin showed) are generally something Iād avoid. Thereās other issues here too though. x.foo
has literal information, and so if you know all of the fields already and have that information at compile-time, why not use a NamedTuple? It would be safer, because x.foo2 = y
would create a new field in the Dictionary while it would error with the NamedTuple, so if you know all of the fields at compile-time well enough to write x.foo
then you probably want error checking. If you donāt know the field at compile-time, then youād do getproperty(x,:foo)
, in which case you might as well do x[:foo]
.
So I just donāt see where the utility is: either itās dynamic so use a Dictionary and because itās dynamic names you need to x[sym]
, or itās static so you can x.foo
in which case you can construct it like (;foo = y)
.
7 Likes
There are cases where you donāt want to use NamedTuple because you need mutability and also because you have many of these objects and want a unique type to not trigger needlessly many compilation of methods. One example where this dot syntax is convenient if for āconfigurationā, which can be stored in files for example, which you could load with YAML
and manipulate with such a configuration dict; in some contexts you want to assume that some keys do exist (and be able to write statically e.g. config.params
), you might have for example validated the data upstream, and at the same time allow arbitrary keys at whatevel level of the configuration.
3 Likes
You run into issues shadowing actual properties of Dicts
, no? Dict
has properties
julia> propertynames(Dict())
(:slots, :keys, :vals, :ndel, :count, :age, :idxfloor, :maxprobe)
Of course, none of these are part of the public interface so it would technically be possible to bury them under key names (after rewriting all the Dict
internals to use getfield
rather than getproperty
). But having mydict.count
mean different things depending on whether :count
is a key seems like a recipe for chaos.
Is mydict[:count]
really so onerous? NamedTuple
also supports this syntax, so itās already a consistent interface for both.
3 Likes
In some cases yes, when you have nested stuff, like d[:a][:b]
instead of just d.a.b
, in particular when playing with this at the REPL (well, the REPL-completion is kinda broken for this case, I have a patch for this waiting to be PRāedā¦)
(EDIT: Iām not specifically arguing in favor making Dict
handle the nice dot syntaxt, just that dot syntax is actually very convenient; I currently just use a custom dict).
Allowing the .
for Dict
to work like it does for NamedTuple
and DataFrame
would be more consistent ā¦
The inconsistency while I was coding today is what brought this to my attention.
# Package Table
df = DataFrame()
df."Quantity" = ["Radial Stress", "Tangential Stress", "Longitudinal Stress", "Equivalent Stress"]
df."Average" = Ļ_mean
df."Maximum" = Ļ_max
df."Minimum" = Ļ_min
df."Max Location" = r[Ļ_max_index]
df."Min Location" = r[Ļ_min_index]
# Package Unit Dictionary for Table Columns
df_units = Dict{String, Any}()
df_units["Quantity"] = ""
df_units["Average"] = Ļ_units
df_units["Maximum"] = Ļ_units
df_units["Minimum"] = Ļ_units
df_units["Max Location"] = r_units
df_units["Min Location"] = r_units
But I wasnāt aware that Dictionaries had inherent properties, so that is probably a good enough reason not to implement this.
GitHub - JuliaCollections/PropertyDicts.jl does this but is out of date. I made a PR a while ago to resolve this but not many people have permissions to repos in JuliaCollections
2 Likes
Frames White (@oxinabox) was kind enough to give me permissions, so PropertyDicts.jl has been updated with a new version.
3 Likes