λ1009: Do not use default to instantiate this type

Types marked [NonDefaultable] must not be created with default or a parameterless constructor.

Cause

A default(T) expression, a default literal, or a parameterless new T() is used with a struct marked with [NonDefaultable]. This applies to Either<L, R>, Result<T> and EitherOrBoth<L, R>.

Reason for rule

These structs have no meaningful "empty" state: an Either is always Left or Right, a Result is always Ok or Error. A default instance is in neither state. Every member on such an instance throws, so a default value is a latent bug that surfaces far away from where it was created.

Option<T> is not affected, because its default is a valid None.

How to fix violations

Construct the value explicitly using one of the constructors, such as Either<L, R>.Left(...), Either<L>.Return(...), Result.Return(...) or Result<T>.Error(...).

Examples

Disallowed

Result<int> result = default;
var either = default(Either<string, int>);
var eitherOrBoth = new EitherOrBoth<string, int>();

Allowed

Result<int> result = Result.Return(42);
var either = Either<string, int>.Left("error");
var eitherOrBoth = EitherOrBoth<string, int>.Both("left", 42);

// Option<T> has a valid default state.
Option<int> none = default;

Using the attribute on your own structs

The attribute is internal to Funcky, but the analyzer matches it by its full name Funcky.CodeAnalysis.NonDefaultableAttribute, so a copy in your own assembly works just as well. The rule itself is built into Funcky; the generator that writes the copy ships with the Funcky.Analyzers package. Install it and list the attribute in your project file:

<PropertyGroup>
  <FunckyCodeAnalysisAttributes>NonDefaultable</FunckyCodeAnalysisAttributes>
</PropertyGroup>

Alternatively, add the attribute by hand:

namespace Funcky.CodeAnalysis;

[AttributeUsage(AttributeTargets.Struct)]
internal sealed class NonDefaultableAttribute : Attribute;

Either way, the rule then applies to every struct you annotate:

[NonDefaultable]
public readonly struct Money { ... }

Money money = default; // λ1009

See Using the attributes in your own code for the details of the generator.