Resource-Oriented Programming vs Solidity
In Solidity, a token balance is just a number in a mapping:
3.1 The problem Move solves
In Solidity, a token balance is just a number in a mapping:
The "asset" is an integer, and nothing in the language stops a buggy contract from incrementing it out of thin air, forgetting to decrement, or being re-entered mid-update.
In Move, the asset is a value of a resource type:
A Coin cannot be copied (no copy ability) and cannot be silently discarded (no drop ability). The compiler and verifier force every Coin to end up somewhere: transferred, stored in an object, joined into another coin, or destroyed by the coin module itself.
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount) external {
require(balances[msg.sender] >= amount, "insufficient");
balances[msg.sender] -= amount;
balances[to] += amount;
}public struct Coin<phantom T> has key, store {
id: UID,
balance: Balance<T>,
}3.2 Linear types in one paragraph
A linear value must be used exactly once. Move's abilities give a fine-grained version: a type without drop must be consumed; a type without copy cannot be duplicated. A struct with neither is a true linear resource. A struct with no abilities at all is a "hot potato" — it must be passed back to its module in the same transaction (Chapter 31).
3.3 Comparison table
Solidity / EVM Integers in contract storage First-class typed values (resources) Copy / destroy safety
Enforced by type system + bytecode verifier Common vulnerability class
Impossible: no dynamic dispatch, references cannot escape call, interfaces, delegatecall
None; generics are monomorphic and statically linked Checked since 0.8 (unchecked blocks exist) Always checked; overflow aborts Per-contract key-value slots
Per-account resources (Aptos) or objects (Sui) msg.sender checks
&signer, capabilities, object ownership Native package upgrades with compatibility checks Move Prover, spec language built in
Sui: owned objects skip consensus; Aptos: Block-STM optimistic parallelism
3.4 Why "move" semantics?
Ownership is tracked at compile time, so asset bugs become compile errors rather than exploits.
let a = coin; // `coin` is MOVED into `a`; `coin` can no longer be used
let b = a; // moved again
// let c = a; // ERROR: use of moved value
transfer::public_transfer(b, recipient); // consumed