Difference between `include` and `using`

When using Oxygen.jl, I noticed an unexpected difference between using and include. I created a simple project using a slightly modified version of the example code in the readme.

(@v1.8) pkg> generate OxygenExample
  Generating  project OxygenExample:
    OxygenExample/Project.toml
    OxygenExample/src/OxygenExample.jl

shell> cd OxygenExample/
/tmp/OxygenExample

(@v1.8) pkg> activate .
  Activating project at `/tmp/OxygenExample`

(OxygenExample) pkg> add Oxygen HTTP
<snip>
Precompiling project...
  6 dependencies successfully precompiled in 6 seconds. 15 already precompiled.

src/OxygenExample.jl

module OxygenExample
using Oxygen
using HTTP

@get "/greet" function(req::HTTP.Request)
    return "hello world!"
end

function runserver()
    serve()
end

end # module OxygenExample

This doesn’t work, when I fetch /greet, I always get a 404:

julia> using OxygenExample

julia> OxygenExample.serve(port=8000)
   ____
  / __ \_  ____  ______ ____  ____
 / / / / |/_/ / / / __ `/ _ \/ __ \
/ /_/ />  </ /_/ / /_/ /  __/ / / /
\____/_/|_|\__, /\__, /\___/_/ /_/
          /____//____/

[ Info: ✅ Started server: http://127.0.0.1:8000
[ Info: 📖 Documentation: http://127.0.0.1:8000/docs
[ Info: 2022-09-25T17:00:47-0700 - 127.0.0.1:45300 - "GET /greet HTTP/1.1" 404
[ Info: 2022-09-25T17:00:48-0700 - 127.0.0.1:45300 - "GET /favicon.ico HTTP/1.1" 404

But after starting a new session julia --project in the project directory, this does work:

julia> include("src/OxygenExample.jl")
Main.OxygenExample

julia> using .OxygenExample

julia> OxygenExample.serve(port=8000)
   ____
  / __ \_  ____  ______ ____  ____
 / / / / |/_/ / / / __ `/ _ \/ __ \
/ /_/ />  </ /_/ / /_/ /  __/ / / /
\____/_/|_|\__, /\__, /\___/_/ /_/
          /____//____/

[ Info: ✅ Started server: http://127.0.0.1:8000
[ Info: 📖 Documentation: http://127.0.0.1:8000/docs
[ Info: 2022-09-25T17:07:57-0700 - 127.0.0.1:35256 - "GET /greet HTTP/1.1" 200

Why is the include necessary? What happened here?

When you use add you are adding a snapshot of the package at the time you did that. The alternative is to use dev which will load whatever is currently located there.

You should generally not use include outside of a package module. You lose most of the benefits of a package such as precompilation caching.

Yeah, that is one of many reasons this example bothers me. It only works with the include.

This should be julia --project=. if you are in the directory. Is that what you did?

If you have an existing environment in the folder --project seems to do the same thing as --project=. for me at least. Though if there isn’t any it activates the default. So in this case it seems like there should definitely be an environment so I don’t think that would be the reason.

With that said I get the same results as OP, not really sure why this is happening.

I misunderstood the problem, but I see what the issue is now.

In your example above, you invoked @get at the top level of the module OxygenExample. The problem is that this is only executed during precompilation. It is not executed when loading the module via using OxygenExample.

To have it execute when loading the module, move the code into __init__:

module OxygenExample
using Oxygen
using HTTP

function __init__()
    @get "/greet" function(req::HTTP.Request)
        return "hello world!"
    end
end

function runserver()
    serve()
end

end # module OxygenExample
1 Like

That makes sense, thank you.

I agree this is a bit weird and under documented. I created an Oxygen.jl issue: