In Solidity a contract variable is really just an address under the hood.
You can actually interact with code deployed at a particular address without having a contract variable. address
has member functions like .call()
for example. These functions are a low-level EVM way to make an external call. At this level functions do not really exist. You specify some call data to be sent to that code and receive back a piece of return data.
Solidity's contract types are an abstraction to make that external code look more like classes you may be familiar with from other languages. Classes can have methods, and in Solidity the compiler simulates this by having the bytecode expect a function ID (selector) in the first 4 bytes of call data and do different things based on which ID was sent. In particular the ID determines how to interpret the data that follows it (i.e. the parameters).
Instead of using the low-level .call()
on an address and manually constructing the right call data, you can just call an external function on a contract, and the compiler will convert that for you to a low-level call in the bytecode it generates. To do this, however, it needs to know the address of that contract. You can give it this information by casting the address to the contract type. For convenience, you can store the result of such a cast in a contract variable instead of having to cast it every time.
Apart from external functions, contracts also have internal ones and these work very differently. You probably noticed that you cannot call an internal function on a contract variable. You can only call internal functions from your own contract or from contracts you inherit from. That's because calls to these do not go to a different address and do not need the whole mechanism that simulates external functions. They're actual functions that reside in your contract's own bytecode. Calling them is just a normal jump to a different place in the bytecode.
So, to summarize, contracts contain a mix of internal functions that you use in the contract itself and external functions that you don't call yourself but expect to be called from other contracts. This might be confusing when you're only using the latter because you do not need all that other stuff. You don't even need to know the function body to call it, just the name and the parameters. This is why there exists another kind of contract - interface
. Interfaces only define names and parameters of external functions. That's really all you need to know to perform an external call. It's much more common to use an interface rather than actual contract in the situation shown in your example, and I think it makes its purpose clearer.
Contract construction is yet another thing. The constructor is not involved at all when you're casting. The constructor is invoked only when you deploy a contract, and this usually happens in a completely separate transaction. Constructor parameters are included in transaction data in that case.
It's only possible to call the constructor from within a contract in one of two ways:
- Passing arguments to a base constructor. This cannot be mistaken for a cast because it never happens inside a function body.
- Contract deploying another contract. This uses a different syntax:
new B(...)
so it's also clearly distinguishable from a cast. Note that you cannot use this with interfaces because they only carry enough information to call the contract they represent, not to recreate it.
Best Answer
The easiest and fastest way to start coding Solidity is using Remix, which is a web-based IDE that allows you to code and compile smart contracts without the need of installing anything else.
VSCode is a great editor to write code and if you use a Solidity extension, this will give you hints when coding and options to compile (read the extension documentation to know how to compile, etc)
Finally, if you want to run tests or automate deployments, then you can go for frameworks such as Truffle or Hardhat, that will require Node.js to be installed.