Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to import an MX file without evaluating the contents?

Question: Is it possible to import an MX file saved using DumpSave without evaluating the contents?


Let me illustrate:

Let's create a variable, data:

In[2]:= data = Range[10]

Out[2]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

It can be exported to and imported from MX without making any definitions:

In[3]:= ImportString@ExportString[data, "MX"]

Out[3]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

But what if we use DumpSave?

In[4]:= DumpSave["data.mx", data]

Out[4]= {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}

(And clear data)

In[5]:= Clear[data]

On re-import, nothing is returned:

In[6]:= Import["data.mx", {"MX", "HeldExpression"}]

But the variable data becomes defined again, as if we had used Get.

In[7]:= data

Out[7]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

I would have expected to get something like Hold[data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}], i.e. something similar to what would be written to an .m file when using Save.


Perhaps it's technically impossible to avoid the definition being made because DumpSave and Get directly manipulate the kernel state instead of writing and reading an evaluatable definition like Save does? This is just a guess.


(edit) please note: I am not trying to save in a way that can be imported "Held". I can already do that using Export. I am looking to import previously DumpSaved MX files instead.


Answer It appears it is impossible to do this unless the MX file was saved to specifically allow it.

like image 220
Szabolcs Avatar asked Jan 04 '12 18:01

Szabolcs


2 Answers

First, let me point out that there appears to be an undocumented third argument for DumpSave. I discovered this while trolling for functions with MX in them.

See for yourself by evaluating ?System`Private`BuildApplicationMXFunction (fix those context marks--SO markup prevents using the regular symbol). Note that in the last line of the function, HoldAllComplete is given as a third argument.

Dunno if that will be of use or not. Regardless, here's a solution to what I think you're asking.

Remove[data, assignment];
assignment := (data = Range[10])

Depending on what you want, you might also try assignment := Defer[(data = Range[10])].

Now evaluate:

DumpSave["data.mx", assignment, HoldAllComplete] (*Also could try Unevaluated as 3rd arg *)
Remove[data, assignment];
Import["data.mx", "HeldExpression"]

And note that data is undefined until evaluating assignment. If you use the Defer version ofassignment,data will again be undefined and assignment will return (literally) data = Range[10] You could use Evaluate@@assignment to evaluate and restore the original assignment to data.

(Now it's time to read Leonid's answer and see how dumb I am!!) :D

like image 43
telefunkenvf14 Avatar answered Nov 14 '22 20:11

telefunkenvf14


My understanding is that the logic of .mx files is the inverse one: when you load an .mx file, the definitions (DownValues and others) for symbols are created at the lowest level, so that the values are assigned directly to the internal memory locations, by-passing the main evaluator. This is the reason why loading .mx files is so fast. It seems that you can't have both - your expectation corresponds to a higher-level symbolic code. You can, however, encapsulate your data by using symbols in some context, as handles for that data.

So, I don't see a real problem here, since you can always query the DownValues and other ...Values of symbols and extract the r.h.sides of the rules in unevaluated form (there are some pathological cases for which DownValues don't fully reconstruct the original definitions being stored in them, but they are, so to say, of measure zero, and not much practical importance). You can define certain interface, which would allow you to extract your data via a few functions (symbols), while the data can use many more symbols under the cover, which would be hidden behind those.

EDIT

If you control the initial use of DumpSave, here is an illustration of one possibility - you can create a custom dumpSave-like function. These are helper function to prepare information on symbols:

ClearAll[dress];
dress[prop_] := 
   Function[s, With[{pr = prop[s]}, Hold[prop[s] = pr]], HoldAll]

ClearAll[getHeldProperties];
getHeldProperties[HoldComplete[s_Symbol]] :=
 Thread[
    Through[(dress /@ {
        DownValues, UpValues, OwnValues,
        SubValues, DefaultValues, NValues, 
        FormatValues, Options, Messages, 
        Attributes
      })[Unevaluated[s]]], 
    Hold];

for example:

In[284]:= 
getHeldProperties[HoldComplete[data]]

Out[284]= Hold[{DownValues[data]={},UpValues[data]={},OwnValues[data]={HoldPattern[data]:>
{1,2,3,4,5,6,7,8,9,10}},SubValues[data]={},DefaultValues[data]={},
NValues[data]={},FormatValues[data]={},Options[data]={},Messages[data]={},
Attributes[data]={}}]

Now, the main function:

ClearAll[dumpSave];
SetAttributes[dumpSave, HoldRest];
dumpSave[file_String, storage_Symbol, symbs___] :=
  Module[{n = 1},
    Replace[
      Thread[HoldComplete[{symbs}]],
      held : HoldComplete[s_] :> 
         (storage[n++] = getHeldProperties[held]), 
      {1}];
    DumpSave[file, storage]
]

You basically designate a single symbol as a storage of unevaluated definitions of other symbols. Here is how you can use it:

dumpSave["data.mx", storage, data, dumpSave, dress]

If you now clear the storage symbol and load back the file, you will observe that all definitions of other saved symbols are stored in unevaluated form in DownValues of storage. You only need to call ReleaseHold on them to actually execute the assignments, but you also have access to them in unevaluated form.

like image 125
Leonid Shifrin Avatar answered Nov 14 '22 21:11

Leonid Shifrin