Hi,

As far as I can see, the "in" operator should return true if any object in the 
enumerable is "equal" to the object given as reference:

IronPython 2.7.5 (2.7.5.0) on .NET 4.0.30319.34209 (32-bit)
Type "help", "copyright", "credits" or "license" for more information.
>>> t = (1,2)
>>> o = (t, 3, "4", 1024)
>>> 1024 in o
True
>>> "4" in o
True
>>> (1,2) in o
True
>>> t in o
True
>>> a = 2**100
>>> b = 2**100
>>> a in (b,)
True
>>> a is b
False
>>> import System
>>> g = System.Guid.NewGuid()
>>> h = System.Guid(g.ToString())
>>> g == h
True
>>> g is h
False
>>> g in (h,)
True


However, it looks like this is not working correctly with 
IDynamicMetaObjectProvider implementations.

I attached an example which is a stripped down case of some much more complex 
real world code[1]. In that case, the assertion in the last line fails although 
a equals b.

# a and b are provided by the host written in C#
assert a == b, 'a equals b'
assert not a is b, 'a is not b'

assert a in (a,), 'a is in (a,)'
assert a in (b,), 'a is in (b,)' # this one fails...

As far as I can see via breakpoints, the Equals methods of the objects are 
never actually called, except on the first assertion with the == operator.

[1] In the real world code, arbitrary plugins may provide extensions to 
extendable objects from other plugins, to dynamically (at run-time) add methods 
and properties to those instances.

Best regards

Markus Schaber

CODESYS(r) a trademark of 3S-Smart Software Solutions GmbH

Inspiring Automation Solutions

3S-Smart Software Solutions GmbH
Dipl.-Inf. Markus Schaber | Product Development Core Technology
Memminger Str. 151 | 87439 Kempten | Germany
Tel. +49-831-54031-979 | Fax +49-831-54031-50

E-Mail: m.scha...@codesys.com | Web: http://www.codesys.com | CODESYS store: 
http://store.codesys.com
CODESYS forum: http://forum.codesys.com

Managing Directors: Dipl.Inf. Dieter Hess, Dipl.Inf. Manfred Werner | Trade 
register: Kempten HRB 6186 | Tax ID No.: DE 167014915

This e-mail may contain confidential and/or privileged information. If you are 
not the intended recipient (or have received
this e-mail in error) please notify the sender immediately and destroy this 
e-mail. Any unauthorised copying, disclosure
or distribution of the material in this e-mail is strictly forbidden.

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;

public class ScriptExecutor
{
        private const string SRC = @"
assert a.bar();

assert a.extension1() == 0;

assert a == b, 'a equals b'
assert not a is b, 'a is not b'

assert a in (a,), 'a is in (a,)'
assert a in (b,), 'a is in (b,)'
";

        private static void Main()
        {
                try
                {
                        ScriptEngine engine = Python.CreateEngine();
                        ScriptSource scriptSource = 
engine.CreateScriptSourceFromString(SRC, "test.py");

                        
engine.Runtime.LoadAssembly(typeof(ScriptExecutor).Assembly);

                        ScriptScope scope = engine.CreateScope();

                        scope.SetVariable("a", new Foo().Extender);
                        scope.SetVariable("b", new Foo().Extender);

                        scriptSource.Execute(scope);
                }
                catch (Exception ex)
                {
                        Console.WriteLine(ex);
                }
                finally
                {
                        Console.WriteLine("Script Finished");
                        Console.ReadLine();
                }
        }
}

public interface IFoo : IBaseObject<IFoo>
{
        bool bar();
}

public class Foo : IFoo
{
        public Foo()
        {
                this.Extender = ExtendedObject<IFoo>.Create(this);
        }

        public override bool Equals(object obj)
        {
                return true;
        }

        public bool Equals(Foo other)
        {
                return true;
        }

        public override int GetHashCode()
        {
                return 0;
        }

        public bool bar()
        {
                return true;
        }

        public IExtendedObject<IFoo> Extender
        {
                get;
                private set;
        }

        public bool Equals(IFoo other)
        {
                return true;
        }

        public bool Equals(IExtendedObject<IFoo> other)
        {
                return true;
        }
}

internal class ExtendedObject<T> : IDynamicMetaObjectProvider, 
IExtendedObject<T>
        where T : IBaseObject<T>
{
        private readonly T BASE_OBJECT;
        internal readonly IList<object> EXTENSIONS = new List<object>();

        private ExtendedObject(T baseObject)
        {
                this.BASE_OBJECT = baseObject;
        }

        #region IDynamicMetaObjectProvider Members

        public DynamicMetaObject GetMetaObject(Expression parameter)
        {
                return new ScriptMetaObject<T>(parameter, 
BindingRestrictions.Empty, this);
        }

        #endregion

        #region IExtendedObject<T> Members

        public T BaseObject
        {
                get { return BASE_OBJECT; }
        }

        public IEnumerable<object> Extensions
        {
                get
                {
                        for (int i = 1; i < EXTENSIONS.Count - 1; i += 1)
                        {
                                yield return EXTENSIONS[i];
                        }
                }
        }

        #endregion

        // TODO: Cacheing of ExtendableTypes...
        internal static ExtendedObject<T> Create(T baseObject)
        {
                ExtendedObject<T> result = new ExtendedObject<T>(baseObject);

                // We put the base object into search path s_first so that 
exceptions are mapped to the
                // correct type.
                result.EXTENSIONS.Add(baseObject);

                // In the real code, a bunch of extensions is fetched from the 
plugin manager.
                result.EXTENSIONS.Add(new Extension1());                

                // We also put the base object into the search past s_last so 
that the base object overrides
                // extension objects.
                result.EXTENSIONS.Add(baseObject);              

                return result;
        }

        public override string ToString()
        {
                return BASE_OBJECT.ToString();
        }

        public override bool Equals(object obj)
        {
                return BASE_OBJECT.Equals(obj);
        }

        public override int GetHashCode()
        {
                return BASE_OBJECT.GetHashCode();
        }
}

internal static class MyDynamicObjectOps<T>
        where T : IBaseObject<T>
{
        public static object GetPlugin(object myDo, int index)
        {
                return ((ExtendedObject<T>)myDo).EXTENSIONS[index];
        }

        internal static MethodInfo GetPluginMethod = 
typeof(MyDynamicObjectOps<T>).GetMethod("GetPlugin");
}

internal class ScriptMetaObject<T> : DynamicMetaObject
        where T : IBaseObject<T>
{
        public ScriptMetaObject(Expression parameter, BindingRestrictions 
restrictions, ExtendedObject<T> value)
                : base(parameter, restrictions, value)
        {
        }

        public new ExtendedObject<T> Value
        {
                get
                {
                        return (ExtendedObject<T>)base.Value;
                }
        }

        public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder 
binder, DynamicMetaObject[] args)
        {
                DynamicMetaObject boundMember = null;

                for (int i = 0; i < Value.EXTENSIONS.Count; i++)
                {
                        DynamicMetaObject pluginDo = new DynamicMetaObject(
                                Expression.Call(
                                        MyDynamicObjectOps<T>.GetPluginMethod,
                                        Expression,
                                        Expression.Constant(i)
                                ),
                                
BindingRestrictions.GetInstanceRestriction(this.Expression, Value),
                                Value.EXTENSIONS[i]
                        );

                        boundMember = binder.FallbackInvokeMember(pluginDo, 
args, boundMember);
                }

                return boundMember;
        }

        public override DynamicMetaObject BindSetMember(SetMemberBinder binder, 
DynamicMetaObject value)
        {
                DynamicMetaObject boundMember = null;

                for (int i = 0; i < Value.EXTENSIONS.Count; i++)
                {
                        DynamicMetaObject pluginDo = new DynamicMetaObject(
                                Expression.Call(
                                        MyDynamicObjectOps<T>.GetPluginMethod,
                                        Expression,
                                        Expression.Constant(i)
                                ), 
BindingRestrictions.GetInstanceRestriction(this.Expression, Value), 
Value.EXTENSIONS[i]);

                        boundMember = binder.FallbackSetMember(pluginDo, value, 
boundMember);
                }

                return boundMember;
        }

        public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
        {
                DynamicMetaObject boundMember = null;

                for (int i = 0; i < Value.EXTENSIONS.Count; i++)
                {
                        DynamicMetaObject pluginDo = new 
DynamicMetaObject(Expression.Call(
                                        MyDynamicObjectOps<T>.GetPluginMethod,
                                        Expression,
                                        Expression.Constant(i)
                                ), 
BindingRestrictions.GetInstanceRestriction(this.Expression, Value), 
Value.EXTENSIONS[i]);

                        boundMember = binder.FallbackGetMember(pluginDo, 
boundMember);
                }

                return boundMember;
        }

        public override DynamicMetaObject 
BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
        {
                // Currently only supported for equality (python == operator) 
equality, we bind to the base object only.
                DynamicMetaObject baseDo = new 
DynamicMetaObject(Expression.Call(
                                        MyDynamicObjectOps<T>.GetPluginMethod,
                                        Expression,
                                        Expression.Constant(0)
                                ), 
BindingRestrictions.GetInstanceRestriction(this.Expression, Value), 
Value.EXTENSIONS[0]);

                return binder.FallbackBinaryOperation(baseDo, arg, null);
        }
}
public interface IExtendedObject<T>
        where T : IBaseObject<T>
{
        T BaseObject { get; }

        IEnumerable<Object> Extensions { get; }
}

public interface IBaseObject<T> : IEquatable<T>, IEquatable<IExtendedObject<T>>
        where T : IBaseObject<T>
{
        IExtendedObject<T> Extender { get; }
}

public class Extension1
{
        public int extension1() { return 0; }
}
_______________________________________________
Ironpython-users mailing list
Ironpython-users@python.org
https://mail.python.org/mailman/listinfo/ironpython-users

Reply via email to