# Implicitly loaded modules in the future?

**URL:** <https://discourse.julialang.org/t/implicitly-loaded-modules-in-the-future/62646>\
**Category:** Internals & Design\
**Tags:** question, module, code-organization\
**Created:** [June 9, 2021, 8:58pm UTC](https://discourse.julialang.org/t/implicitly-loaded-modules-in-the-future/62646 "2021-06-09T20:58:00Z")\
**Posts on this page:** 1\
**Showing post:** 265

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [June 24, 2021, 4:40am UTC](https://discourse.julialang.org/t/implicitly-loaded-modules-in-the-future/62646/265 "2021-06-24T04:40:07Z")

</div>

I could get behind @Skoffer’s idea regarding the keyword `depends`. I would favor the word `depends` over `import`, since `import` is already used to mean that you are importing objects from a module.

@patrick-kidger My apologies if the `depends` idea is essentially what you had in PatModules.jl… perhaps I didn’t look closely enough at the details of that package.

The advantages of `depends`, from my point of view:

- I no longer have to manually order my `include` statements.
- It does not enforce a file-module correspondence.
  - Thus, I can still use the flat namespace that I prefer.

However, the example that @Skoffer provided is not the best example, because you can define your methods of `foo` in whatever order you want. There’s no sense in which the `A.jl` and `B.jl` files depend on the `utils.jl` file. (`function foo end` is not more primal than any other method.) If we ignore modules that run imperative code, the only thing that matters is that types are defined before they are referred to.

Let me elaborate a bit more on why I don’t like turning every file into a module. Suppose I have a generic function `foo`, with various methods, that gets used throughout a package `DemoPackage.jl`. With Julia as it is now, `foo` “belongs” to the `DemoPackage` module. But if every file now has to be a module, I have to arbitrarily pick a submodule to “own” `foo`, and then I have to import `foo` from my arbitrarily chosen submodule every time that I want to extend it.

Below is a runnable example of what this would look like, using the current module system with nested modules. I think it would look basically the same if the nested modules in the example were separate files with the file-module correspondence enforced.

```julia
module DemoPackage
       
	module A
		struct S end
		foo(::S) = 1
	end
	
	module B
		import ..A: foo
		struct T end
		foo(::T) = 2
	end
	
	module C
		import ..A: foo
		struct U end
		foo(::U) = 3
	end
	
	import .A: S
	import .B: T
	import .C: foo, U
	export foo, S, T, U
	
end

```

```julia
julia> using .DemoPackage

julia> methods(foo)
# 3 methods for generic function "foo":
[1] foo(::S) in Main.DemoPackage.A at REPL[1]:8
[2] foo(::T) in Main.DemoPackage.B at REPL[1]:14
[3] foo(::U) in Main.DemoPackage.C at REPL[1]:20

```

Note how I arbitrarily picked module `A` to “own” `foo`. But in reality, none of the modules really owns `foo`—it is a generic function who’s full definition spans multiple modules. There are other arbitrary choices I had to make here:

- In module `C`, I could have done `import ..B: foo` instead of `import ..A: foo`, because, now `B` “owns” `foo` just as much as `A` does!
- In the third to last line, I could have done either `import ..A: foo`, `import ..B: foo`, or `import ..C: foo`. It’s an arbitrary choice, because they all refer to the _same generic function_.

To make matters worse, I’ve actually introduced an artificial code dependency that wouldn’t have existed otherwise. Look what happens if I transpose the definition of module `B` above the definition of module `A`:

> **DemoPackage module with order of A and B flipped**
>
> ```julia
> module DemoPackage
>        
> module B
> import ..A: foo
> struct T end
> foo(::T) = 2
> end	
> 
> module A
> struct S end
> foo(::S) = 1
> end
> 	
> module C
> import ..A: foo
> struct U end
> foo(::U) = 3
> end
> 	
> import .A: S
> import .B: T
> import .C: foo, U
> export foo, S, T, U
> 	
> end
> 
> ```

If I run the new `DemoPackage` with the order of `A` and `B` flipped, I get `ERROR: UndefVarError: A not defined`. You might say, “That’s exactly how it’s supposed to work. The code dependency has been enforced.” But the point is, there should not be a code dependency here, because I can define methods in any order I want! I could have done the following, where I can flip the order of defining `foo(::S)`, `foo(::T)`, and `foo(::U)` to my heart’s content:

```julia
module DemoPackage

    struct U end
    struct T end
    struct S end

    foo(::U) = 3
    foo(::T) = 2
    foo(::S) = 1

    export foo, S, T, U

end

```

To summarize:

- Using the same generic function across multiple submodules requires arbitrary import choices and introduces artificial and unnecessary code dependencies.
- You can’t really encapsulate a generic function inside a module, because the generic function is defined by its _global_ method table.

---

_[View the full topic](https://discourse.julialang.org/t/implicitly-loaded-modules-in-the-future/62646)._
