I have a Base module that contains some functionality, which I would like to (optionally) extend upon.
Ideally, the extension simply overrides some functions in the base module, while leaving the others as they are.
One option which comes to mind is to define a submodule, which imports the desired function, however the following code does not work as intended:
module BaseModule
export g
f() ="Base Module"
function g()
print("Version is: ")
println(f())
end
module Extension
export g
using ..BaseModule
import ..BaseModule:f
f() = "Extension"
end
end
Calling the function g gives:
julia> BaseModule.Extension.g()
Version is: Extension
julia> BaseModule.g() #I'd like this to print "Version is: Base Module" instead
Version is: Extension
Can anyone help me in this? Is there maybe a better way achieving the desired result?
Other ideas, I’ve had:
Create two separate modules, with the second one importing the first. → I get nasty warnings if i want to simply overwrite the function from another module
Create both modules in the same repository, each including the respective definitions independently. → Pkg.add only adds the first module so I would always have to include the file with the definition of the second module.
Looking forward to hear some interesting suggestions from you.
I don’t see any warning from this (not importing f in the Extension module)
module BaseModule
export g
f() ="Base Module"
function g()
print("Version is: ")
println(f())
end
module Extension
export g
using ..BaseModule
f() = "Extension"
end
end
you’re overriding this function. Please don’t do this, Julia is not Class-OOP, please don’t use Module as hacky “Class” for “dispatching”
a function from a different modules (normally speaking, ) should never “replace” each other completely. If they are unrelated, use name space, A.f() and B.f(), if they are related, use multi dispatch
Yes, multiple dispatch is probably the solution here. In my case, the extension module does not require me to define a new type, so there seems no natural way to use multiple dispatch here. Of course, I could define a dummy type which is different for both modules and pass it to the functions to distinguish them, but that also feels slightly unelegant.
if it doesn’t need a new type, and you’re doing (spiritually) the same thing f() to the same data, but it’s somehow different, why should this function be called f(), it should be called B.f() (again, just use name space to distinguish) or advance_f()
In essence, f is a setup function that is later used by another function g and g is further used. Since f is the only function that changes, I would prefer to keep the name so that I do not need to modify all the other functions down the line. I suppose another way would be to modify g to take f as an input, though
yeah. If g() rely on a setup function but that setup function is “hot swapable”, you should make that an input and have a default maybe. Think count. which by default the by function is identity, this pattern is common.
silently mutating the f() that g() ends up calling is pretty hacky, and hard to undo from the user end if they somehow uses your extension package but want to do the “original” thing – it ends up being a import-order-dependent issue then?
Thank you for your help. I accept your argument that this is probably the best option, so I marked it as a solution. (Of course I still have interest in hearing if there are other approaches to this).
To answer your question: Yes, I suppose it does. Although my intention was not really that both modules really have to be used within the same scope (Its a module for my own purposes that is unlikely to be of use to others), it is still better to do this without breaking it if one decides to do so anyway.