Dive into import statements with Solidity
Modules and Code Modularity.Solidity Imports.Forms of Solidity Import Syntax.
* World Import
* Particular ImportsImport Aliases.
* World Alias
* Alias ParticularWhich import syntax to make use of?What are you able to import from a Solidity file?Solidity Import Syntax Cheatsheet
Earlier than diving into Import statements in Solidity, let’s first perceive modular programming. The idea of modules may be very previous. It first appeared 44 years in the past with the programming languages Modula-2 and Pascal.
The concept behind modules is to interrupt code into reusable parts. You group functionalities in a module file and expose them to different information in order that these different information can use them.
A module system helps organise your code by grouping variables and features that make sense collectively in a single single file.
Let’s take the instance of modules in Javascript (ES6). In ES6, modules are information that export a number of values (objects, features or variables). Then, every other Javascript module can use the performance supplied by this file by importing it (Copes, 2018).
The concept of importing information in Solidity is similar to the idea of modules described above. It helps modularise your sensible contracts by:
- Creating reusable items that different information can import.
- Making it simpler to grasp and digest your entire Solidity codebase of your challenge.
- Making it simpler to work with the “Solidity modules” by specializing in smaller information (helpful when debugging).
You’ll be able to group and outline variables (like fixed
, enum
, struct
outlined on the file degree) and different Solidity objects (like contract
, interface
or library
) right into a single file. Solely as soon as. And you may then import them and use them in different Solidity information utilizing the import
syntax.
The one distinction with different programming languages like Javascript or C++ is that you don’t want to instantly (explicitly) outline these variables or Solidity objects with an export
key phrase.
NB: notice that Solidity doesn’t help default exports.
Let’s have a look at an import
assertion in Solidity, impressed by the ES6 import syntax and similar to the Python import syntax too (from X import *
).
import “./MySolidityFile.sol”;
The code snippet above reveals the basic and most generally used import syntax throughout most open-source Solidity projects. Right here, “./MySolidityFile.sol”
is a path pointing to the file we need to import. This path is relative, that means primarily based on the place we’re importing from (= the present file).
World Imports
The assertion beneath will import all Solidity objects present in “./MySolidityFile.sol”
import “./MySolidityFile.sol”;
I exploit the time period “Solidity object” to explain any contract
, library
, interface
, or different fixed
or variables that you would be able to outline on the file degree (struct
, enum
, and so forth.)
NB: this is able to be the equal of
import * from “./MySolidityFile.sol”
in ES6, however Solidity doesn’t permit this syntax.
When the Solidity compiler encounters this assertion, two issues occur.
- All world symbols (what I name “Solidity Objects”) outlined in
“./MySolidityFile.sol”
get imported into the present world scope. - All world symbols imported inside
“./MySolidityFile.sol”
get additionally imported into the present world scope.
That is very totally different from ES6! In ES6, if you import a module, you import what’s outlined inside this module, not every part else imported inside this module.
Let’s take a short instance to grasp.
The primary line contained in the file “GPS.sol”
imports the three tackle
constants outlined in “Endpoints.sol”
. The file “CarGPS.sol”
can then use them, even tho it doesn’t import the file “Endpoint.sol”
instantly.
In Solidity, every part imported inside a file A will get subsequently accessible (imported) in different information that import A.
Here’s a sensible instance to higher perceive how these subsequent imports work. If I remark out the road import “./Endpoints.sol”;
inside “GPS.sol”
, the compiler doesn’t discover the constants anymore.



The issue with this world import syntax is that even when the fixed SIGNAL_TOWER_A
is imported in “GPS.sol”
file, it’s exhausting to know that it comes from “./Endpoint.sol”
. A small replace on the import definitions in “./GPS.sol”
would break it and make it cease compiling.
This world import syntax isn’t really helpful, because it makes it exhausting to grasp the place modules come from or the place modules are outlined.
It’s even talked about within the Solidity docs:
“This type isn’t really helpful to be used as a result of it unpredictably pollutes the namespace.”
When you add new top-level objects inside “filename”, they mechanically seem in all information that import like this from “filename”.
As an alternative, the Solidity docs suggest specifying imported symbols explicitly.
Particular Imports
Particular imports are nearer to the ES6 syntax. You might be extra particular and import what you want from a Solidity file.
Import One thing from “./MySolidityFile.sol”;
You’ll be able to then point out inside the curly braces
the particular symbols/objects that you just need to import and use. As an illustration, if the file specified within the import path accommodates a number of contract
, you possibly can decide which contracts you want to import precisely with this syntax.
Let’s have a look at the next instance from Solmate, a sensible contract library underneath growth that can be utilized to construct fashionable and gasoline optimised contracts.
Take a particular have a look at the RoleAuthority.sol
contract. It defines the next import assertion.

As you possibly can see from above, specifying contracts or different symbols inside curly braces helps find them.
The Auth contract is simpler to find, because it has the identical identify because the filename “Auth.sol”.
However for Authority
(which, regardless of the identify, is an interface
), one wouldn’t have discovered it if the import assertion was Import “../Auth.sol”
.
The import syntax with curly braces helps find the place the constructing blocks that make your sensible contracts (summary contract
, interface
, library
, and so forth.) come from and which information they’re truly outlined.
Let’s re-write our code pattern above from the “World Imports” part.
Our code refactoring added an additional import line that helps to find the place the fixed SIGNAL_TOWER_A
come from (as a substitute of “burying it”).
Our Solidity code can also be cleaner in one other approach which may not be noticeable: the struct Level
. We had been importing it beforehand with world import however not utilizing it. The Level
struct “polluted the supply code” with an pointless object we weren’t utilizing as a result of we didn’t want it. This was breaking the rule of modularity and modular programming:
“solely import what you want”
Particular imports with curly braces permit us to use this rule higher.
Import aliases are very previous in Solidity and date again to the release version 0.2.1. Import aliases can be utilized for each varieties of imports:
- Aliases for world imports: can then be used to discuss with particular objects outlined within the file, utilizing the dot “.” syntax (like object properties).
- Aliases for particular imports: allow to rename objects or symbols imported from a Solidity file, as an illustration, to keep away from naming collision (or to present higher identify for higher code readability if wanted).
World Aliases
A world alias containing every part outlined within the imported file might be created utilizing the wildcard operator *
coupled with an alias as
.
Within the code snippets beneath, a brand new world image Endpoints
is created and turns into accessible within the file’s context.
// longer syntax
import * as Endpoints from “./Endpoints.sol”.// shorter syntax
import “./Endpoints.sol” as Endpoints;
NB: Be aware that the second assertion (various syntax) has no equal in ES6. In ES6 modules, you possibly can create module alias utilizing the first syntax, however the 2nd syntax doesn’t exist.
All of the symbols and objects outlined in “./Endpoints.sol”
(in addition to imported in “./Endpoints.sol”
) at the moment are accessible within the format Endpoints.TOWER_ADDRESS_A.
They’re now members of this world image and might be accessed such as you entry properties of a JavaScript object (or discuss with the members of a Struct in Solidity) utilizing the dot notation.
Particular Aliases
When you use particular imports lined earlier than to import solely what you want in your Solidity file, you can too give an alias identify to what you might be importing.
import Level as Coordinate, GPS from “./Endpoints.sol”;
Within the import assertion above, the GPS library is imported as it’s, whereas the struct Level
can also be imported however renamed Coordinates
. The Solidity import assertion creates a brand new image Coordinates
that refers back to the struct Level
.
Such aliases are helpful in two instances:
- Keep away from naming collisions: in instances the place what you need to import is already imported by different information. When you encounter naming collisions whereas importing, use aliases to resolve this.
- Stop sudden behaviour (if the compiler didn’t flag it, and a variable you might be utilizing references the incorrect variable imported from elsewhere).
- Rename what you might be importing: if you wish to use extra significant names in your context and in your code readability.
Here’s a quote from the SonarSource documentation relating to imports.
“On the precept that clearer code is healthier code, you must import the belongings you need to use in a module.”
You’ll be able to apply this precept to sensible contracts in Solidity. Though most open-source Solidity initiatives with supply code accessible on Github use the import ” ./File.sol”
syntax, this doesn’t comply with the perfect observe talked about by SonarSource.
The PEP8 docs additionally discourage world imports in Python.
“Wildcard imports (from <module> import *) needs to be prevented, as they make it unclear which names are current within the namespace, complicated each readers and lots of automated instruments.”
The principle cause for this subject is that as talked about within the World Imports part, import “./MySolidityFile.sol”
imports every part from the Solidity file (talked about within the path) → to the Solidity file (the place the import assertion is asserted).
I bought used to this Soldity world import syntax over time. Nonetheless, I’ve now concluded that importing every part from a Solidity file can result in a number of points. These fall into two important classes: Readability and Bugs associated to the namespace.
Readability
- Runs the danger of complicated the maintainers and customers of Solidity contract or library.
- Reduces code readability. Builders utilizing your Solidity contracts or library can have issue figuring out the place the imported names come from.
Bugs associated to namespace
- Importing every part clutters the native “namespace”, making debugging tougher.
- Imported names can change if you replace your dependencies. Due to this fact, a wildcard import that works as we speak may be damaged tomorrow.
There are two methods to keep away from a wildcard import:
– Substitute it with import mySolidityModule
and entry module members as mySolidityModule.MyContract
.
– Checklist each imported identify. If obligatory, import statements might be break up into a number of strains utilizing parentheses (most well-liked answer) or backslashes.
Analogy: importing every part is the equal of two mechanics in a storage repairing a automotive, the place one the mechanics ask the opposite, “give me an Allen key” and the opposite mechanic brings him your entire toolbox, as a substitute of taking the Allen key out of the toolbox and hand it to him.
Consider this analogy such as you and the Solidity compiler. You need to make issues simple for the compiler by offering exactly the code wanted for the compiler to do its finest job at compiling the contracts into bytecode. You don’t need to litter the compiler with code that’s not required, like “making it search by way of your entire toolbox”.
You’ll be able to import the next components in a Solidity file.
contract
library
interface
enum
(outlined on the file degree)struct
(outlined on the file degree)error
definitions (outlined on the file degree)perform
s (outlined on the file degree, since Solidity 0.7.1)- User-defined Value Types (since their introduction in Solidity 0.8.8)
Beneath is a abstract of the totally different import statements accessible in Solidity. I wrote these examples primarily based on those supplied within the Javascript ES6 docs about import statements.
For readability, simplicity, and to make it as shut because the ES6 docs, I name a “Solidity module” a Solidity file that accommodates totally different objects/symbols outlined above within the part “What are you able to import from a Solidity file?”.
Import a whole Solidity module content material.
That is the most typical syntax on the market. I feel this syntax needs to be prevented when doable, because it imports every part with out figuring out what’s being imported. This reply from Ethereum StackExchange (referencing PEP8 type docs on the identical subject) mentions that it clutters and “pollute the namespace”.
import "./modules/MySolidityFile.sol";
Import a whole Solidity module content material and assign it a worldwide alias.
A special syntax to import every part. What’s outlined in MySolidityFile.sol, can then be referenced by way of mySolidityModule.MyContract
, mySolidityModule.MyLibrary
or mySolidityModule.MyStruct
.
import * as mySolidityModule from "./modules/MySolidityFile.sol";
This second syntax is a barely shorter model.
import "./modules/MySolidityFile.sol" as mySolidityModule;
Import a single export from a Solidity module
import MyContract from "./modules/MySolidityFile.sol";
Import a number of exports from a module
import
MyContract,
MyLibrary,
MyStruct,
customFunction
from "./modules/MySolidityFile.sol";
Import export with a extra handy alias
import
reallyReallyLongSolidityModuleExportName as solidityModule
from "./modules/MySolidityFile.sol";
Rename a number of exports throughout import
import
reallyReallyLongSolidityModuleExportName as solidityModule,
anotherLongSolidityStructName as MyStruct
from "/modules/my-module.js";