What's the value of using symbols instead of string literals to reference dictionary keys?
It replaces a 'magic string' with a 'magic variable name', which is worse than the normal solution for magic strings, which is to move them to a constant.
If I have code in one place that says:
dict["key"] = "value";
and code elsewhere that says:
var value = dict["key"];
I can make that code better today by adding
const string KEY = "key"
and then using dict[KEY] in both places. I can change the key in one place, and if I misspell the constant name in either location then the compiler tells me I have a problem.
With the new syntax, I can now write
dict.$key = "value";
and
var value = dict.$key;
but if I go ahead and change one of these:
dict.$newkey = "value";
I'm not going to get a compiler warning when I try to read $key (am I?). Unless there's some smart tooling support, where's the win here?
Key symbols aren't becoming a new type - I don't get to write
var key = $key;
var big_key = ["key with spaces"];
(so far as I'm aware - though I actually quite like the idea of a datatype that represents this kind of non-manipulable string identifier)
I guess the new .$ syntax combines with the null-propagating ?. operator, so you could have nested dictionaries and access them with:
dict?.$subdict?.$subsubdict
which looks... horrible. And suffers from the fact that there's no null-propagating equivalent index access operator, ?[], so I can only use this trick on keys that can be written as C# symbols.
I really feel like I'm completely missing what the use cases are for this capability...
But if they were adding symbol support, it would have to work for accessing actual members, not for just faking string indexed members as if they were members. Symbol support would let you do things like this:
public double GreatestExtent {
get {
Symbol directionOfGreatestExtent = $X;
if (this.Y > this.X) directionOfGreatestExtent = $Y;
return this.#directionOfGreatestExtent;
}
}
(I'm making up some sort of syntax on the spur of the moment here)
Clearly this can be written easily enough without symbol support, but you could argue that the intent of the logic is clearer here than it is in some alternative approaches.
But the thing is that the kind of symbol they've given us isn't a syntax where $foo is a literal which means 'a symbol which accesses the member foo on the target', but instead a syntax where $foo means 'a symbol which accesses the indexer on the target which takes a single string as an argument and passes the string "foo" to it' - just like ["foo"] does.
If I have my co-ordinates stored in a dictionary, I don't need this symbol support to be able to write that kind of logic:
public double GreatestExtent {
get {
string directionOfGreatestExtent = "X";
if (this["Y"] > this["X"]) directionOfGreatestExtent = "Y";
return this[directionOfGreatestExtent];
}
}
In fact, it isn't even possible to really make use of the new $key support in that scenario because, as I said, they're not providing any mechanism to store the $key value and reuse it; you're forced to mix string literals and these key symbols:
public double GreatestExtent {
get {
string directionOfGreatestExtent = "X";
if (this.$Y > this.$X) directionOfGreatestExtent = "Y";
return this[directionOfGreatestExtent];
}
}
I don't see how being able to make that change to this code is a step forward...
It replaces a 'magic string' with a 'magic variable name', which is worse than the normal solution for magic strings, which is to move them to a constant.
If I have code in one place that says:
and code elsewhere that says: I can make that code better today by adding and then using dict[KEY] in both places. I can change the key in one place, and if I misspell the constant name in either location then the compiler tells me I have a problem.With the new syntax, I can now write
and but if I go ahead and change one of these: I'm not going to get a compiler warning when I try to read $key (am I?). Unless there's some smart tooling support, where's the win here?Key symbols aren't becoming a new type - I don't get to write
(so far as I'm aware - though I actually quite like the idea of a datatype that represents this kind of non-manipulable string identifier)I guess the new .$ syntax combines with the null-propagating ?. operator, so you could have nested dictionaries and access them with:
dict?.$subdict?.$subsubdict
which looks... horrible. And suffers from the fact that there's no null-propagating equivalent index access operator, ?[], so I can only use this trick on keys that can be written as C# symbols.
I really feel like I'm completely missing what the use cases are for this capability...