Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Overload Resolution and Expression-Bodied Members

โญโญ intermediateโณ 15 min read๐Ÿ“ Lesson 91 of 265

How the compiler picks an overload, ambiguity traps, optional/named arguments, and members that read like math.

Overload resolution: betterness, not cleverness

Given a call, the compiler picks the best candidate: exact matches beat implicit numeric conversions, which beat object boxing. Ambiguity is a compile error โ€” the fix is in your API design, not the call site:

static void Log(int n) { }
static void Log(double n) { }
static void Log(object o) { }

Log(5);        // Log(int) โ€” exact
Log(5.0);      // Log(double) โ€” exact
Log((short)5); // Log(int) โ€” short->int beats short->double and boxing
Log(null);     // Log(object)? ambiguous with string overloads if present!

Two rules prevent most pain: never overload on boxed types only, and keep overload sets so the same intent is expressible โ€” overloads are synonyms, not different behaviors.

Optional and named arguments

Defaults collapse overload explosions; named arguments make call sites self-documenting:

static void Send(string to, string subject = "(no subject)", bool cc = false) { }

Send("a@b.c");
Send("a@b.c", cc: true);              // skip the middle default
Send(to: "a@b.c", subject: "hi");     // reads like a sentence

Pitfall: changing a default value is a binary-breaking change โ€” callers compile the constant in. Version carefully.

Expression-bodied members

For members that are one computation, the arrow removes ceremony:

public static int Square(int x) => x * x;
public string Name => _name?.Trim() ?? "";
public static bool IsVowel(char c) =>
    c is 'a' or 'e' or 'i' or 'o' or 'u';

The limit is readability: if the body needs two thoughts, use a block with a name. Local functions complete the toolbox โ€” named helpers scoped to one method, closing over its parameters, zero ceremony:

static int CircleOps(double r)
{
    double Area() => Math.PI * r * r;      // closes over r
    double Circ() => 2 * Math.PI * r;
    return Area() > 100 ? 1 : (Circ() > 10 ? 2 : 0);
}

Check your understanding

  • Why is Log(null) ambiguous with Log(string) + Log(object)? (string is "better" but null fits both; compiler refuses to guess.)
  • Optional parameter vs overload: which is binary-compatible to extend? (Overloads โ€” new defaults bake into callers.)

โšก Now practice

Ready to Code
Overload Resolution PracticePick the exact overload the compiler picks, and wire optional/named arguments without surprises.
2 challenges ยท ยท ~20 min