Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write my wrapper class to use partial generic type inference?

This is related to this question.

I'd like to create a generic wrapper class:

public abstract class Wrapper<T>
{
    internal protected T Wrapped { get; set; }
}

With the following extensions:

public static class WrapperExtensions
{
    public static W Wrap<W,T>(this T wrapped) where W:Wrapper<T>,new()
    {
        return new W {Wrapped = wrapped};
    }

    public static T Unwrap<T>(this Wrapper<T> w)
    {
        return w.Wrapped;
    }
}

Now assume a concrete Wrapper:

public class MyIntWrapper : Wrapper<int>
{
    public override string ToString()
    {
        return "I am wrapping an integer with value " + Wrapped;
    }
}

I would like to call the Wrap extension like this:

MyIntWrapper wrapped = 42.Wrap<MyIntWrapper>(); 

This is not possible because in c# we need to provide both type arguments to the Wrap extension. (it's all or nothing)

Apparently partial inference is possible in F#.

How would the above code look in F#?

Would it be possible to use it from C#?

like image 566
3dGrabber Avatar asked Dec 11 '22 19:12

3dGrabber


2 Answers

Apparently partial inference is possible in F#.

Yes, only W would need to be specified in your example. T will be inferred.


How would the above code look in F#?

[<AbstractClass>]
type Wrapper<'a>() =
    [<DefaultValue>]
    val mutable internal Wrapped : 'a

let Wrap<'W,'T when 'W :> Wrapper<'T> and 'W: (new: unit -> 'W)> (wrapped: 'T): 'W = 
    let instance = new 'W()
    instance.Wrapped <- wrapped
    instance

let Unwrap (w: Wrapper<_>) = w.Wrapped

type MyIntWrapper() =
    inherit Wrapper<int>()
    override this.ToString() = 
        sprintf "I'm wrapping an integer with value %d" this.Wrapped

And you can call Wrap from F# interactive this way

> let wrapped = Wrap<MyIntWrapper,_> 5;;
val wrapped : MyIntWrapper = I'm wrapping an integer with value 5

In my opinion this is not very idiomatic in F#, I would rather use Discriminated Unions and Pattern Matching for wrapping/unwrapping but I don't know exactly what's your specific case.


Would it be possible to use it from C#?

Sure, but if you call Wrap from C# you're back to C# type inference and will have to specify the second type parameter.

like image 164
Gus Avatar answered Dec 28 '22 06:12

Gus


Implement custom implicit conversion:

MSDN sample

struct MyIntWrapper
{
    public MyIntWrapper(int value) 
    {
        this.value = value; 
    }

    static public implicit operator MyIntWrapper(int value)
    {
        return new MyIntWrapper(value);
    }

    static public explicit operator int(MyIntWrapper wrapper)
    {
         return wrapper.value;
    }

    private int value;
}

You can then write:

MyIntWrapper wrapped = 42;
like image 37
Jakub Konecki Avatar answered Dec 28 '22 08:12

Jakub Konecki