Import vs Import and inherit

It occurred ot me today that there is something about imports I don’t quite get.

What is the practical difference between:

  1. simply importing a contract in the head of your sol file, versus

  2. importing that contract AND ALSO using the ‘is’ keyword referring to that contract in your contract declaration

And follow up questions 3 and 4 would be the same as above, but if it was an interface instead of a contract you were importing.

2 Likes

Hi @CryptoEatsTheWorld,

Importing imports all the global symbols from the file being imported into the current global scope.

See the Solidity documentation for details on imports:
https://docs.soliditylang.org/en/v0.7.5/layout-of-source-files.html#importing-other-source-files

An example of importing where you are not inheriting is using utilities such as SafeMath or Counters:

is means that your contract inherits from another contract.
contract MyToken is ERC20 means that your token inherits from the OpenZeppelin Contracts ERC20 implementation.

See the Solidity documentation for details on inheritance:
https://docs.soliditylang.org/en/v0.7.5/contracts.html#inheritance

Also see the OpenZeppelin Contracts documentation on extending:

An example of importing where you are inheriting is extending from ERC20Burnable and ERC20Pausable:

  1. simply importing an interface in the head of your sol file, versus

Importing an interface would allow you to declare variables of an interface type to interact with contracts using the interface.

See the Solidity documentation for details on interfaces:
https://docs.soliditylang.org/en/v0.7.5/contracts.html#interfaces

An example of importing an interface where you are not inheriting is using IERC20 to interact with an ERC20 contract:

  1. importing that interface AND ALSO using the ‘is’ keyword referring to that interface in your contract declaration

Importing and inheriting from an interface is just like inheriting from any other contract. Just like an abstract contract you would need to implement the functions defined in the interface.

An example of importing and inheriting from an interface is inheriting from IERC20:

2 Likes

Hi @CryptoEatsTheWorld,

Did you need any more information?

No, thanks for the info.

1 Like

Actually I do… I am honestly screwed up and Confused between Libraries, Interfaces and Imports

1 Like

@Suveett An interface is like a blueprint for a contract. It says what functions there are and what parameters they take but does not say what they actually do. If your contract inherits from an interface, the compiler will make sure that you do not forget to provide implementations for all its functions and that you do not change their signatures.

You can also use an interface to tell the compiler that a contract deployed at a particular address provides a particular set of functions. This way the compiler can know how to encode parameters for an external call without having access to the whole source code of the contract you’re calling.

One thing you did not mention but might be interested in are abstract contracts. You can think of them as a mix between a contract an an interface. They can have both unimplemented functions (like interfaces) and implemented ones (like contracts). The use case is usually different though. You’d typically create an abstract contract if you wanted to create an “incomplete” contract that cannot be deployed on its own and where the one inheriting from it has to fill the gaps. That’s usually better than creating a contract with empty function stubs because the compiler can check if all the right functions have been provided by the inheriting contract.

A library is just a special kind of contract. It has two uses:

  • Grouping internal utility functions. Any contract can access a library and all the internal library functions it calls become a part of its own bytecode. This is similar to free functions.
  • Splitting larger contracts into smaller pieces. Calling public and external library functions results in a DELEGATECALL - an external call that also gives the library access to contract’s storage (library functions can take storage parameters). I think this is used much less in practice due to the cost of DELEGATECALL and more complicated deployment (you need to deploy the library first and then tell the compiler to link in the address).

Imports are just… imports. If you have used any other language you’re probably familiar with imports/includes/requires/etc. They tell the compiler to make stuff defined in another file visible in the current file. Please read the docs linked above, they explain all of this in much more detail.

3 Likes

Splitting larger contracts into smaller pieces. Calling public and external library functions results in aDELEGATECALL- an external call that also gives the library access to contract’s storage (library functions can takestorageparameters). I think this is used much less in practice due to the cost ofDELEGATECALL and more complicated deployment (you need to deploy the library first and then tell the compiler to link in the address).

Since we can just Import a Library(and hence access to its public/external functions and also the Library functions have power to compute and affect caller contract’s storage), OR we can just Import the Interface (with external unimplemented functions which need to be implemented but they don’t access storage of caller contract) then why do we in fact even need abstract contracts?, because all functionalities are already catered with Libraries and Interfaces, or is it not ??

If i Understand correctly, abstract contracts basically are to build small modularise contracts (Splitting larger contracts into smaller pieces), with extended functionalities and usage/access via “Internal functions” ?

So the difference is basically Internality and Externality, right ?? Am I understanding it correctly ??

& ALSO, if I understand it correctly, the abstract (aka base) contracts don’t get compiled and only the Most derived contract gets compiled on EVM using all the functions of abstract contracts as part of its own bytecode (and also because there are only INTERNAL calls between inherited contracts - derived contract => abstract contract ) WHEREAS Libraries need to be compiled because they access & change the state/ scope/ storage of Caller contract (through EXTERNAL Delegate Calls made by Caller)?, so the difference again is Internal vs External ??

Its a little bit too much to grasp, But I am slowly getting it…(if what i said above is correct) ??
Kindly Please revert and enlighten me :pray:

Thanks and Regards
Suveett Kalra

then why do we in fact even need abstract contracts?, because all functionalities are already catered with Libraries and Interfaces, or is it not ??

Their main purpose is to let you extract common functionality from multiple contracts into one base contract. You can do this using a normal contract as well but if that base contract is incomplete and should not be deployed on its own or is missing some functions, marking it as abstract is just a way to tell that to the compiler. It's a completely different use case than libraries and interfaces. Libraries can't be used in the same way because you do not inherit from them. For example you cannot have virtual functions in a library and override them. And interfaces do not let you provide already implemented functions at all.

If i Understand correctly, abstract contracts basically are to build small modularise contracts (Splitting larger contracts into smaller pieces), with extended functionalities and usage/access via “Internal functions” ?

Yes. This is no different from normal contracts. The only difference is that abstract contracts do not have to be complete.

So the difference is basically Internality and Externality, right ?? Am I understanding it correctly ??

Yeah. Mostly. Interfaces are meant to define an external interface of a contract and you can use abstract contracts to define an internal interface.

Note however that you can have external methods in abstract contracts too. In fact they used to be used as ad-hoc external interfaces before a separate keyword for interfaces was introduced.
If you're interested in some language history, you can take a look at the discussions back from when these features were introduced:

& ALSO, if I understand it correctly, the abstract (aka base) contracts don’t get compiled and only the Most derived contract gets compiled on EVM using all the functions of abstract contracts as part of its own bytecode (and also because there are only INTERNAL calls between inherited contracts - derived contract => abstract contract ) WHEREAS Libraries need to be compiled because they access & change the state/ scope/ storage of Caller contract (through EXTERNAL Delegate Calls made by Caller)? , so the difference again is Internal vs External ??

The distinction does not really have anything to do with whether it's a library or an abstract contract. Both can have external and internal functions. In both cases internal functions are compiled into your own contract and external ones remain a part of another contract that is CALLED/DELEGATECALLED has to be deployed separately.

Thanks a ton. It really helped me a lot !!

Really appreciate your kind gesture :pray: