dapr / dotnet-sdk

Dapr SDK for .NET
Apache License 2.0
1.11k stars 335 forks source link

Add nullability annotations to DaprClient #523

Open rynowak opened 3 years ago

rynowak commented 3 years ago

Describe the proposal

Once we ingest the .NET 5.0 SDK we we'll be able to add nullability annotations to most of the methods on DaprClient. The reason we didn't do this because is because prior to the C#9 compiler, a core use case didn't work with nullability:

public Task<TValue> DoSomething<TValue>();

There is no supported way (pre C# 9) to say this method returns a task that might return a null without also constraining TValue : class. We didn't want to block the use of value types at a fundamental level especially when records and structs are about to hit.

Now that this barrier has been removed there will be a benefit to adding NNRT annotations.

dlemstra commented 3 years ago

I gave this a try and changed almost everything in the Dapr.Client project. But DaprClientGrpc fails to compile. Details are in the image below. Not sure if this is a bug or that I should implement it differently because the method is abstract? Any ideas @rynowak?

image afbeelding

Small reproducable test case that fails to compile:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

#nullable enable

namespace Dapr.Client
{
    abstract class Class1
    {
        public abstract Task<T?> CompilationError<T>();
    }
    class Class2 : Class1
    {
        public override Task<T?> CompilationError<T>()
        {
            throw new NotImplementedException();
        }

        public Task<T?> ThisWorks<T>()
        {
            throw new NotImplementedException();
        }
    }
}
rynowak commented 3 years ago

Thanks @dlemstra - I would have expected this to work as well. I was able to track down the documentation for this. https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/unconstrained-type-parameter-annotations

I wonder if we need to use where T : default on the overrides. Other than the examples, I don't really have a good sense of when that is needed 🤓

If you are interested in taking this on, it might be best to do it in chunks and review each stage separately. Maybe start with something simple like bindings. I'd hate for you to take the trouble of changing everything before we agree on design.

rynowak commented 3 years ago

Note for myself in the future - when we do start rolling this out, we'll want make an announcement about how we're positioning it:

dlemstra commented 3 years ago

The where T : default solution seemed to work @rynowak. I also created the first PR for this with one of the small libraries. Can you clarify what you mean with the bindings?

philliphoff commented 1 year ago

@halspang Do you think there's any interest in this still? I just ran into a bug in my own application as a result of a wayward null that would have been caught with proper annotations.

frankbuckley commented 1 year ago

@halspang / @philliphoff - any update on this? it would be helpful. would you accept a PR?