Skip to content

Proposal: user-defined null/default check (non-defaultable value types / nullable-like types) #15108

@ufcpp

Description

@ufcpp

Nullable types - Nullable<T> or any reference types - are specially treated with some syntax:

  • propagate an invalid value with a ?. operator
  • serve an alternative value with a ?? operator
  • [planned] Flow-analysis based validity checking like non-nullable reference types

There are some types behaving like nullable types, and I would like these "nullable-like" types to be "first-class" in terms of special treatment like ?., ??, and flow-analysis.

Nullable-like types examples

1. value-constrained struct

Suppose that you implement a type which value has some constraints: for instance, an integer type which is constrained to be positive:

struct PositiveInt
{
     public int Value { get; }
     public PositiveInt(int value)
    {
        if (value <= 0) throw new InvalidOperationException();
        Value = value;
    }
}

If C# compiler would have DbC and record types, this sample would be written like:

struct PositiveInt(int Value) requires Value > 0;

This struct is meant not to be zero or less, but can be zero if and only if using default(PositiveInt). The default should be treated as an invalid value like null.

2. Expected

There is a problem with using null as an invalid value, it does not tell why the operation returned null. To solve this problem, some people prefer a type similar to expected<T> in C++ - it is a union type of T and Exception as following:

struct Expected<T>
{
    public T Value { get; }
    public Exception Exception { get; }
    public bool HasValue => Exception == null;
}

When I use such a type, I want to write as following:

Expected<string> s;
Expected<int> len = s?.Length;
int x = len ?? 0;

This code uses "exception propagating operator" ?. and "exception coalescing operator" ?? by analogy with null propagating/coalescing operator.

Proposed syntax

I want some syntax to introduce "nullable-like" types to C#; One idea is "operator null":

// definition
struct Expected<T>
{
    public T Value { get; }
    public Exception Exception { get; }
    public static bool operator null => Exception != null;
}

// usage
Expected<int> e;
int x = e ?? 0;

// generated code
Expected<int> e;
int x = operator null(e) ? 0 : e.Value;

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions