# Argument Labels and Parameters

Harder cases for the label rules in the main skill, plus how to name
parameters and order defaulted ones.

## Prepositional labels

The base rule: when the first argument finishes a prepositional phrase that
the base name starts, the preposition is its label.

```swift
removeBoxes(havingLength: 12)
fade(from: red)
relativePath(from: root)
```

### When two arguments form one idea

If the first two arguments are coordinates of a single thing, a label like
`atRow:` would glue the preposition to only one of them. Keep the preposition in
the base name and label each part:

```swift
grid.cellAt(row: r, column: c)        // row and column together locate one cell
grid.cell(atRow: r, column: c)        // avoid: "at" seems to belong to row only
```

The same reasoning gives `moveTo(x:y:)` rather than `move(toX:y:)`.

### Several prepositions

When each argument has its own relationship to the operation, each gets its
own prepositional label:

```swift
shelf.move(book, from: source, to: destination)
theme.transition(from: light, to: dark, duration: 0.3)
```

## Grammatical phrases

If the first argument simply continues the sentence the base name began, it
needs no label:

```swift
stack.addSubview(child)
tags.contains(element)
```

Words that would lead the label belong in the base name instead:

```swift
warehouse.removeBoxes(havingLength: 12)       // good
warehouse.remove(boxesHavingLength: 12)       // avoid
```

## Conversions

### Value-preserving: no label

The new value represents the old one exactly, so the call reads as a type
conversion and nothing needs explaining.

```swift
Int64(someUInt32)
String(someCharacter)
Double(someFloat)
```

### Narrowing or lossy: a label that says how

| Initializer | What the label warns about |
|---|---|
| `Int64(truncating:)` | bits or precision are dropped |
| `UInt32(clamping:)` | out-of-range values are pinned to the limits |
| `String(describing:)` | a debug-style text description, not a value conversion |
| `Int(exactly:)` | returns `nil` unless the value converts without loss |

### A different representation: the label names the interpretation

```swift
String(utf8String: cString)
try Data(contentsOf: fileURL)
URL(string: "https://example.com")
```

## Parameter names are documentation

A parameter name may never appear at the call site, but it appears in the
generated documentation and in the doc comment. Pick names that read well
there.

```swift
extension Roster {
    /// Returns the position of `member` in the roster, if present.
    ///
    /// - Parameter member: The person to look for.
    /// - Returns: The index of `member`, or `nil` if they are not listed.
    func index(of member: Person) -> Int? {
        people.firstIndex(of: member)
    }
}
```

Compare `func index(of p: Person)`: the doc comment would have to talk about
"`p`", which tells the reader nothing. Use whole English words for parameter
names; single letters and abbreviations make the documentation worse.

## Default arguments instead of method families

One method with defaults is easier to learn than several near-identical
overloads:

```swift
extension Transcoder {
    func transcode(
        _ video: Video,
        preset: Preset = .standard,
        preservesMetadata: Bool = true
    ) async throws -> Video {
        try await engine.run(video, preset: preset, metadata: preservesMetadata)
    }
}

// Instead of transcode(_:), transcode(_:preset:) and
// transcode(_:preset:preservesMetadata:)
```

### Ordering

Required parameters come first and defaulted ones last. The required
parameters usually carry the meaning and form the grammatical core of the
call, so they should read first:

```swift
struct Glossary {
    func lookup(
        _ term: String,
        in scope: Scope = .everything,
        limit: Int = 25,
        startingAt offset: Int = 0
    ) -> [Entry] {
        index.matches(for: term, in: scope).dropFirst(offset).prefix(limit).map { $0 }
    }
}
```

Exception: a trailing closure that callers most often supply can follow the
defaulted parameters, so it can still be written as a trailing closure.

```swift
final class SettingsStore {
    func observe(
        _ key: SettingKey,
        initial: Bool = true,
        onChange handler: @escaping (SettingValue) -> Void
    ) -> Observation {
        registry.add(key, emitsCurrentValue: initial, handler: handler)
    }
}

// store.observe(.theme) { newValue in apply(newValue) }
```
