[IronPython] Magic methods on CLR types

Dino Viehland dinov at microsoft.com
Fri Dec 4 10:03:53 PST 2009


Yeah, I think I buy your argument on #2.  We'll need to change the way we do resolution to make that happen which is a little scary - I'm inclined to say it'll have to wait until we either figure out exactly how we support normal extension methods or until IronPython 3k when we can make some breaking changes.

From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of Jeffrey Sax
Sent: Wednesday, December 02, 2009 9:19 PM
To: 'Discussion of IronPython'
Subject: Re: [IronPython] Magic methods on CLR types

#1: Ok. And I just found Converter.ConvertToIndex so it's easy enough to do. Great! Thanks.

#2: I think something else is going on. An extension type should not remove functionality, which is what is happening here. Consider this:

[assembly: ExtensionType(typeof(Sliceable), typeof(SliceableExtensions))]
namespace Compatibility.Python {
    public class Sliceable {
        public int this[int index] { get { return index; } }
    }
    public static class SliceableExtensions {
        public static ISlice __getitem__(Sliceable a, ISlice b) { return b; }
    }
}

IronPython 2.6 (2.6.10920.0) on .NET 2.0.50727.4927
Type "help", "copyright", "credits" or "license" for more information.
>>> import clr
>>> clr.AddReferenceToFile("Compatibility.Python")
>>> from Compatibility.Python import *
>>> s = Sliceable()
>>> s[1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected ISlice, got int
>>> s.Item[2]
2
>>> s.Item[10]
10

There is no IList<T> or anything enumerable, just the indexer method. And it's basically hidden by the __getitem__ in the extension type. Item still works, because that's a direct reflection of the CLR type.

Adding an extension type to enable standard Python functionality like slicing for CLR objects seems like a common scenario that, IMHO, should be properly supported, eventually. F# has something similar with type augmentations. Yes, I can just create pass-through methods, but in my view that shouldn't be necessary. (In F#, it isn't, but then there are other limitations.)

Thanks,

Jeffrey

From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of Dino Viehland
Sent: Wednesday, December 02, 2009 10:02 PM
To: Discussion of IronPython
Subject: Re: [IronPython] Magic methods on CLR types

#1 is definitely correct behavior, consider:

IronPython 2.6 (2.6.10920.0) on .NET 2.0.50727.4927
Type "help", "copyright", "credits" or "license" for more information.
>>> class c(object):
...     def __getitem__(self, index):
...             return index
...
>>> c()[0:1.2]
slice(0, 1.2, None)

It's Python's list implementation which is converting indexes to integers so you'll need to do that as well.  You can do that via IronPython.Runtime.Converter.ConvertToIndex though.

On #2 in theory we don't let you override existing members w/ extension members.  But __getitem__ is taking precedence here because we pick up the List<T> version later in resolution via a .NET mapping than looking up members by name.  But you can define the integer overload for __getitem__ and forward it to the real implementation.

We could also consider just adding slicing support for List<T> to IronPython natively :) We probably can't do that for all IList<T>'s though in case there's one that accepts negative or out of range indexes.

From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of Jeffrey Sax
Sent: Wednesday, December 02, 2009 5:39 PM
To: 'Discussion of IronPython'
Subject: Re: [IronPython] Magic methods on CLR types

I found 2 issues:

1. It looks like __index__ is not called for slice arguments of non-Python objects (like List<T>'s). Reading PEP 357 (which introduced __index__), I would expect __index__ to always be called, so that I can be sure that the slice components are either int, long, or NULL. (I haven't verified this in CPython.)

2. If I supply a  __getitem__ method in my extension type (in my case with a strongly typed ISlice parameter), the underlying CLR indexers are no longer picked up.

Extender assembly:

[assembly: ExtensionType(typeof(List<>), typeof(ListExtensions<>))]
namespace Compatibility.Python {
    public static class ListExtensions<T> {
        public static T __getitem__(List<T> a, ISlice slice) {
            return a[(int)slice.Start]; // Dummy
        }
    }
}

IP session 1:
IronPython 2.6 (2.6.10920.0) on .NET 2.0.50727.4927
Type "help", "copyright", "credits" or "license" for more information.
>>> from System.Collections.Generic import List
>>> a=List[int]()
>>> a.Add(55)
>>> a[0]
55
>>> a[0:1.2]
55
>>> b=[1,2,3,4]
>>> b[0:1.2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected index value, got float
>>>

IP session 2:
IronPython 2.6 (2.6.10920.0) on .NET 2.0.50727.4927
Type "help", "copyright", "credits" or "license" for more information.
>>> import clr
>>> clr.AddReferenceToFile("Compatibility.Python")
>>> from System.Collections.Generic import List
>>> a=List[int]()
>>> a.Add(55)
>>> a[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected ISlice, got int
>>>

From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of Dino Viehland
Sent: Tuesday, December 01, 2009 8:57 PM
To: Discussion of IronPython
Subject: Re: [IronPython] Magic methods on CLR types

If you want IronPython to recognize them you just need to create an assembly w/ ExtensionTypeAttribute and have it point at the extended and extending types.  Then the assembly needs to be loaded into the ScriptRuntime using ScriptRuntime.LoadAssembly.

We still need to figure out our story for recognizing and importing normal .NET extension methods that C# supports.

From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of Jeffrey Sax
Sent: Tuesday, December 01, 2009 5:27 PM
To: 'Discussion of IronPython'
Subject: [IronPython] Magic methods on CLR types

Is there a way to add magic methods like __repr__, __call__, etc. to CLR types?


1.       Can it be done in the external CLR assembly without polluting the API for other languages? If so, how?

2.       Can it be done using F# style type augmentations by redefining such methods on the Python type corresponding to the CLR type? If so, how?

3.       If neither of these alternatives is possible, is there a third way?

Thanks!

Jeffrey Sax
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ironpython.com/pipermail/users-ironpython.com/attachments/20091204/d2100623/attachment-0001.htm>


More information about the Users mailing list