Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Create bindings between existing classes and existing interfaces #2643

Closed
TheUnlocked opened this issue Jul 10, 2019 · 4 comments
Closed

Comments

@TheUnlocked
Copy link

TheUnlocked commented Jul 10, 2019

This is a proposal to add some kind of "bind" declaration (the name can be changed if people prefer something else), where one can create a binding between a class and an interface such that the class can be used as though it implemented the interface in code where the binding is accessible. Here's an example of what this might look like:

// Assembly A
public class Foo {
    public int val;
    public Foo(int i){
        val = i;
    }

    public void MethodA() {}
    public void MethodB() {}
    public void MethodC() {}
}

// Assembly B
public interface IBar {
    void SomethingA();
    int SomethingB();
    void SomethingC(int x);
}


// Your Assembly

// this syntax was thrown together quickly, so that can be changed.
public bind Foo : IBar {
    void SomethingA() => MethodA();
    int SomethingB() { MethodB(); return val; } // only public fields and methods are accessible. 
    void SomethingC(int x) => MethodC();
}

// The binding can be used as such...

Foo foo = new Foo(3);
IBar bar = foo;
bar = new Foo(4);
foo = (Foo)bar;

The bind declaration automatically generates:

[ClassInterfaceBinding(typeof(Foo), typeof(IBar))] // Exposes this binding to other assemblies.
                                                   // There may be another way to do this that I'm not aware of.
struct _BindFooIBar : IBar {
    private Foo _instance;
    public _BindFooIBar(Foo instance) {
        _instance = instance;
    }

    public void SomethingA() => _instance.MethodA();
    public int SomethingB() { _instance.MethodB(); return _instance.val; }
    public void SomethingC(int x) => _instance.MethodC();

    public static explicit operator Foo(_BindFooIBar v) => v._instance;
    public static explicit operator _BindFooIBar(Foo v) => new _BindFooIBar(v);
}

And the usage magically translates to:

Foo foo = new Foo(3);
IBar bar = (_BindFooIBar)foo;
bar = (_BindFooIBar)new Foo(4);
foo = (Foo)(_BindFooIBar)bar;

While in some ways similar, this proposal is not covered by shapes. "Extension everything" also does not cover this proposal to my knowledge, though this proposal could theoretically be merged into "extension everything."

Outstanding questions:

  • What should be done if multiple namespaces provide the same binding? With extension methods it simply blocks you from using that extension method. Would doing the same make sense for bindings?
@Joe4evr
Copy link
Contributor

Joe4evr commented Jul 10, 2019

Isn't this literally what Shapes is trying to achieve? #164

@TheUnlocked
Copy link
Author

TheUnlocked commented Jul 10, 2019

Almost, but not quite. This would allow binding a class to an interface that already exists. To my understanding (which may be wrong), an API must ask for a shape in order to support shapes being used. If it only asks for an interface, you can't treat that interface as if it was a shape.

@yaakov-h
Copy link
Member

I think this was discussed in #164 or similar threads, but it has bad implications for things like object equality, e.g.:

Foo foo = new Foo(3);
IBar bar1 = (_BindFooIBar)foo;
IBar bar2 = (_BindFooIBar)foo;

bar1 == bar2 // returns false

@YairHalberstadt
Copy link
Contributor

I think is suitable covered by the championed #1711

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants