Video course contents16
All video lessons

LESSON 03 · HHY 1.7.0

Functions and Control Flow

Classify scores, total passing results, and use bounded repetition.

4:48 · English audio & captions

Your progress stays in this browser. No account needed.

Read the companion manual chapter

Chapters & transcript

Select a timestamp to jump in the video. Expand a title to read the transcript and code.

Build a score summary

Our task is to classify three scores and total only the passing results. This is a useful size for learning control flow: the input is small enough to check by hand, and the decisions are visible. We will define one function, loop over a list, skip unwanted values, and finish with a bounded while loop. The full downloadable program includes definitions before calls, so you can run it as a single file.

scores.hhy
print(classify(98))
print(classify(72))
print(classify(55))
# excellent
# pass
# retry

Follow along with the downloadable example.

Name a reusable decision

A function gives a reusable operation a name. Score is its parameter, so each call can classify a different number without repeating the decision tree. Return sends the result back to the caller and ends that function call. This function returns a string in every branch, which keeps its behavior predictable. Read the thresholds aloud: at least ninety, otherwise at least sixty, otherwise retry. The order makes the categories mutually exclusive.

hhy
fn classify(score) {
    if score >= 90 { return "excellent" }
    else if score >= 60 { return "pass" }
    else { return "retry" }
}

Follow along with the downloadable example.

Test the boundaries

Boundary values are more revealing than a few random inputs. Ninety should enter the first branch; sixty should enter the second; fifty nine should reach the last branch. If we tested only ninety eight, a mistaken passing threshold could go unnoticed. These are small executable checks, not a complete grading system. For a real application you would also decide what to do with missing values, non numeric input, and scores outside the allowed range.

hhy
print(classify(90))
print(classify(60))
print(classify(59))
# excellent
# pass
# retry

Follow along with the downloadable example.

Visit each score

The for loop introduces score for each list entry. Total lives outside the loop because we need to carry it from one iteration to the next and read it afterward. Continue skips the rest of the current iteration, so fifty five never reaches the addition. The final total is one hundred seventy. Notice that classify returns a label, while this loop accumulates a number. Keeping those responsibilities separate makes both pieces easier to understand.

hhy
let mut total = 0
for score in [98, 72, 55] {
    if score < 60 { continue }
    total = total + score
}
print(total)

Follow along with the downloadable example.

Choose whether to skip or stop

Break ends the loop completely. Continue only skips the current iteration. With this particular input, break prints the first two scores and stops at the failing one. Add another passing score after fifty five to see the difference clearly: continue would still consider it, while break would not. Choose the control statement from the task meaning. A report that needs every passing score should not stop just because one earlier entry failed.

hhy
for score in [98, 72, 55] {
    if score < 60 { break }
    print(score)
}

Follow along with the downloadable example.

Bound a while loop

While checks a condition before each iteration. Here the counter starts at zero and moves toward the stopping condition on every pass, so the output is one, two, three. A loop without that update would keep satisfying the same condition. Before writing a while loop, identify what changes and why the loop will end. For visiting an existing collection, a for loop often makes that termination behavior simpler to see.

hhy
let mut attempts = 0
while attempts < 3 {
    attempts = attempts + 1
    print(attempts)
}

Follow along with the downloadable example.

A small anonymous function

A closure expresses a small function that we can pass into another operation. Here apply calls its callback with the supplied value. The closure parameter appears before the arrow, and the expression after it computes the result. This example also previews the pipe syntax we will study next: twenty one becomes the input to apply. Soon we will pass closures into stream operators. Keep each closure focused on a small transformation.

closure.hhy
fn apply(value, callback) {
    return callback(value)
}
21 |> apply { value -> value * 2 } |> print
# 42

Follow along with the downloadable example.

Repair an unreachable category

This version runs, but the logic is wrong. A score of ninety eight already satisfies the first branch, so the excellent branch cannot receive it. A syntax check cannot infer your intended grading rules. Put the more specific high threshold first, then rerun the boundary examples. This is why running a program once without an error is not enough: correct syntax and correct answers are separate things that require different kinds of checking.

logic-error.hhy
fn wrong(score) {
    if score >= 60 { return "pass" }
    else if score >= 90 { return "excellent" }
    else { return "retry" }
}
print(wrong(98))

Follow along with the downloadable example.

Practice a complete summary

Extend the input with one hundred and sixty, predict the new total, and add a counter for passing scores. Keep the counter update beside the addition so both use the same filtering decision. Then test the threshold values again. You have now combined function calls, returned values, branching, iteration, and mutable state in one small task. In the next lesson we will express a sequence of transformations with the pipe operator.

hhy
# Add 100 and 60 to the input list.
# Predict the new passing total.
# Add a mutable passing counter.
# Print the total and count separately.

Follow along with the downloadable example.