beginner
+200 XP

Making Decisions in Code

Teach your smart contracts to think! Learn how to make decisions with if/else, repeat actions with loops, handle errors gracefully, and keep your variables organized — all in beginner-friendly steps.

Lesson Syllabus

Conditionals: if/else
🔀

if/else as Expressions

Your code needs to make decisions, just like you do every day — "If it's raining, bring an umbrella, else wear sunglasses." That's exactly what `if/else` does in Move. But here's a cool twist that's different from many other languages: in Move, `if/else` is an expression, which means it produces a value. Think of it like a question that gives you an answer: "If this condition is true, the answer is X, otherwise it's Y." You can assign that answer directly to a variable! The only rule is that both branches need to give back the same type (you can't have one branch return a number and the other return text). The condition inside the parentheses must be a `bool` (true or false). If you write an `if` without an `else`, the if block can't return a value — it just does something and moves on.

🧮

Boolean Operators & Conditions

Before you can make decisions, you need to ask questions — and that's what comparison operators do. You've got the usual suspects: `==` (are these equal?), `!=` (are these different?), `<`, `>`, `<=`, `>=`. But sometimes one question isn't enough. That's where logical operators come in. These are basically the words AND, OR, and NOT — just written as symbols: `&&` (and), `||` (or), `!` (not). For example, "is the user the owner AND is the account active?" becomes `is_owner && is_active`. One handy detail: Move uses short-circuit evaluation. In `a && b`, if `a` is already false, Move doesn't even bother checking `b` (because the whole thing can't be true anyway). Same idea with `||` — if `a` is true, `b` gets skipped. This isn't just a performance trick — it can actually prevent errors when `b` might cause an abort.

🛡️

Nested Conditions & Guards

In real Sui contracts, if/else is your go-to tool for access control, input validation, and conditional business logic. A super common pattern is the "guard clause" — you check your preconditions at the top of the function and bail out immediately if something's wrong. Think of it like a bouncer checking IDs at the door before letting anyone into the club. This is way cleaner than wrapping your entire function in a big nested if/else. When you do need nested conditions, try to keep the nesting shallow (2-3 levels max). If you find yourself going deeper, it's a sign you should extract some logic into a helper function.

Loops & Iteration
🔁

while Loops

Sometimes you need your code to do something over and over — like washing dishes. You keep going while there are dirty dishes left, and you stop when the sink is empty. That's a `while` loop! In Move, `while` repeats a block of code as long as a condition stays true. It checks the condition before each round, so if the condition is false from the start, the code inside never runs at all. The most common use in Move is looping through a vector (a list) by index — you start at 0, process each item, and stop when you've reached the end. One important warning: if the condition never becomes false, the loop runs forever, eats all the gas, and your transaction fails. Always make sure your loop has a clear exit plan!

♾️

loop with break & continue

An infinite loop is like walking on a treadmill — you need to decide when to step off. The `loop` keyword creates a loop that runs forever until you explicitly say `break`. Why would you want this? Sometimes the exit condition is complicated, or you want to break from the middle of the loop body rather than checking at the top like `while` does. `break` is your "I'm done" signal — it exits the loop. `continue` is different — it says "skip the rest of this round and start the next one." And here's something neat: in Move, `loop` can be an expression! You can write `break some_value` to return a value from the loop, just like if/else returns a value.

🔧

Practical Loop Patterns

In real Sui contracts, you'll use loops all the time — iterating over a list of items, distributing rewards to multiple addresses, or searching for a specific element. Think of loops as your assembly line: each item comes through, you do something with it, and move on to the next. But here's something important to keep in mind: every trip through the loop costs gas (the fee for running code on the blockchain). If you're looping over a really long list, you could hit the gas limit and your transaction fails. For large collections, smart developers use a "pagination" pattern — process a batch at a time across multiple transactions, like reading a book chapter by chapter instead of all at once.

Error Handling & Scopes
🛑

abort and assert!

What happens when something goes wrong in your contract? Maybe someone tries to withdraw more money than they have, or a non-owner tries to modify something they shouldn't. You need a way to say "Nope, not happening" and stop everything. That's where `abort` and `assert!` come in. Think of them like a bouncer at a club — if you don't meet the rules, you're not getting in. `abort error_code` immediately stops the transaction and undoes everything that happened in it. `assert!(condition, error_code)` is the shorthand version: "if this condition is false, abort with this error code." Most developers use `assert!` because it reads like plain English: "assert that the sender is the owner, otherwise error." Pro tip: always give your error codes descriptive constant names (like `ENotAuthorized` instead of just `1`) so that when something fails, you can actually figure out why.

⏏️

return and Early Exit

Remember how in Move the last expression in a function (without a semicolon) is automatically the return value? That works great most of the time. But sometimes you want to bail out of a function early — like saying "if there's nothing to process, just give back zero and don't bother with the rest." That's what the `return` keyword is for. You only need explicit `return` when you want to exit before reaching the end of the function. It's called the "guard clause" pattern, and it keeps your code flat and readable instead of nesting everything inside if/else blocks. At the end of a function, just write the value without a semicolon — no `return` needed.

📦

Scopes, Blocks & Shadowing

Variables live inside their curly braces — like how conversations at a dinner table stay at that table. When someone leaves the table (the closing `}` brace), whatever was said there is gone. In Move, `{ }` creates a new scope. Any variable you declare inside a scope disappears when the scope ends. But here's something useful: a block can also produce a value! The last expression inside the block (without a semicolon) becomes the block's result. This lets you do temporary calculations without cluttering up your outer code with variables you only need briefly. Move also supports "shadowing" — you can declare a new variable with the same name as an existing one, and the new one takes over. The old one isn't changed or destroyed; it's just hidden until the shadow goes away.