print and println@printftry-catch for Exception HandlingfinallyWhen code is organized into modules, managing how other parts of a program, or even other programs, access the functions, types, and variables defined within them is essential. Julia provides three primary keywords—export, using, and import—to control this visibility and access. Understanding these is fundamental to building larger, maintainable Julia applications.
exportBy default, everything defined inside a module is private to that module. This means you can't directly use a function or variable from a module in your main script or another module just by knowing its name. To make specific items from your module available to the outside, you use the export keyword.
Think of export as declaring the public interface of your module. You list the names of functions, variables, types, or even other modules that you want to make accessible.
Here’s how you use export inside a module:
# File: StringUtilities.jl
module StringUtilities
export capitalize_string, count_occurrences
# This function will be part of the public API
function capitalize_string(s::String)
return uppercasefirst(s)
end
# This variable will also be public
DEFAULT_GREETING = "Hello"
# This function is also public
function count_occurrences(text::String, pattern::String)
return count(pattern, text)
end
# This function is internal to the module, not exported
function internal_helper_function()
println("This is an internal helper, not meant for direct external use.")
end
end # module StringUtilities
In this StringUtilities module, capitalize_string and count_occurrences are explicitly exported. DEFAULT_GREETING is not exported in this example, and internal_helper_function is also not exported, making it an internal implementation detail. If we wanted DEFAULT_GREETING to be public, we would add it to the export list: export capitalize_string, count_occurrences, DEFAULT_GREETING.
using and importNow that StringUtilities has exported some of its members, how do we use them in another script or in the Julia REPL? This is where using and import come into play.
using KeywordThe using ModuleName statement brings all exported names from ModuleName into the current scope. This means you can call the exported functions or use the exported variables directly by their names, without prefixing them with the module name.
Let's assume StringUtilities.jl is in a location where Julia can find it (e.g., the same directory, or you've used include("StringUtilities.jl")):
# main_script.jl
include("StringUtilities.jl") # Make the module definition known
using .StringUtilities # The dot indicates a module in the current scope or a submodule
s = "julia programming"
capitalized = capitalize_string(s) # Directly accessible
println(capitalized) # Output: Julia programming
occurrences = count_occurrences(s, "a") # Directly accessible
println("Found 'a' $occurrences times.") # Output: Found 'a' 2 times.
# DEFAULT_GREETING is not exported, so this would cause an error:
# println(DEFAULT_GREETING) # ERROR: UndefVarError: DEFAULT_GREETING not defined
# internal_helper_function is not exported, so this would also cause an error:
# internal_helper_function() # ERROR: UndefVarError: internal_helper_function not defined
When to use using:
using is very convenient when you plan to use many functions from a module, and their names are unlikely to clash with names already in your current scope. For example, using Plots is common because you'll use many plotting functions.
A potential downside is "namespace pollution." If your current scope already has a function named capitalize_string, and you using StringUtilities, Julia will issue a warning, and the newly imported capitalize_string will replace the existing one for subsequent calls.
import KeywordThe import keyword offers more control over what names are brought into scope and how.
import ModuleName:
This form brings only the module name itself into the current scope. To access any members of the module (exported or not), you must qualify them with the module name followed by a dot (.).
# main_script_import.jl
include("StringUtilities.jl")
import .StringUtilities
s = "julia programming"
# Must use qualified name for exported functions:
capitalized = StringUtilities.capitalize_string(s)
println(capitalized) # Output: Julia programming
occurrences = StringUtilities.count_occurrences(s, "a")
println("Found 'a' $occurrences times.") # Output: Found 'a' 2 times.
# You can even access non-exported names if you qualify them:
# StringUtilities.internal_helper_function() # This would call the internal function
# Note: Accessing non-exported members is generally discouraged for external modules
# as they are considered internal implementation details that might change.
When to use import ModuleName: This is the safest option to avoid name conflicts. It makes it very clear where each function or variable comes from. It's often preferred in larger projects or when using modules with very generic names.
import ModuleName: name1, name2, ...:
This form allows you to selectively bring specific names from ModuleName into the current scope. These names can then be used directly, just like with using. A main difference from using is that you explicitly list what you want. This can also be used to bring non-exported names into scope if needed, for instance, for testing or specific integrations.
# main_script_import_specific.jl
include("StringUtilities.jl")
import .StringUtilities: capitalize_string # Only bring capitalize_string into scope
s = "julia programming"
capitalized = capitalize_string(s) # Directly accessible
println(capitalized) # Output: Julia programming
# count_occurrences was not imported directly, so it needs qualification:
# occurrences = count_occurrences(s, "a") # ERROR: UndefVarError: count_occurrences not defined
# It can be accessed via the module if the module itself is also known (e.g., via a previous `import .StringUtilities` or implicitly):
occurrences = StringUtilities.count_occurrences(s, "a")
println("Found 'a' $occurrences times.") # Output: Found 'a' 2 times.
If you only did import .StringUtilities: capitalize_string, then StringUtilities itself is not brought into scope as a name. If you want both capitalize_string directly and be able to use StringUtilities.count_occurrences, you can do:
import .StringUtilities # Makes StringUtilities.name accessible
import .StringUtilities: capitalize_string # Makes capitalize_string directly accessible
Or, more commonly, if you only need a few names directly:
import .StringUtilities: capitalize_string, count_occurrences
# Now both are directly accessible.
When to use import ModuleName: name1, name2: This is a good balance between convenience and explicitness. You get direct access to frequently used names while avoiding bringing in everything. It's also the standard way to prepare for extending functions from another module (adding new methods), a more advanced topic.
Regardless of whether you've used using or import, you can always refer to an exported member of a module using its fully qualified name: ModuleName.memberName. If the module is a submodule, it would be ParentModule.SubModule.memberName.
This is particularly useful:
using export the same name.For example, if you had using ModuleA and using ModuleB, and both export a function foo(), you would get a warning. To call ModuleA's version, you'd write ModuleA.foo().
The following diagram illustrates how export in a module definition relates to the using and import statements and their effect on how you access module members.
How
exportin a module definition works withusingandimportstatements to control access to module members.
LinearAlgebra, Dates): using ModuleName is often fine for convenience.import ModuleName (and using qualified names like ModuleName.func) is safer and clearer.import ModuleName: name1, name2 provides a good balance.By mastering export, using, and import, you gain precise control over your code's structure and how its components interact, which is essential for writing clear, maintainable, and scalable Julia programs. As you start working with external packages, you'll see these mechanisms used extensively.
Was this section helpful?
export, using, and import keywords, and their role in code organization.export, using, and import for beginners.© 2026 ApX Machine LearningEngineered with