Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to read the code of already defined function (especially from the System` context)?

Occasionally we like to look into how certain System` functions are defined (when they're written in Mathematica). This question is about the best way to do that.

Points to keep in mind:

  • Of couse ReadProtected needs to be removed first.

  • Builtins usually need to be used at least once before they get loaded into the kernel. Is a single simple invocation usually sufficient for this when they have extended functionality (e.g. through options)?

  • Information (??) gives the definition in a hard-to-read format (no indentation, and all private context names prepended). What is the best way to get rid of the context names, and get formatted code?

    One idea for getting rid of certain contexts is Block[{$ContextPath = Append[$ContextPath, "SomeContext`Private`"], Information[symbol]]. Code can be auto-formatted using Workbench. Some issues remain, e.g. Information doesn't quote strings, preventing the code from being able to be copied into Workbench.

Generally, I'm interested in how people do this, what methods they use to make the code of builtins as easy to read as possible.

Use case: For example, recently I digged into the code of RunThrough when I found out that it simply doesn't work on Windows XP (turns out it fails to quote the names of temp files when the path to them contains spaces).


Update: It appears that there used to be a function for printing definitions without context prepended, Developer`ContextFreeForm, but it's not working any more in newer versions.

like image 651
Szabolcs Avatar asked Dec 22 '11 17:12

Szabolcs


2 Answers

Regarding the pretty-printing: the following is a very schematic code which builds on the answer of @Mr.Wizard to show that a few simple rules can go a long way towards improving the readability of the code:

Internal`InheritedBlock[{RunThrough},
   Unprotect[RunThrough];
   ClearAttributes[RunThrough, ReadProtected];
   Block[{$ContextPath = Append[$ContextPath, "System`Dump`"]},
      With[{boxes = ToBoxes@ DownValues[RunThrough]},
         CellPrint[Cell[BoxData[#], "Input"]] &[
            boxes /. 
            f_[left___, "\[RuleDelayed]", right___] :> 
                 f[left, "\[RuleDelayed]", "\n", right] //.
           {
             RowBox[{left___, ";", next : Except["\n"], right___}] :> 
                 RowBox[{left, ";", "\n", "\t", next, right}],
             RowBox[{sc : ("Block" | "Module" | "With"), "[", 
               RowBox[{vars_, ",", body_}], "]"}] :>
                 RowBox[{sc, "[", RowBox[{vars, ",", "\n\t", body}], "]"}]
           }]]]]

This is for sure not a general solution (in particular it won't work well on deeply nested functional code without many separate statements), but I am sure it can be improved and generalized without too much trouble to cover many cases of interest.

like image 57
Leonid Shifrin Avatar answered Sep 19 '22 20:09

Leonid Shifrin


Good question, because I don't think I have seen this discussed yet.

I do essentially the same thing you outlined. You can get a somewhat different print-out with Definition, and more information with FullDefinition:

Unprotect[RunThrough];

ClearAttributes[RunThrough, ReadProtected]

Block[{$ContextPath = Append[$ContextPath, "System`Dump`"]}, 
  Print @ FullDefinition @ RunThrough
]
like image 32
Mr.Wizard Avatar answered Sep 19 '22 20:09

Mr.Wizard