Scope Issues of Exported Functions in Module

Probably a basic question and answer I am searching for here, but I am trying to get into package development and it has been quite difficult. This time around, I have made much more progress, but just ran into issues with running Test which is baffling me. More than likely comes down to my confusion about scopes and making sure I’ve loaded the proper environments.

I have a module that I want to create, called FinancialAccounting. I do an include("loans.jl"), and inside loans.jl we have a simple function saying hello, and another outputting a number.

In my test file, I have a testset looking for the return of the “hello” function, as well as the number. The what_is_x and hello_package functions appear, so I think I am loading the module properly. The problem I have, is that when I type into the REPL FinancialAccounting.hello_package() it returns the correct phrase, but is T{Nothing}. When I just straight up enter hello_package() into the same REPL, it returns the proper phrase, and is T{String}. This disconnect is causing issues in the test statements and I don’t know how to fix them.

Module File:

module FinancialAccounting

export hello_package, what_is_x

include("loans.jl")

end

Included File:

function hello_package()
        println("Hello FinancialAccounting!")
end

function what_is_x()
    2
end

runtests.jl

using FinancialAccounting
using Test

@testset "FinancialAccounting.jl" begin
    @test FinancialAccounting.hello_package() == "Hello FinancialAccounting!"
    @test FinancialAccounting.what_is_x() == 2
    @test FinancialAccounting.hello_package() != "Hello World!"
end

Hello and welcome to the community :wave:

The problem might be that the hello_package function doesn’t actually return a string, it prints a string. The function println does not return anything.

julia> a = println("hej")
hej

julia> typeof(a)
Nothing

so you can never test this function this way

@test FinancialAccounting.hello_package() == "Hello FinancialAccounting!"

You might be confused because a function that returns a string to the REPL will also cause the string to be printed, similar to if the string had been printed using println?

What is the T you are writing about? I cannot see it appearing in your code.

2 Likes

It’s printed visibly different, though:

julia> (() -> "hello")()
"hello"

julia> (() -> println("hello"))()
hello

julia> (() -> begin println("hello"); "world" end)()
hello
"world"

Assuming that you’re typeofing the returned value consistently, then this would indicate the two functions are in fact different. Check FinancialAccounting.hello_package === hello_package. If true, then you evaluated a separate function somewhere else that behaves differently.

1 Like

T{String} was just how I thought the notation was for denoting “type = String”, my mistake. I think it’s something slightly different according to the core/base docs.

I didn’t know that println returns a ::Nothing object, that’s interesting…

Here’s what I tried running, within the runtests.jl and after starting a fresh terminal/REPL instance. I’m starting to think this may be an issue/change in the Julia version, because I am following the official walkthrough for package creation and this is where I got all the example tests (How to develop a Julia package).

The comparison they use with the println and the true ::String might be incorrect now.

I believe everything in the module is working though. I can access my custom Loan struct, as well as the other functions and attributes from loans.jl, so I think my exporting is correct. I appreciate the help!

julia> names(Main)
5-element Vector{Symbol}:
 :Base
 :Core
 :InteractiveUtils
 :Main
 :ans

julia> @__MODULE__
Main

julia> FinancialAccounting.
Loan                  amortization          amortization_periods  eval                  hello_package
include               what_is_x
julia> typeof(FinancialAccounting.hello_package())
Hello FinancialAccounting!
Nothing

julia> typeof(hello_package())
Hello FinancialAccounting!
Nothing

julia> hello_package() === FinancialAccounting.hello_package()
Hello FinancialAccounting!
Hello FinancialAccounting!
true

I doubt it’s a version change, println should return nothing even 4 years ago. That is either a test doomed to fail or a typo (probably the case).

Good that’s all consistent now.

1 Like

@ChrisRackauckas, your turorial needs fixing.

The following tests will fail.

using YourPackageName
using Test

@testset "YourPackageName.jl" begin
    @test YourPackageName.greet_your_package_name() == "Hello YourPackageName!"
    @test YourPackageName.greet_your_package_name() != "Hello world!"
end

With the stated definition.

function greet_your_package_name()
    println("Hello YourPackageName!")
end

What tutorial? I’m lost and don’t recall writing an example like this.

Hmm. Maybe this is not actually you:

Yeah I don’t know who wrote that, but anyways you’d put a PR to GitHub - JuliaLang/www.julialang.org: Julia Project website to get it fixed.