5
$\begingroup$

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?

$\endgroup$
  • 1
    $\begingroup$ Related: access-curated-or-locally-stored-data-with-curated-data-functions $\endgroup$ – Sjoerd C. de Vries Aug 13 '14 at 15:51
  • $\begingroup$ This is difficult to achieve, mainly because the arguments are strings so that it's not possible to directly use the approach mentioned by @SjoerdC.deVries. Maybe the cleanest way would be to define myElementData such that it calls ElementData and adds new definitions only when that doesn't return a built-in result. Strings with built-in meanings have proliferated in recent versions, and UpValues don't work on them; also this makes it harder to do syntax-checking (highlighting) in complicated commands. $\endgroup$ – Jens Aug 13 '14 at 17:55
3
$\begingroup$

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"
| improve this answer | |
$\endgroup$
  • $\begingroup$ 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 also ElementData["C", "Resonance"]. Not sure there is a way to easily link them, though, without a manual clone $\endgroup$ – PFD Aug 14 '14 at 6:37
  • $\begingroup$ @PFD So you mean you want e.g. ElementData["anything", "Foo"] to return bar? $\endgroup$ – Mr.Wizard Aug 14 '14 at 6:40
  • $\begingroup$ Yes as long as the value bar becomes available for other instances of anything. For ex. ElementData[1, "Name"] returns the same as ElementData["H", "Name"] or ElementData["Hydrogen", "Name"] = hydrogen. $\endgroup$ – PFD Aug 14 '14 at 6:53
  • $\begingroup$ @PFD Please see my updated answer. $\endgroup$ – Mr.Wizard Aug 14 '14 at 7:16
  • $\begingroup$ @mr-wizard, very elegant. And to generalize your Hydrogen example: _ElementData[i | ToString[ElementData[i, "Abbreviation"]] | ToString[ElementData[][[i]][[2]]] , "Wobble"] -> 0.4 where i is the element number. That will do. $\endgroup$ – PFD Aug 14 '14 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.