I would like to add new attributes to built in symbols (e.g. ElementData or PolyhedraData) so that I can still call the symbol in the same way (e.g. ElementData["name","property"]) but now with a new, user-added property. Is that possible?
1 Answers
You did not state that you wished to avoid making additional assignments upon a System` Symbol, therefore that is a natural approach and it is possible using Unprotect since ElementData is not Locked, and it appears to work correctly here:
Unprotect[ElementData];
ElementData["Carbon", "Resonance"] = 42;
ElementData["Phlebotinum", "AtomicWeight"] = 666;
Protect[ElementData];
Now:
ElementData["Tungsten", "ThermalConductivity"]
ElementData["Carbon", "Resonance"]
ElementData["Phlebotinum", "AtomicWeight"]
170. W/(m K)42
666
If this this is not acceptable please explain why, or if it fails please give me an example.
Based on the comments I think you need something more advanced than the naive assignments above. Instead your problem is similar to:
Because more general patterns will not result in your own definitions being tried first.
I propose keeping your own element rules in a separate list and using a single DownValue on ElementData to inject them. To accomplish this the DownValue (definition rule) must be placed at the beginning of the DownValues list so that it has priority, and it should be placed there after ElementData is first run to preload the base definitions.
ElementData[] (* preload *);
Unprotect[ElementData];
PrependTo[
DownValues @ ElementData,
HoldPattern[p_ElementData /; $modElemData =!= True] :>
Block[{$modElemData = True}, Replace[Unevaluated[p], elementRules]]
];
Protect[ElementData];
We now define elementRules however we like:
elementRules =
{
_["Carbon", "AtomicWeight"] -> "Fat",
_["Phlebotinum", "AtomicWeight"] -> 666,
_[1 | "H" | "Hydrogen", "Wobble"] -> 0.37,
_[_, "Charge"] -> "Matter"
};
Note that _ is used as a proxy for ElementData; this prevents unwanted evaluation and a more specific pattern is not necessary as these rules will only be applied to ElementData expressions. (Add Dispatch for performance if you have many rules.)
Now the rules are applied before any built-in ones:
ElementData["Titanium", "Density"]
ElementData["Carbon", "AtomicWeight"]
ElementData["H", "Wobble"]
ElementData["Gold", "Charge"]
4507. kg/(m)^3"Fat"
0.37
"Matter"
-
That is what I have been doing but ideally I would like all definitions of "atom" to share such "property" so that not only
ElementData["Carbon", "Resonance"]works but alsoElementData["C", "Resonance"]. Not sure there is a way to easily link them, though, without a manualclone– PFD Aug 14 '14 at 06:37 -
@PFD So you mean you want e.g.
ElementData["anything", "Foo"]to returnbar? – Mr.Wizard Aug 14 '14 at 06:40 -
Yes as long as the value
barbecomes available for other instances ofanything. For ex.ElementData[1, "Name"]returns the same asElementData["H", "Name"]orElementData["Hydrogen", "Name"]=hydrogen. – PFD Aug 14 '14 at 06:53 -
-
@mr-wizard, very elegant. And to generalize your Hydrogen example:
_ElementData[i | ToString[ElementData[i, "Abbreviation"]] | ToString[ElementData[][[i]][[2]]] , "Wobble"] -> 0.4where i is the element number. That will do. – PFD Aug 14 '14 at 15:03 -
@PFD I'm glad you like my answer. However note that
_ElementData[__]will not matchElementData[1,2]but only something likeElementData[1][2]. Use merely_as the head of the pattern as I did in my answer. – Mr.Wizard Aug 14 '14 at 16:31
myElementDatasuch that it callsElementDataand adds new definitions only when that doesn't return a built-in result. Strings with built-in meanings have proliferated in recent versions, andUpValuesdon't work on them; also this makes it harder to do syntax-checking (highlighting) in complicated commands. – Jens Aug 13 '14 at 17:55