Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have to explicitly specify my type arguments for Func parameters?

I am writing a simple Memoize helper that allows caching method results instead of computing them every time. However, when I try to pass a method into Memoize, the compiler can't determine the type arguments. Aren't they obvious from my method signature? Is there a way around this?

Sample code:

using System;
using System.Collections.Concurrent;

public static class Program
{
    public static Func<T, V> Memoize<T, V>(Func<T, V> f)
    {
        var cache = new ConcurrentDictionary<T, V>();
        return a => cache.GetOrAdd(a, f);
    }

    // This is the method I wish to memoize
    public static int DoIt(string a) => a.Length;        

    static void Main()
    {
        // This line fails to compile (see later for error message)
        var cached1 = Memoize(DoIt);

        // This works, but is ugly (and doesn't scale to lots of type parameters)
        var cached2 = Memoize<string, int>(DoIt);
    }
}

Error message:

error CS0411: The type arguments for method 'Program.Memoize<T, V>(Func<T, V>)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
like image 435
Alexei S Avatar asked Mar 23 '18 09:03

Alexei S


People also ask

What are the types of function arguments in Python?

Give an example. What are the types of function arguments in Python? Hence, we conclude that Python Function Arguments and its three types of arguments to functions. These are- default, keyword, and arbitrary arguments. Where default arguments help deal with the absence of values, keyword arguments let us use any order.

How many arguments can a function expect from a function?

By default, a function must be called with the correct number of arguments. Meaning that if your function expects 2 arguments, you have to call the function with 2 arguments, not more, and not less.

What is an argument in a function?

An argument is the value that are sent to the function when it is called. By default, a function must be called with the correct number of arguments. Meaning that if your function expects 2 arguments, you have to call the function with 2 arguments, not more, and not less.

Why does the generic and() method work without type arguments?

What makes me confused is that the generic And () method works without specifying the type arguments explicitly Basically, type inference for generic type parameters works based on the arguments you pass to the method. So And () works, because you're passing in an isAdult.


1 Answers

Isn't DoIt() signature compatible with Func<string, int>?

Yes it is. It's fine to convert it to that specific type, like this for example:

Func<string, int> func = DoIt;
var cachedDoit = Memoize(func);

The problem you're running into is that type inference basically doesn't work particularly well with method group conversions. When you pass DoIt as an argument, that's a method group. In your case it only refers to a single method, but it could refer to multiple methods, with different signatures... and that complicates things.

I often see this come up with LINQ, where I'd like to call foo.Select(SomeMethodGroup), but type inference fails. There's some support for method groups within type inference, but it's not everything we might want it to be.

This isn't a matter of the C# team being lazy... type inference is hugely complicated, and any change is really fraught with danger in terms of backward compatibility. It's in section 7.5.2 of the C# 5 specification if you want to have a look - but frankly that's part of the spec where I get lost really quickly.

like image 103
Jon Skeet Avatar answered Oct 19 '22 22:10

Jon Skeet