All articles
Web3 FoundationsSeptember 14, 20267 min read

view vs pure in Solidity: Two Promises a Function Can Make

What view and pure actually promise, why the compiler enforces both, why calling them from off chain is free, and what it means when a function is marked neither.

By Carlos (Bloqarl)

TL;DR

  • view promises the function reads state but never changes it. pure promises it does not even read. Both are enforced by the compiler.
  • A function marked neither can change state, and that is the default. The absence of the word is itself information.
  • Calling a view or pure function from outside the chain costs nothing, which is why contracts expose so many of them.
  • Called from inside another contract's transaction, they cost gas like any other code. Free only means free from off chain.
  • Reading the state-mutability word before the function body tells you, in one glance, whether this function can possibly change anything.

What is the difference between view and pure in Solidity?

view means the function may read the contract's state but may not modify it. pure means it may not even read state, only work with the values passed into it. Both promises are checked by the compiler, so a function that breaks them will not compile.

Our contract has one of each kind of function, and the difference is visible at a glance:

    function progress() external view returns (uint256) {
        return address(this).balance;
    }

    function smash() external {
        require(msg.sender == owner, "only the owner");
        require(address(this).balance >= goal, "goal not reached");
        payable(owner).transfer(address(this).balance);
    }

progress is view. It reads the contract's balance and reports it. Nothing changes.

smash is marked neither, and that absence is the point: it can move money, and it does.

Why does view matter to a reader?

Because it collapses a whole class of question in one word.

When you open an unfamiliar contract with forty functions, the first useful sort is not what they are called. It is which of them can change anything. Every function marked view or pure is, by compiler guarantee, incapable of altering the contract's state. They can be read quickly, or skipped entirely on a first pass.

What is left is the set of functions that can actually do something, and that set is usually far smaller than the file's length suggests. In many real contracts, half the functions are getters.

This is why we teach reading the mutability word before the function name, and why it is one of the three questions the function pass in how to read a smart contract asks of every function. function progress() external view returns (uint256) has already told you the three things that matter before you reach the body: anyone outside can call it, it changes nothing, and it hands back a number.

Why are view functions free to call?

Because nothing has to be agreed on.

Changing chain state requires a transaction: every validating node must execute it, agree on the result, and store it. That is what gas pays for. But a function that only reads state changes nothing, so there is nothing to agree on and nothing to store. Any single node can run it locally and hand back the answer.

So when your wallet or a block explorer calls progress(), it asks one node to compute the answer and read it out. No transaction, no fee, no waiting for a block. This is why a contract's public state variables and view functions are how the outside world reads a contract, and why exposing generously costs the protocol nothing.

The important qualification: free means free from off chain. If another contract calls progress() in the middle of a transaction, that execution happens inside the transaction and is paid for in gas like any other code. The word view does not make code weightless, it makes it skippable when nobody needs consensus about it.

What can pure functions actually do?

Arithmetic, comparisons, hashing, and anything else that depends only on the arguments handed in.

    function double(uint256 x) external pure returns (uint256) {
        return x * 2;
    }

This function does not know what contract it lives in. It cannot read owner, cannot read the balance, cannot look at the block timestamp. Give it 5 and it returns 10, today and in ten years, deployed anywhere.

That makes pure a strong signal when reading. A pure function is a self-contained calculation, and you can verify it by reading it alone, with no reference to the rest of the file. In big contracts, maths helpers are usually pure, and they are the safest place to start reading when you want to understand how a protocol computes something without first understanding everything it stores.

What does it mean when a function is marked neither?

That it can change state, and you should read it carefully.

Solidity has no keyword for "this function modifies state", because that is the default. The mutability markers only ever restrict. So the absence of view and pure is the signal:

MarkingCan read stateCan change state
pureNoNo
viewYesNo
(none)YesYes
payableYesYes, and can receive ETH

That table is worth memorising, because it lets you triage an unfamiliar contract in about thirty seconds. Scan the function signatures, ignore everything marked view or pure on the first pass, and you are left with the contract's real surface area.

You will also meet constant on older functions, which was the previous spelling of view and is no longer used in current Solidity.

Can a view function still fail?

Yes, and this catches people out.

view promises the function does not change state. It does not promise the function succeeds. A view function can revert, for instance if it divides by zero or if a require inside it fails. When called from off chain, that failure comes back as an error rather than a value. When called inside a transaction, it reverts the transaction like any other failure. See require and revert.

Nor does view promise the answer stays true. It reports the state at the moment it is called, and the very next transaction can change that state. A balance read a second ago is a fact about a second ago. In a contract that reads its own numbers across multiple steps, the gap between "when this was read" and "when it is used" is exactly where a careful reader slows down.

Delete the word and ask what breaks

  • Delete view from progress and nothing about today's behaviour changes, but the compiler-enforced promise is gone. Callers can no longer rely on it, and wallets that would have called it for free may now treat it as a transaction.
  • Add view to smash and the contract will not compile, because smash moves ETH. The compiler refuses the false promise, which is the whole value of the keyword.
  • Change view to pure on progress and it also fails to compile, since reading address(this).balance is reading state.
  • Add payable to a view function and it fails to compile as well. Accepting ETH is a state change by definition.

Notice how many of those are compile-time refusals. These keywords are not documentation. They are constraints the compiler holds you to, which is exactly why a reader can trust them.

Related questions

What is the difference between view and pure? view may read the contract's state but not modify it. pure may do neither, working only with its arguments and returning a result derived from them.

Are view functions free? Free when called from off chain, because no transaction or consensus is needed and a single node can compute the answer. Called from inside another contract's transaction, they consume gas like any other execution.

Can a view function change state? No. The compiler rejects any state modification inside a view function, so the guarantee holds for every function carrying the keyword.

What does it mean if a function has no view or pure? That it is allowed to modify state, which is the default in Solidity. There is no positive keyword for "modifies state", so the absence of a restriction is the signal.

Is constant the same as view? It was. constant on a function was the older spelling of view and has been removed from current Solidity. On a state variable, constant means something different: a value fixed at compile time.

Can a view function call a function that changes state? No. The restriction propagates, so a view function cannot call a non-view function. This is what makes the guarantee reliable rather than merely local.

Where to go next

Two keywords, two promises, both enforced. Together they let you sort an unfamiliar contract into "can change things" and "cannot" before you have read a single function body, which is the fastest triage move available to a contract reader.

The other half of a function signature answers a different question: not what it does to state, but who is allowed to call it at all. That is public, private, internal, external.

Tagged

SoliditySmart ContractsLearn to Code