# How to write an \`include\_once\` function?

**URL:** <https://discourse.julialang.org/t/how-to-write-an-include-once-function/123496>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [December 5, 2024, 12:47pm UTC](https://discourse.julialang.org/t/how-to-write-an-include-once-function/123496 "2024-12-05T12:47:26Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [December 5, 2024, 12:47pm UTC](https://discourse.julialang.org/t/how-to-write-an-include-once-function/123496/1 "2024-12-05T12:47:27Z")

</div>

Closely related to this recent post:

- [Using or import search current directory?](https://discourse.julialang.org/t/using-or-import-search-current-directory/123463)

Is it possible to write an `include_once` function, which calls `include`, but only once.

```julia-auto
function include_once(path)
    if not run before
        include(path)
    end
end

```

I’m not sure how to approach the issue of writing in the `if` statement logic. Is there a way to detect if `include` has been called with a particular path before?

I suspect this is tricky to do. I don’t think there is any mechanism to query if a module has a name defined within a file, because finding names in files would require loading them (`include`ing them) first.

Possibly some boolean state could be injected into the `include_once` function? Or a global dict could be used to track which paths have been loaded from which modules?

Just some initial ideas…

#### Edit:

I tried to come up with something and came up with this, which seems to work. But I’m not sure I am really doing this in the best way. This feels like something a macro could be useful for?

```julia-auto
function include_once(target_module, path)

    global g_include_once_dict

    if ! (@isdefined g_include_once_dict)
        g_include_once_dict = Dict()
    end

    key = (target_module, path)
    if !haskey(g_include_once_dict, key)
        println("include: $(target_module) $(path)")
        g_include_once_dict[key] = true
        include(path)
    end
end

```

Intended use is something like this

```julia-auto
include_once(@ __MODULE__ , "test.jl")

```

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [December 5, 2024, 3:03pm UTC](https://discourse.julialang.org/t/how-to-write-an-include-once-function/123496/2 "2024-12-05T15:03:51Z")

</div>

You might find some ideas in [FromFile](https://github.com/Roger-luo/FromFile.jl)

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 5, 2024, 7:44pm UTC](https://discourse.julialang.org/t/how-to-write-an-include-once-function/123496/3 "2024-12-05T19:44:58Z")

</div>

> [@world-peace](#):
>
> I’m not sure how to approach the issue of writing in the `if` statement logic. Is there a way to detect if `include` has been called with a particular path before?

Just keep a `Set` of previously included paths?

```julia
let previous_includes = Set{String}()
    global include_once
    function include_once(path::AbstractString)
        if !in!(abspath(path), previous_includes)
          include(path)
        end
        return nothing
    end
end

```

(I used `let` here so that the `Set` is a local variable, rather than being global.)

However, since this should be module-specific, it should **probably be a macro** instead of a function so that it can expand to an `include` in the _caller_ module (rather than in the module where `include_once` is defined) and use `@ __MODULE__ ` to determine the caller module for the `Set{Tuple{Module,String}}`. (FromFile.jl also uses macros.) For example:

```julia
const _included_once = Set{Tuple{Module,String}}()
macro include_once(path)
    quote
        path = $(esc(path))
        if !in!((@ __MODULE__ , abspath(path)), _included_once)
          include(path)
        end
        nothing
    end
end

```

which you can then call as `@include_once(somepath)`.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [December 6, 2024, 12:46am UTC](https://discourse.julialang.org/t/how-to-write-an-include-once-function/123496/4 "2024-12-06T00:46:01Z")

</div>

> [@stevengj](#):
>
> so that it can expand to an `include` in the _caller_ module (rather than in the module where `include_once` is defined)

Considering the linked post about imported modules, I think this is the opposite of what OP wants. The typical “include once, import repeatedly” approach works if you have a good place to order your `include` calls for the imports to work consistently, like a `PackageC.jl` in a `PackageC` directory. `include_once` seems intended to be paired with import statements to mimick how packages are loaded once upon first import because there _isn’t_ a good place to put `include` calls (I’ll leave whether such a place should be made or the soundness of the intents to the other post). In that case, you _don’t_ want the modules with the import statements to contain the imported modules, it changes the dots you write in the import statements depending on which module happened to load a shared module first. Instead, the modules need to be evaluated into a consistent module, like how packages are organized into an environment. I’m not sure what that consistent module should be, I think `Main` always exists.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 6, 2024, 12:54am UTC](https://discourse.julialang.org/t/how-to-write-an-include-once-function/123496/5 "2024-12-06T00:54:16Z")

</div>

> [@Benny](#):
>
> I think this is the opposite of what OP wants.

I think I was solving the problem as specified in this thread — @world-peace used `include_once(@ __MODULE__ , path)` above — why would it be once per `@ __MODULE__ ` (i.e. the caller’s module) if you don’t want to include into the caller’s namespace?

But then they called `include` in their `include_once` function, which is inconsistent (and I suspect that it was simply an error) — this will call the `include` for the module where `include_once` is defined, which is _not_ necessarily the caller’s module.

That’s why I used a macro.

> [@Benny](#):
>
> Instead, the modules need to be evaluated into a consistent module, like how packages are kept in an environment. I’m not sure what that consistent module should be, I think `Main` always exists.

I agree that it is generally better to include files only once, into a single “parent” module, and then refer to that module’s namespace elsewhere. (You should not generally be including into `Main`, however — this top-level module doesn’t belong to your package, it belongs to interactive users or scripts!)

If you want to specify fixed parent module to do the including, you could have a function with a `parentmodule` argument and call `parentmodule.include` _instead_ of `include`.

But if you are doing that, why not just include the files directly from the parent module in the first place, instead of including them obliquely from some submodule? (Which is, of course, what one normally does in Julia packages.)

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [December 6, 2024, 11:26pm UTC](https://discourse.julialang.org/t/how-to-write-an-include-once-function/123496/6 "2024-12-06T23:26:15Z")

</div>

> [@stevengj](#):
>
> You should not generally be including into `Main`, however — this top-level module doesn’t belong to your package, it belongs to interactive users or scripts!

Yeah, I stand corrected there. Maybe the module containing `include_once` then? A macro could make that import statement easier to write, too.

> [@stevengj](#):
>
> But if you are doing that, why not just include the files directly from the parent module in the first place

It sounds like there isn’t a designated parent module, hence the need for import statements to load a module’s code if it isn’t present in a cache (`sys.modules` in Python). That said, I’m also just guessing at what OP wants to accomplish, you also seem to find the intent unclear in the linked thread.
