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 DumpSave
d MX files instead.
Answer It appears it is impossible to do this unless the MX file was saved to specifically allow it.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With