λ1016: Pass the fallback value directly

A function passed to GetOrElse, OrElse or Match that only returns a plain value should be replaced by the value.

Cause

A lambda is passed to the lazy overload of GetOrElse, OrElse or the none parameter of Match on Option<T>, Result<T> or Either<L, R>, and its body is nothing but a literal, a constant, a local, a parameter of the enclosing method, a field or auto-property read on a receiver that cannot be null, typeof or nameof.

Reason for rule

The lazy overload exists to defer work until the fallback is needed. option.GetOrElse(() => 0f) has no work to defer; the lambda only adds a delegate allocation and noise around the value. The eager overload option.GetOrElse(0f) says the same thing directly.

A lambda that uses its own parameter (exception => …, left => …) or that does work (a method call, an object creation, an indexer, a throw) is a legitimate use of the lazy overload and is not reported. Neither are () => null and () => default, because the bare value would be ambiguous between the two overloads.

How to fix violations

Replace the lambda with its body. A code fix is available.

Examples

Disallowed

static float Example(Option<float> option)
    => option.GetOrElse(() => 0f);

static int Example(Result<int> result, int fallback)
    => result.GetOrElse(_ => fallback);

static Option<int> Example(Option<int> option)
    => option.OrElse(() => Option<int>.None);

Allowed

static float Example(Option<float> option)
    => option.GetOrElse(0f);

static int Example(Result<int> result, int fallback)
    => result.GetOrElse(fallback);

// The function does work that is only needed in the error case.
static Settings Example(Option<Settings> settings)
    => settings.GetOrElse(() => LoadDefaultSettings());

// The function uses the left value.
static int Example(Either<string, int> either)
    => either.GetOrElse(left => left.Length);