Module functions vs built-in functions

When you call a method that’s not exported (or even defined!) from a module, Julia matches a function defined outside the module. Is this a bug?

Example code:

module LogicalOperations

export and, or, not

function and(p, q)
    p && q

function or(p, q)
    p || q

function not(p)

end # End of module

# Setup
op = LogicalOperations 
x = 5
y = 10

op.and(x > 4, y == 10) # Works as expected

op.xor(x > 4, y == 9) # Julia calls the built-in function xor, which is not part of the module!

Let’s say those definitions were a part of MyPackage.jl, a big package that also needs since logical operations.

You write some code using MyPackage.and and MyPackage.not.
Then, one day, the author of MyPackage decides to refactor, and split the codebase into related packages, e.g. grouping all the logical functions into a new package called LogicalOperations, and has MyPackage now use/depend on it. Or maybe not even a new package, but a submodule within the package.

Should the code calling MyPackage.and and MyPackage.not start to error? Should this refactoring be a breaking change?

Or course, you could also say code shouldn’t depend on the internals of other packages, and that if they do they should expect random breakages.
However, not all packages define their API as what they export, and this would be restrictive on what sort of internal reorganizing is allowed.

You could make your module a baremodule if you don’t want base methods to be in scope.


Great, thanks, I’m going to look at baremodule!

As you can tell I come from an OOP background, and certain aspects of Julia are… strange.

Is this because modules define just “namespaces” and then clearly a function which is available in the namespace of the module can be called explicitly from that namespace?

Is that one way of seeing this?

1 Like

There is an implicit using Base at the beginning of each module, see