Skip to content
This repository has been archived by the owner on Mar 9, 2021. It is now read-only.

ElementCollection implementing IEnumerable<Element> #15

Open
n9 opened this issue Mar 2, 2014 · 8 comments
Open

ElementCollection implementing IEnumerable<Element> #15

n9 opened this issue Mar 2, 2014 · 8 comments

Comments

@n9
Copy link

n9 commented Mar 2, 2014

What about to add interface IEnumerable<Element> to ElementCollection (and maybe other similar collections)?

@erik-kallen
Copy link
Contributor

Unfortunately, that is not possible because they do not comply with the contract for IEnumerable<T> (have a method called getEnumerator that returns an object with methods moveNext and get_current). But somewhat related to Saltarelle/SaltarelleCompiler#159

@n9
Copy link
Author

n9 commented Mar 2, 2014

What about to provide something like external interfaces. When an extenal interface is obtained from the class:

// C#
IEnumerable<Element> Foo(ElementCollection elements)
{
  return elements;
}

The compiler will create a wrapper:

// JavaScript
function foo(elements) {
  return new ElementCollectionEnumerable(elements);
}

@erik-kallen
Copy link
Contributor

It is a good idea, I have been thinking something similar myself. However, I don't think the ElementCollectionEnumerable idea will work (I do not want users to be required to add additional JS to use the web reference assembly), but I think the generated code could be something like

function foo(elements) {
    return ss.mkInterface(elements, { 'getEnumerator': function() { return new ArrayEnumerator(elements) });
}

or something like that. This could also be used for things like (illegal today)

interface IA { int Value { get; } }
interface IB { int Value { get; } }
class C : IA, IB {
    int IA.Value { get { return 0; } }
    int IB.Value { get { return 1; } }
}

by causing an identity conversion from C to IA and/or IB to generate such proxy interface type.

Notes for implementation:

  1. ss.referenceEquals() should be fixed to ensure that the proxies are considered reference equal to both other proxies for the same object as well as the object itself.
  2. ss.cast() and families need to support this as well,
  3. We need to somehow handle type parameter conversions. We don't want to end up in a situation where
class G<T> where T : IEnumerable<object> {
    void M(T t) {
        var e = t.GetEnumerator();
    }
}

fails for G<ElementCollection>.

@ProdigySim
Copy link
Contributor

In the meantime, putting an extension method on ElementCollection and/or other classes with methods returning them might be a simple fix for you n9. I use something like this

public static class ElementCollectionExtensions
{
    public static IEnumerable<Element> AsEnumerable(this ElementCollection elements)
    {
        return Enumerable.From(elements).Select(e => Script.Reinterpret<Element>(e));
    }

    public static IEnumerable<Element> GetChildren(this Element e)
    {
        return e.Children.AsEnumerable();
    }
}

Being able to define some sort of implicit cast for ElementCollection could also be helpful, but I don't really know if that's possible through extensions in C#.

@erik-kallen
Copy link
Contributor

Unfortunately it is not possible to define conversion operators to and from interfaces in C#, otherwise that would have probably been the best solution

@n9
Copy link
Author

n9 commented Mar 5, 2014

I do not want users to be required to add additional JS to use the web reference assembly

My idea is to specify the behavior using attributes.

One attribute could be:

[ExplicitExternalInterface(typeof(IEnumerable<Element>), typeof(ElementCollectionEnumerable))]

where ElementCollectionEnumerable is a class with constructor with single parameter of type that must be assignable from the class on which the attribute is applied.

The other attribute could be:

[ImplicitExternalInterface(typeof(IEnumerable<Element>))]

in this case the external interface implementation is composed from the methods (e.g. with inline code) which are present on the class.

@erik-kallen
Copy link
Contributor

Where is your ElementCollectionEnumerable class defined? And I do not really see any point for the ImplicitExternalInterface attribute; the metadata importer can find this out by itself

@n9
Copy link
Author

n9 commented Mar 5, 2014

Somewhere in C#:

public class ElementCollectionEnumerable : IEnumerable<Element>
{
  public ElementCollectionEnumerable(ElementCollection elements)
  {
     // ...
  }

  //...
}

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

No branches or pull requests

3 participants