8
$\begingroup$

In Mathematica 9, I had the function(s). I apologize for the weak formatting.

RemoveBackground[data_,n_,rng_?NumericQ]:=RemoveBackground[data,n,{{-∞,-rng},{rng,∞}}];

RemoveBackground[data_,n_:2,regions_:{{-∞,∞}}]:= (

RemoveBackground[] = Function[{x}, Evaluate[
    Fit[
        (* select points only in specified regions *)
        Select[
            Flatten[data,Depth[data]-3],
            Function[{pt},Or@@(#[[1]]<=pt[[1]]<=#[[2]]&/@regions)]
        ][[;;,;;2]],
        (* build list of polynomial terms *)
        x^#&/@Range[0,n],
        x
    ]
]];

Map[ReplacePart[#,2->#[[2]]-RemoveBackground[][#[[1]]]]&, data, {-2}] );

Now in Mathematica 10.0, RemoveBackground is a protected function. I know that you can unprotect variables. This worked perfectly fine when I had to do it Devices, which they also protected in Mathematica 10.0. For some reason since one of the calls to RemoveBackground has four arguments it goes red inside the package and continues to give the message

SetDelayed::write: Tag RemoveBackground in RemoveBackground[data_, n_:2, regions_:{{-inf,inf}}] is protected.

It doesn't seem to to matter where I put Unprotect[RemoveBackground]; I keep getting this error. Any ideas as to why?

I have also tried various combinations of Unprotect then Clear as well.

$\endgroup$
  • 1
    $\begingroup$ RemoveBackground is a new system function. You'll need to change the name of yours. See reference.wolfram.com/language/ref/RemoveBackground.html $\endgroup$ – Chip Hurst Aug 12 '14 at 21:00
  • 1
    $\begingroup$ I am aware of this. However this function has been a staple for almost 4 years used throughout various notebooks and packages. It would be much better if there was just a way to remove the definition. For example Sqrt[] is protected but it is extremely easy to change the definition. $\endgroup$ – Nick Aug 12 '14 at 21:11
  • 4
    $\begingroup$ This perfectly illustrates the rule that the user-defined symbols should always start from a lower-case letter. $\endgroup$ – Alexey Popkov Aug 13 '14 at 2:06
  • 3
    $\begingroup$ @AlexeyPopkov I don't think it does... all that OP needs to learn is some context management, which is not hard. I don't think that everyone needs to strictly adhere to this maxim for their packages. $\endgroup$ – rm -rf Aug 13 '14 at 3:56
  • 2
    $\begingroup$ @Nick As others have mentioned, there is a collision with a built-in function. I would not recommend clearing the definitions of the System` symbol to make way for yours, because you never know what depends internally on what (and it is a bad practice, period.) and you could be doing more damage than you think. Rather, you might want to look at using the full contexts, such as MyPackage`MySymbol and System`MySymbol. This way, you get to use both functions. You can also change the order in which the contexts appear in $ContextPath to determine which definition is used first. $\endgroup$ – rm -rf Aug 13 '14 at 4:01
9
$\begingroup$

Do not try to redefine a System` symbol. It is almost guaranteed to cause trouble sooner or later. Instead, here's how to deal with name collisions:

If your function is not part of a package, then make sure that you never used symbol names that start with a capital letter. This way you can avoid name collisions. The same applies to any non-public symbols used in packages.

If your function is part of a package: Let's look at a standard package structure first. Your package should look like this:

BeginPackage["My`"]

RemoveBackground

Begin["`Private`"]

RemoveBackground[___] := "Package symbols"

End[]
EndPackage[]

The definition RemoveBackground[...] := ... will fail in Mathematica 10, as RemoveBackground is a builtin now. What you need to do at this point is simply specify the full name, including the context, at the point where the symbol name is exported. This requires a single simple change. The package should look like this now:

BeginPackage["My`"]

My`RemoveBackground    (* <-- single change required *)

Begin["`Private`"]

RemoveBackground[___] := "Package symbols"

End[]
EndPackage[]

When you load the package, you will get a warning

RemoveBackground::shdw: Symbol RemoveBackground appears in multiple contexts {My,System}; definitions in context My` may shadow or be shadowed by other definitions. >>

but don't worry about it, it's just a warning. Notice the $ContextPath after loading this package:

$ContextPath
(* {"My`", "TemplatingLoader`", "PacletManager`", "System`", "Global`"} *)

Your package's context appears before System` in the context path. This means that whenever you type RemoveBackground, it will automatically refer to My`RemoveBackground and not to System`RemoveBackground. You do not need to and should not try to modify System`RemoveBackground. Just create My`RemoveBackground, as I described above, and you'll be able to refer to it as RemoveBackground, without explicitly needing to mention the context name:

Mathematica graphics

In summary, the proper way to proceed: Do not modify the builtin RemoveBackground. Instead create an identically named symbol in a different context and let it shadow System`RemoveBackground.

Ideally, eventually you'll be able to rename your own function and all code that is using it. If that's not possible, (or as a temporary measure) use the solution from above. If you are the only user of your package, then I suggest you do rename your function eventually.

$\endgroup$
  • $\begingroup$ Thanks, this worked for me. I usually just use the unprotect but this is much cleaner. The code we use was written a while back and it seems like every Mathematica update they add a function or two that overlaps our namespace. I've suggested an overhaul but we tend to use old notebooks quite a bit, and going through and changing it every time is tedious. Plus some of the older members tend to get up in arms over any changes. $\endgroup$ – Nick Aug 13 '14 at 16:35
  • 1
    $\begingroup$ @Nick Even some of the packages that come with Mathematica have conflicts with new builtins and this is how they deal with the conflicts. Just one thing to keep in mind: make sure any private package symbols, i.e. everything that's not explicitly exported inbetween BeginPackage and Begin, does not start with a capital letter. If private symbols conflict, it will be harder to fix them. If public symbols conflict, it's a single change that's needed for each conflict. $\endgroup$ – Szabolcs Aug 13 '14 at 16:57
  • $\begingroup$ Although if something like that occurs in the private part of the package a simple name change should be possible right? Since that's just the guts and a name change wouldn't change what the package does? $\endgroup$ – Nick Aug 13 '14 at 17:15
  • $\begingroup$ @Nick Sure. But why not avoid it in the first place? Do you have unit tests for the package? If not, you might not even notice that something broke until someone tries to use an affected function (if you're unlucky, otherwise it'll complain on package load). Combinatorica uses some capitalized private names, and they have to keep patching it with each release now ... $\endgroup$ – Szabolcs Aug 13 '14 at 17:24
  • $\begingroup$ We have unit tests for a majority of the packages. Some of them are highly experimental (ie the whole point is we don't know quite what we expect) and I can see the merit in avoiding capital letters in that case. $\endgroup$ – Nick Aug 13 '14 at 17:28
10
$\begingroup$

Caveat

This is the known risk with any user definition upon a Symbol starting with a capital letter that is not explicitly called from a user context. It is not adequate to believe that you will not need any new functionality that is added as the new function may itself be required by other functions which you do need, including existing ones if they are rewritten using the new abstraction.

The preferred course of action is to use only Symbols starting with lower-case letters or call your function with an explicit context, e.g. Nick`RemoveBackground. By convention the first method should never conflict with built-in functions, and so long as Wolfram Research doesn't release a standard package named Nick you should be OK with the second.

Since "this function has been a staple for almost 4 years used throughout various notebooks and packages" you require a work-around.

 

Overwrite the System function

Since the System` function is not Locked we can at least attempt to enact a direct substitution. The first reason you had trouble is that the native function definition is not fully loaded initially. I ran into this surprise myself a few years ago:

The second reason is that you did not clear the existing definition before proceeding.

Incorporating a fix for each issue your redefinition works:

Quiet @ Quiet @ RemoveBackground[1] (* preload *);

Unprotect[RemoveBackground];

ClearAll[RemoveBackground] (* remove old definitions *);           

RemoveBackground[data_, n_, rng_?NumericQ] := . . .

 

Define your function in a user context

Rather than trampling on a System` function which may or may not be used internally you can define your new function in a user context, then prioritize your context over System`. This results in shadowing and red warning syntax, but it also lets your function work as desired without actually overwriting the built-in or having to rename every appearance of your function. Rather than using your full definition I shall show how this works with a very simple example. Imagine that I want Plus to concatenate strings rather than add numbers:

BeginPackage["foo`"];

foo`Plus[s__] := StringJoin[s]

EndPackage[];

Plus::shdw: Symbol Plus appears in multiple contexts {foo`,System`}; definitions in context foo` may shadow or be shadowed by other definitions. >>

The new context foo` is prefixed to $ContextPath which means that its definitions are prioritized. Now a use of Plus is highlighted in red (by default) to indicate shadowing, and my definition is used:

enter image description here

Crucially however System`Plus remains unharmed:

System`Plus[1, 2, 3]
6

It is also used if the short form of Plus is used as this is interpreted as System`Plus directly:

1 + 2 + 3
6
$\endgroup$
  • $\begingroup$ Okay I agree with your second method, that works fine (other then having to live with constant red text). Your first method however seems to not quite work for a strange reason. If I run the code with the Quiet @ Quiet ... RemoveBackground doesn't work properly. It seems to be in that first line I have above. RemoveBackground[data_,n_,rng_?NumericQ]:=RemoveBackground[data,n,{{-\[Infinity‌​],-rng},{rng,\[Infinity]}}]; Everything after the second n, to the colon is red and I get the Set::write error. I would like to believe it is because the system RemoveBackground can only take two arguments $\endgroup$ – Nick Aug 13 '14 at 17:17
  • $\begingroup$ @Nick I am having trouble replicating the problem you describe. Do you have time to join me in Chat? $\endgroup$ – Mr.Wizard Aug 13 '14 at 22:11
  • $\begingroup$ Indeed, I will be around for the next hour or so. $\endgroup$ – Nick Aug 13 '14 at 23:37
  • $\begingroup$ Okay if I pull out the code above and put it into its own package this works fine (I still get a Set::write error but the code executes). I'm not going to go through and figure out what the difference is between the full package and the snippet I pulled out. $\endgroup$ – Nick Aug 13 '14 at 23:54

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.