[Date Index]
[Thread Index]
[Author Index]
Re: Need features to make kernel and user functions bullet proof
*To*: mathgroup at smc.vnet.net
*Subject*: [mg84064] Re: Need features to make kernel and user functions bullet proof
*From*: Szabolcs Horvát <szhorvat at gmail.com>
*Date*: Sat, 8 Dec 2007 05:46:00 -0500 (EST)
*References*: <fjbceq$4mf$1@smc.vnet.net>
Hi,
Here are my thoughts on this:
Ted Ersek wrote:
> Need features to make kernel and user functions bullet proofWe can
> overload functions that are part of the Mathematica language, and this
> is good. However, we often hear in the MathGroup that you can easily
> break the kernel by changing kernel functions. This wouldn't be so risky
> if users could not indirectly change the way functions such as Solve,
> Simplify, NDSolve, etc. perform. I mean a user should be able to change
> what Simplify does by making a new definition for Simplify, but changing
> functions such as Thread, Map, or Apply should not change Solve, Simplify,
> or NDSolve. Besides that users who are writing their own functions should
> be able to ensure their functions cannot be broken inadvertently.
But is this really necessary? I mean, is there any legitimate reason to
change symbols like Thread, Map, or Apply? If one needs a Map that
behaves a bit differently, shouldn't one just define a new myMap function?
(I know that some people are changing these symbols ... see e.g.
http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/90da91b2fb43891a/4d26e4c1e1edcce3#4d26e4c1e1edcce3
But I always found these things extremely scary (and I think that it is
a bad practice to do this). As you mentioned, it is possible that some
built-in (or package) function uses the form Map[{a,b,c},d] (see the
referenced post), so it would be broken by this change to Map. However,
in this situation the user could have just defined his own listableMap[]
function, which would be safe. Actually after I read that message I
searched all the standard packages and the UpValues, OwnValues and
DownValues of symbols returned by Names[] for Map[_List, __], but found
nothing (though I'm not sure I searched the *built-in* definitions
correctly, and I could completely prevent evaluation of the symbols only
if I ran Mathematica without the Front End ...) )
>
> -------------------------------------------------------------------------
> Also notice you can change the default options of a protected symbol
> without first calling Unprotect. As a result a user can seriously break
> a lot of functions with lines such as
>
> SetOptions[ReplaceRepeated,MaxIterations -> 1];
> SetOptions[Map,Heads->True];
>
> Mathematica needs a new attribute called OptionsProtected.
> OptionsProtected::usage="OptionsProtected is an attribute that prevents
> the default options of a symbol from being modified."
OptionsProtected could be useful.
> -------------------------------------------------------------------------
>
> Now about preventing inadvertent changes to a functions definitions. One
> way WRI could provide this capability would be to have all symbols in the
> System` context also in a context called DefaultDefinitions`. All Symbols
> in context DefaultDefinitions` would have attributes {OptionsProtected,
> Protected, Locked}. That would make it impossible for a user to modify
> features in the DefaultDefinitions` context.
>
> Things that happen automatically behind the scenes should use symbols
> from the DefaultDefinitions` context to ensure everything always
> works correctly. So for example when definitions are automatically
> added to DownValues[f], UpValues[f], etc. they should be created using
> DefaultDefinitions`HoldPattern, and DefaultDefinitions`RuleDelayed.
>
> Imagine what could happen if you changed the meaning of RuleDelayed in
> the current Mathematica.
>
> -------------------------------------------------------------------------=
> -
> WRI could also give us a new function called SystemDefaults that would
> do the following.
>
> Attributes[SystemDefaults]={HoldRest};
>
> SystemDefaults[All, expr] replaces all symbols in expr that are in
> the System` context with the same symbol from the DefaultDefinitions`
> context. Once the replacements are made the new form of expr evaluates.
>
> SystemDefaullts[{symb1, symb2, ...},expr] selects from {symb1, symb2,
> ....} Symbols in the System` context and replaces each instance of
> these symbols in expr with the same symbol from the DefaultDefinitions`
> context. Once the replacements are made the new form of expr evaluates
> ..
>
> -----------------------------------------------
>
> Then I could write the following and ensure all system symbols below
> are from the DefaultDefinitions` context and it would not be possible
> to make Inadvertent changes to my function integrate.
>
>
>
> SystemDefaults[All,
> integrate[c_?NumericQ, f_, x_Symbol]:=c*integrate[f,x];
> integrate[f_+g_,x_Symbol]:=integrate[f,x]+integrate[g,x];
> integrate[x_Symbol,x_Symbol]:=1/2 x^2;
> integrate[_Symbol^n_?(NumericQ[#]&&TrueQ[# != -1]&),
> x_Symbol]:=1/(n+1) x^(n+1)
> ]
>
> ------------------------------------------------
> Instead I might want to use the following to ensure
> symbols DefaultDefinitions`NumericQ, DefaultDefinitions`Power,
> DefaultDefinitions`SetDelayed are used in my definitions of integrate. No
> other symbol form the DefaultDefinitions` context would be used.
>
>
>
> SystemDefaults[{NumericQ,Power,SetDelayed},
> integrate[c_?NumericQ f_,x_Symbol]:=c*integrate[f,x];
> integrate[f_+g_,x_Symbol]:=integrate[f,x]+integrate[g,x];
> integrate[x_Symbol,x_Symbol]:=1/2 x^2;
> integrate[_Symbol^n_?(NumericQ[#]&&TrueQ[#!=-1]&),x_Symbol]:=1/(n+1)x
> ^(n+1)
> ]
>
> In the above examples above use of SystemDefaults[_._] would not force
> the use of symbols from the DefaultDefinitions` context when f[t], or
> (t) in integrate[f[t], t] evaluates.
>
Now about changing symbols like Simplify, NIntegrate, etc.:
There might be reasons for changing these, but one could argue that a
legitimate change should extend these symbols in a mathematically
sensible way, so that other function which use them would not break
(i.e. Simplify would still simplify expression, but would be a bit
smarter, NIntegrate would still compute integrals numerically, possibly
with another method etc.) If the behaviour of these functions is
changed completely, then probably it would have been better to define
completely new functions instead.
So I think that one should never change built-in symbols, except in the
case when it is really expected that the new definitions would be
applied even when the re-defined symbols are used inside some package
(or built-in) function.
I see that the proposed SystemDefaults allows for excluding certain
symbols (more precisely: it allows for only including certain symbols
when rewriting them to the alternatives in DefaultDefinitions), but this
couldn't work correctly because of the nature of Mathematica: Suppose
that we're writing a new function that uses Simplify, and we want to
allow for the re-definition of Simplify, therefore we use
System`Simplify instead of DefaultDefinitions`Simplify. But if our
function "calls" a built-in function that also uses Simplify (I don't
know if there are actually any of these), the built-in function will use
DefaultDefinitions`Simplify and not the intended System`Simplify. So we
would end up with two different versions of Simplify being
inconsistently called in different situations. This sounds even more
dangerous and confusing than the current situation.
In my (subjective) opinion, for those functions where re-definition
seems legitimate (like Simplify), WRI should provide a documented and
safe API that only allows sensible changes. And indeed they do for some
functions: Simplify has the TransformationFunctions option, NIntegrate
can be extended with new integration methods, NumericQ and Derivative
are directly assignable (NumericQ[n] = True and Derivative[1][f] = g
work without Unprotect[]ing these symbols), etc.
To summarize: I think that one should never modify any Protected
built-in functions, except through documented APIs. But I like the idea
of OptionsProtected.
What do other MathGroup users think about this? Are there situations
when it is legitimate to modify built-ins?
I can give one example and show that it was a bad idea because it really
breaks things: when I was trying to get the DownValues of all symbols
returned by Names[], I changed its HoldAll attribute to HoldAllComplete
so that it would work on really strange symbols like 'x' if 'x' has the
definitions x[1]=1 and _[x] ^= x. (Question: Are there other ways of
doing this than changing the attributes of DownValues?) But with this
change, DownValues[Evaluate[sym]] ceases to work, and indeed I got lots
of error messages when I tried to open the Help Browser ...
Szabolcs
P.S. I hope that my broken English didn't make this long post
completely unintelligible.
P.P.S. Your Mathematica Tricks website is really nice!
Prev by Date:
**line in 3d in direction of eigen vector**
Next by Date:
**Memory leak bug in plotting functions? (Sudden kernel shutdown without error message)**
Previous by thread:
**Need features to make kernel and user functions bullet proof**
Next by thread:
**Re: Need features to make kernel and user functions bullet proof**
| |