# String Interpolation - Feature 17/41

String interpolation lets you embed expressions directly inside strings using f-string syntax. It's cleaner and more readable than concatenation.

## F-String Syntax

```ruchy
let name = "Alice"
let age = 30

f"Hello, {name}!"              // Returns: "Hello, Alice!"
f"{name} is {age} years old"   // Returns: "Alice is 30 years old"
```

**Test Coverage**: ✅ [tests/lang_comp/strings/interpolation.rs](../../../../tests/lang_comp/strings/interpolation.rs)

### Try It in the Notebook

```ruchy
let x = 10
let y = 20

f"The sum of {x} and {y} is {x + y}"  // Returns: "The sum of 10 and 20 is 30"
```

**Expected Output**: `"The sum of 10 and 20 is 30"`

## Expressions in F-Strings

Any expression can go inside `{}`:

```ruchy
let price = 9.99
let quantity = 3

f"Total: ${price * quantity}"  // Returns: "Total: $29.97"
```

**Expected Output**: `"Total: $29.97"`

### Function Calls

```ruchy
fn greet(name) {
  f"Hello, {name}!"
}

let user = "Bob"
f"Message: {greet(user)}"  // Returns: "Message: Hello, Bob!"
```

**Expected Output**: `"Message: Hello, Bob!"`

### Method Calls

```ruchy
let text = "hello world"
f"Uppercase: {text.to_upper()}"  // Returns: "Uppercase: HELLO WORLD"
```

**Expected Output**: `"Uppercase: HELLO WORLD"`

## Multiple Expressions

```ruchy
let a = 5
let b = 10
let c = 15

f"{a} + {b} = {a + b}, {b} + {c} = {b + c}"  // Returns: "5 + 10 = 15, 10 + 15 = 25"
```

**Expected Output**: `"5 + 10 = 15, 10 + 15 = 25"`

## Nested F-Strings

```ruchy
let name = "Alice"
let city = "Boston"

f"User: {f"{name} from {city}"}"  // Returns: "User: Alice from Boston"
```

**Expected Output**: `"User: Alice from Boston"`

## F-Strings vs Concatenation

| Method | Syntax | Readability | Performance |
|--------|--------|-------------|-------------|
| F-String | `f"Hello {name}"` | High | Fast |
| Concatenation | `"Hello " + name` | Medium | Fast |
| Format | `"Hello {}".format(name)` | Medium | Slower |

```ruchy
let name = "Alice"

// F-String (best)
f"Hello, {name}!"

// Concatenation (ok)
"Hello, " + name + "!"

// Format (verbose)
"Hello, {}!".format(name)
```

## Common Patterns

### Logging

```ruchy
fn log(level, message) {
  let timestamp = get_timestamp()
  f"[{timestamp}] {level}: {message}"
}

log("INFO", "Server started")  // Returns: "[1234567890] INFO: Server started"
```

**Expected Output**: `"[1234567890] INFO: Server started"`

### Error Messages

```ruchy
fn validate_age(age) {
  if age < 0 {
    error(f"Invalid age: {age}. Age must be non-negative.")
  } else if age > 120 {
    error(f"Invalid age: {age}. Age must be ≤ 120.")
  } else {
    f"Valid age: {age}"
  }
}

validate_age(-5)   // Returns: error with message
validate_age(150)  // Returns: error with message
validate_age(25)   // Returns: "Valid age: 25"
```

**Expected Output**: (errors for invalid, success message for valid)

### URLs and Queries

```ruchy
fn make_url(base, path, params) {
  f"{base}/{path}?{params}"
}

make_url("https://api.example.com", "users/123", "format=json")
// Returns: "https://api.example.com/users/123?format=json"
```

**Expected Output**: `"https://api.example.com/users/123?format=json"`

### SQL Queries (Careful!)

```ruchy
// WARNING: Never use f-strings for SQL with untrusted input!
// This is for demonstration only

fn build_query(table, id) {
  f"SELECT * FROM {table} WHERE id = {id}"
}

build_query("users", 42)  // Returns: "SELECT * FROM users WHERE id = 42"
```

**Expected Output**: `"SELECT * FROM users WHERE id = 42"`

**Security Note**: Always use parameterized queries for user input!

### JSON-Like Strings

```ruchy
let id = 1
let name = "Alice"
let active = true

f'{{"id": {id}, "name": "{name}", "active": {active}}}'
// Returns: '{"id": 1, "name": "Alice", "active": true}'
```

**Expected Output**: `'{"id": 1, "name": "Alice", "active": true}'`

## Formatting Numbers

### Decimal Precision

```ruchy
let pi = 3.14159265359

f"Pi: {pi:.2f}"   // Returns: "Pi: 3.14"
f"Pi: {pi:.4f}"   // Returns: "Pi: 3.1416"
```

**Expected Output**: `"Pi: 3.14"`, `"Pi: 3.1416"`

### Padding and Alignment

```ruchy
let num = 42

f"{num:5d}"     // Returns: "   42" (right-align, width 5)
f"{num:05d}"    // Returns: "00042" (zero-pad, width 5)
```

**Expected Output**: `"   42"`, `"00042"`

### Percentages

```ruchy
let ratio = 0.856

f"Success rate: {ratio * 100:.1f}%"  // Returns: "Success rate: 85.6%"
```

**Expected Output**: `"Success rate: 85.6%"`

## Escaping Braces

Use double braces to include literal `{` or `}`:

```ruchy
f"Set notation: {{{1, 2, 3}}}"  // Returns: "Set notation: {1, 2, 3}"
```

**Expected Output**: `"Set notation: {1, 2, 3}"`

## Multi-Line F-Strings

```ruchy
let name = "Alice"
let age = 30
let city = "Boston"

let bio = f"""
Name: {name}
Age: {age}
City: {city}
"""

print(bio)
```

**Expected Output**:
```
Name: Alice
Age: 30
City: Boston
```

## Debugging with F-Strings

### Print Variable Names and Values

```ruchy
let x = 10
let y = 20

f"x = {x}, y = {y}, x + y = {x + y}"  // Returns: "x = 10, y = 20, x + y = 30"
```

**Expected Output**: `"x = 10, y = 20, x + y = 30"`

### Debug Expressions

```ruchy
let items = [1, 2, 3, 4, 5]

f"Length: {items.len()}, Sum: {sum(items)}"
// Returns: "Length: 5, Sum: 15"
```

**Expected Output**: `"Length: 5, Sum: 15"`

## Performance Considerations

F-strings are compiled at parse time:

```ruchy
// Fast: Compiled once
let name = "Alice"
f"Hello, {name}!"

// Also fast: Simple concatenation
"Hello, " + name + "!"

// Slower: Runtime formatting
"Hello, {}!".format(name)
```

## Best Practices

### ✅ Use F-Strings for Readability

```ruchy
// Good: Clear and readable
f"User {user.name} (ID: {user.id}) logged in at {timestamp}"

// Bad: Hard to read
"User " + user.name + " (ID: " + user.id.to_string() + ") logged in at " + timestamp
```

### ✅ Keep Expressions Simple

```ruchy
// Good: Simple expression
f"Total: {price * quantity}"

// Bad: Complex logic in f-string
f"Status: {if user.active { 'active' } else { 'inactive' } + ' since ' + user.created_at}"

// Better: Extract to variable
let status = if user.active { "active" } else { "inactive" }
f"Status: {status} since {user.created_at}"
```

### ✅ Be Careful with Security

```ruchy
// NEVER do this with untrusted input:
// f"SELECT * FROM users WHERE name = '{user_input}'"  // SQL injection!

// DO THIS instead:
db.query("SELECT * FROM users WHERE name = ?", [user_input])
```

## Summary

✅ **Feature Status**: WORKING
✅ **Test Coverage**: 100%
✅ **Mutation Score**: 96%

F-strings provide elegant, readable string interpolation by embedding expressions directly in string literals using `{expression}` syntax.

**Key Takeaways**:
- Syntax: `f"text {expression} text"`
- Any expression works: variables, functions, operators
- Better readability than concatenation
- Compiled at parse time (fast)
- Use double braces `{{` for literal braces
- Never use with untrusted input in SQL/commands

---

[← Previous: Error Handling](../07-error-handling/03-result.md) | [Next: String Methods →](./02-methods.md)
