Style guide menu

Idiomatic Turf

Turf often gives you two ways to say the same thing. Idiomatic code is code that picks the way most Turf programmers would, so the same idea always looks the same and readers never stop to wonder why it looks different here.

By the end of this page you will

  • Choose between mut and immut.
  • Know when to write a type and when to let Turf work it out.
  • Pick the clearest loop and the clearest choice.
  • Let the compiler check that every enum variant is handled.

TSG-701 Use immut unless the value changes

RecommendedNo tool checks this yet

Declare a variable with immut when it is set once and never changed, and with mut only when the code really assigns to it again. A reader who sees immut knows the value on that line is the value for the rest of the block, without reading the rest of the block.

Do
tsg_701.tr
fn main(): int {    immut price: int = 20;    immut people: int = 4;    mut total: int = 0;    for i in 0..people {        total += price;    }    printline(total);    return 0;}
Don't
tsg_701_avoid.tr
fn main(): int {    mut price: int = 20;    mut people: int = 4;    mut total: int = 0;    for i in 0..people {        total += price;    }    printline(total);    return 0;}

TSG-702 Write mut and immut, not mutable and immutable

RecommendedNo tool checks this yet

Turf accepts the long spellings mutable and immutable, and they mean exactly the same thing. Use the short ones everywhere, so that one word means one thing in every file.

Do
tsg_702.tr
fn main(): int {    mut count: int = 0;    immut amount: int = 2;    count += amount;    return count - 2;}
Don't
tsg_702_avoid.tr
fn main(): int {    mutable count: int = 0;    immutable amount: int = 2;    count += amount;    return count - 2;}

TSG-703 Write the type unless the value makes it obvious

RecommendedNo tool checks this yet

Turf can work out a variable’s type from its starting value. Let it do that when the value is a plain literal and the type is obvious at a glance (mut count = 0;). Write the type when the value comes from a call, a calculation or a conversion, because then the reader would have to go and look it up.

Do
tsg_703.tr
fn ratio(a: int, b: int): double {    return (a to double) / (b to double);}fn main(): int {    mut attempts = 0;    immut share: double = ratio(1, 4);    attempts++;    printline(share);    return 0;}
Don't
tsg_703_avoid.tr
fn ratio(a: int, b: int): double {    return (a to double) / (b to double);}fn main(): int {    mut attempts: guess = 0;    immut share = ratio(1, 4);    attempts++;    printline(share);    return 0;}

TSG-704 Use the short forms for counting

RecommendedNo tool checks this yet

Write i++ to add one and total += price to add an amount, rather than i = i + 1 and total = total + price. The short form names the variable once, so it cannot be misspelled on one side.

Do
tsg_704.tr
fn main(): int {    mut count: int = 0;    mut total: int = 0;    count++;    total += 15;    return total - count - 14;}
Don't
tsg_704_avoid.tr
fn main(): int {    mut count: int = 0;    mut total: int = 0;    count = count + 1;    total = total + 15;    return total - count - 14;}

TSG-705 Count with for, not while

RecommendedNo tool checks this yet

When a loop counts through a range of numbers, write for i in 0..n. The start, the end and the step are all on one line, and there is no counter to forget to increase. Keep while for loops that run until something happens.

Do
tsg_705.tr
fn main(): int {    mut sum: int = 0;    for i in 0..5 {        sum += i;    }    printline(sum);    return 0;}
Don't
tsg_705_avoid.tr
fn main(): int {    mut sum: int = 0;    mut i: int = 0;    while i < 5 {        sum += i;        i++;    }    printline(sum);    return 0;}

TSG-706 One give / otherwise per expression

RecommendedNo tool checks this yet

condition give a otherwise b is perfect for a quick choice between two values. Chaining several in one line makes the reader keep a stack of conditions in their head. For three or more outcomes, use if / elseif or compare.

Do
tsg_706.tr
fn label(n: int): string {    if n > 10 {        return "big";    } elseif n > 5 {        return "medium";    }    return "small";}fn main(): int {    immut n: int = 7;    immut parity: string = n % 2 == 0 give "even" otherwise "odd";    printline(label(n) + " and " + parity);    return 0;}
Don't
tsg_706_avoid.tr
fn main(): int {    immut n: int = 7;    immut size: string = n > 10 give "big" otherwise n > 5 give "medium" otherwise "small";    printline(size);    return 0;}

TSG-707 Name every variant when you compare an enum

RecommendedNo tool checks this yet

When you compare an enum or a machine, give each variant its own arm and leave otherwise out. Turf then checks that every variant is covered (E093). The day someone adds a new variant, the compiler points at every compare that needs a new arm. An otherwise would quietly swallow the new variant instead.

Do
tsg_707.tr
enum Light { Red, Amber, Green }fn action(l: Light): string {    compare l {        matches Light::Red:            return "stop";        done        matches Light::Amber:            return "wait";        done        matches Light::Green:            return "go";        done    }    return "";}fn main(): int {    printline(action(Light::Amber));    return 0;}
Don't
tsg_707_avoid.tr
enum Light { Red, Amber, Green }fn action(l: Light): string {    compare l {        matches Light::Red:            return "stop";        done        otherwise:            return "go";    }    return "";}fn main(): int {    printline(action(Light::Amber));    return 0;}

TSG-708 Keep main short

RecommendedNo tool checks this yet

main should read like a table of contents: set things up, call the functions that do the work, and return. Move the work itself into well-named functions, and into modules once a file gets long.

Esc

Type to search.