Is using `Base.delete_method` on user-defined functions safe?

does someone know if using Base.delete_method user-defined functions is dangerous in any way? I searched for its use on registered packages and someone does already make use of it: https://juliahub.com/ui/Search?q=delete_method&type=symbols. As a minimal example:

julia> f() = 1
f (generic function with 1 method)

julia> Base.delete_method(methods(f)[1])

julia> f() = 2
f (generic function with 1 method)

julia> f()
2

is this bad for some reason (apart that it is unexported)? Or are there other cases which it can cause unexpected behaviours?

For clarification, is there any reason you can’t just redefine the method?

julia> f() = 1
f (generic function with 1 method)

julia> f() = 2
f (generic function with 1 method)

julia> f()
2

@CameronBieganek when this happens in a package it makes precompilation to fail with WARNING: Method definition X in module Y overwritten at Z, and this is my real use case. It doesn’t fail if you first remove the method.

Why are you overwriting the method at all? Why not just delete the first definition from your code?

1 Like

it’s because I actually generate the function with a macro given the information of the function until that point. If it happens that new information shows up for that updates that specific signature of the function I need to redefine it to incorporate the new info. More concretely, I produce a series of if-else branches inside a function at different point in the code with the help of a macro.

It’s hard to say without knowing more, but perhaps you can keep an Expr around with the function definition, and then evaluate the Expr once you know it’s ready?

At any rate, I am of the opinion that you should avoid using private functions from Base (or third-party packages) unless absolutely necessary.

2 Likes

Actually I can let you know a lot more :smiley: , this is the package in question: GitHub - JuliaDynamics/DynamicSumTypes.jl: Combine multiple types in a single one. Actually I sidestepped a bit all this issue by doing exactly what you said with a Expr…I tried to load all the expressions inside (a subpackage) __init__() which is loaded automatically after the package is precompiled, there is a problem though because it means that one can’t actually use a precompile.jl file,actually the __init__ function could call the precompile statements. Stupid me. So this is okay. The only real issue is that they functions defined that way can’t be extended outside of the package, but I can live with that because I can’t really conceive that being useful in this case. So I think I’m fine actually :slight_smile:

That said, I’m still curious, also because there are already some packages doing something similar

1 Like

I have a similar issue in DuckDispatch where I need a fallback method to catch all the calls, wrap them based on the current set of applicable DuckTypes and then redispatch the wrapped arguments.

But each time a new DuckType is used to dispatch that same function, I need to replace the original fallback with one that has the new list of DuckTypes to check.

So I get the warning too.

Edit: sorry for autocorrect profanity :man_facepalming:

Using an internal function to evade an error doesn’t imply you don’t run into the dangers the error was trying to prevent. Precompilation caches apparently don’t support method overwriting well at all:

Turn Method Overwritten Error into a PrecompileError – turning off caching by vchuravy · Pull Request #52214 · JuliaLang/julia · GitHub

I don’t know the mechanics of why overwriting methods during precompilation is such an issue, and the underlying code in gf.c appears to be completely separate, so I can’t say if deleting then replacing a method would do the same thing.

1 Like