On this page

Compare the decisions a maintainer must understand

Equivalent results do not require identical statement sequences. Compare an idiomatic implementation in each language, including the library machinery it needs. The question is whether a reviewer can find the business priority, the changing state and the lifetime boundary. More lines alone do not make code clearer; compact code is useful when its meaning remains obvious.

A review policy with several priorities

The policy uses whole-unit, nonnegative Integer amounts. Approved transactions stay approved; cancelled or unknown states are not processed. A pending transaction first needs verified identity, then manual review at 10,000 or more. All other pending transactions follow standard review.

DirectSharp: read the priority in order

enum ReviewStatus
    Pending
    Approved
    Cancelled
end enum

public action ReviewRoute(status as ReviewStatus, verified as Boolean, amount as Integer)
    returns String
    description "Choose a review route without modifying the transaction."

    require amount >= 0 otherwise new Global.System.ArgumentOutOfRangeException("amount")
    if status = ReviewStatus.Approved then
        return "Already reviewed"
    end if
    if status <> ReviewStatus.Pending then
        return "Do not process"
    end if
    // Identity is checked before the amount can qualify for standard review.
    if not verified then
        return "Identity check"
    end if
    return select amount
        case >= 10000
            take "Manual review"
        else
            take "Standard review"
    end select
end action

C#: a modern tuple-pattern switch

public enum ReviewStatus { Pending, Approved, Cancelled }

public static string ReviewRoute(ReviewStatus status, bool verified, int amount)
{
    ArgumentOutOfRangeException.ThrowIfNegative(amount);
    // Arm order expresses priority; the tuple combines three inputs.
    return (status, verified, amount) switch
    {
        (ReviewStatus.Approved, _, _) => "Already reviewed",
        (ReviewStatus.Pending, false, _) => "Identity check",
        (ReviewStatus.Pending, true, >= 10000) => "Manual review",
        (ReviewStatus.Pending, true, _) => "Standard review",
        _ => "Do not process"
    };
}

This is concise, idiomatic C#. A reader comfortable with tuple patterns can scan it quickly. DirectSharp chooses separate named steps and explicit endings; its benefit is the visibility of priority to readers who do not regularly work with pattern syntax. There is no reason to replace this C# switch with a deliberately verbose version just to make a comparison look favorable.

C++: a status switch with nested checks

#include <cstdint>
#include <stdexcept>
#include <string_view>
enum class ReviewStatus { Pending, Approved, Cancelled };

std::string_view review_route(ReviewStatus status, bool verified, std::int32_t amount)
{
    if (amount < 0) throw std::out_of_range("amount");
    switch (status) {
    case ReviewStatus::Approved:
        return "Already reviewed";
    case ReviewStatus::Pending:
        // These returns terminate the case; there is no fall-through.
        if (!verified) return "Identity check";
        if (amount >= 10000) return "Manual review";
        return "Standard review";
    default:
        return "Do not process";
    }
}

C++ uses its ordinary switch and early returns. The reviewer must connect each return to its case and the closing brace to its scope. DirectSharp's end if, end select and end action make those boundaries explicit. Neither version requires a rule engine or a framework.

Input Expected route in all three versions
Approved, unverified, 10,000 Already reviewed
Pending, unverified, 10,000 Identity check
Pending, verified, 9,999 Standard review
Pending, verified, 10,000 Manual review
Cancelled, verified, 100 Do not process
Any state with a negative amount Argument/range failure before routing

Fresh mutable state: DirectSharp and Python

An import starts with independent empty row/error lists and a zero total. No list should leak rows into the next import.

import System.Collections.Generic

public class ImportBatch
    public properties
        Rows as List <of String> = default
        Errors as List <of String> = default
        Total as Integer = default
    end properties
end class

let first = new ImportBatch()
let second = new ImportBatch()
first.Rows.Add("A")
// The locked List default creates a fresh list: second.Rows.Count is zero.
from dataclasses import dataclass, field

@dataclass
class ImportBatch:
    # Factories create fresh mutable lists for each constructed instance.
    rows: list[str] = field(default_factory=list)
    errors: list[str] = field(default_factory=list)
    total: int = 0

first = ImportBatch()
second = ImportBatch()
first.rows.append("A")
assert second.rows == []

Python's default_factory is an ordinary, useful idiom. A mutable class-level list or a mutable function default would have a different sharing contract; neither is an equivalent replacement. DirectSharp's locked built-in List default expresses fresh initialization with one language rule. It does not promise that arbitrary custom reference types construct themselves: their default can still be nothing. Python annotations and dataclasses do not by themselves enforce runtime input types or freeze the lists, and DirectSharp's writable properties do not freeze them either.

Coordination is more than starting two tasks

The command handler must read customer and risk together, race interchangeable customer replicas, bound active transaction workers, protect shared report/totals updates, and retry only transient GET failures. Its comments identify when capacity is held and when it is released. Compare that outcome with the complete async/resource examples, not just the spelling of await.

Language Idiomatic machinery to inspect What DirectSharp makes explicit
C# Tasks, a shared SemaphoreSlim, try/finally release, CancellationTokenSource and task settlement; Task.WhenAny selects completion, not first success Gate scopes, owned joins and first-success selection are named language contracts
VB.NET The same CLR task/token/semaphore primitives, with Try/Finally and explicit blocks Familiar block endings plus concurrency ownership and the selected cleanup route
Python asyncio.TaskGroup for owned tasks, Semaphore with async with, a deliberate first-success selection and cancellation policy first selects success; end concurrent joins owned children and publishes its result
C++ RAII owners, locks/permits and an executor/task library; the library defines cancellation and how tasks are joined Managed resource scopes and a defined Gate/structured-concurrency contract; native-memory control is a different requirement
Go Goroutines, channels and a shared context; the sender/receiver design must drain or cancel losing work without blocking senders Ownership and losing-producer settlement are part of the scope contract
Java The selected executor/future or structured-task API, interruption support and cleanup; winning future selection alone does not settle all work Selection, cancellation requests and settlement are specified together
Rust Ownership and RAII plus the chosen async runtime's spawn/select/join and cancellation behavior The business source names the scope policy; it does not provide Rust's ownership model or native execution guarantees
JavaScript Promise.any for first fulfillment, explicit AbortController wiring, and settlement of losers when the operation owns them first requests cooperative loser cancellation and joins; a resolved Promise.any alone supplies neither guarantee
TypeScript JavaScript's runtime primitives plus static interface/result types; typing a promise does not change cancellation or ownership Strongly typed results with the same explicit scope obligations

These are API/language responsibilities, not universal equivalent snippets. An alternative implementation must preserve the same failure, cancellation, result-order and ownership contracts before it can be called equivalent. A lock protects shared state; a capacity gate limits admission. Neither automatically replaces the other. Avoid manufacturing lock-heavy code where an ordinary library already provides the needed policy.

Read the complete tasks with these questions

For every language, ask: which input is rejected, which branch wins, which state changes, what happens after a partial failure, and who waits for cleanup? The task index links the complete versions. Use the workload comparison when native integration, a browser runtime or Python's data ecosystem matters more than the syntax of one rule.