[IronPython] Operator overloading, and implicit conversion from Double to Single in operators

Dino Viehland dinov at exchange.microsoft.com
Tue Jun 17 21:57:18 CEST 2008


Great question.  The reason why operators get treated differently due to things like:

[2, 3] * 2.0

For this call we cannot coerce the float into an int by Python semantics.  Compare this to:

xrange(2.0)

which is allowed (but in CPython issues a warning).

So in general Python seems to be more restrictive on binary operators then it does on method calls.  We've mirrored this behavior in IronPython through our support of .NET operator overloading.  That allows us to implement the standard Python semantics in a manner which .NET understands - for example our List class implements operator * and a C# programmer could do someList * 3.  We then just automatically expose these operators out to Python in a way which Python expects - including returning NotImplemented if the parameters aren't compatible.

We could look at relaxing this in the future (in particular for non-Python types) but I think we have bigger fish to fry for the immediate future - and it might just make things that much more confusing as well.  If it's particularly troublesome I'd suggest opening a feature request on CodePlex so we can gauge how many people it's affecting by keeping track of the votes.

-----Original Message-----
From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of Korbinian Abenthum
Sent: Tuesday, June 17, 2008 8:12 AM
To: Discussion of IronPython
Subject: [IronPython] Operator overloading, and implicit conversion from Double to Single in operators

Hi

I basically have the same problem as in http://www.codeplex.com/IronPython/WorkItem/View.aspx?WorkItemId=939

A struct like:
  public struct Test
  {
    public float a;
    public Test(float a)
    {
      this.a = a;
    }
    public static Test operator *(float lscalar, Test test)
    {
      return new Test(lscalar * test.a);
    }
    public static Test mul(float lscalar, Test test)
    {
      return new Test(lscalar* test.a);
    }
    public override string ToString()
    {
      return "Test("+a+")";
    }
  }

If I execute in IronPython:
>>> 6 * Test(1.7)
<Test object at 0x000000000000002F [Test(10.2)]>

>>> Test.mul(6.5, Test(1.7))
<Test object at 0x0000000000000030 [Test(11.05)]>

>>> 6.5 * Test(1.7)
unsupported operand type(s) for *: 'float' and 'Test'
   at _stub_$695##312(Closure , CallSite , CodeContext , Double , Object )
   at _stub_MatchCaller(Object , CallSite , Object[] )
   at Microsoft.Scripting.Actions.CallSite`1.UpdateAndExecute(Object[] args)
   at Microsoft.Scripting.Actions.UpdateDelegates.Update3[T,T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
   at Initialize$694##311(Closure , CodeContext )
   at Microsoft.Scripting.ScriptCode.Run(CodeContext context)
   at Microsoft.Scripting.ScriptCode.Run(Scope scope)
   at Microsoft.Scripting.SourceUnit.Execute(Scope scope, ErrorSink errorSink)
   at Microsoft.Scripting.Hosting.ScriptSource.Execute(ScriptScope scope) [...]
TypeError: unsupported operand type(s) for *: 'float' and 'Test'


The comment in the issue quoted above says that the exception is by design,
since the operator is only defined for a float. And indeed,

>>> System.Single(6.5) * Test(1.7)
<Test object at 0x0000000000000031 [Test(11.05)]>

works just fine.
What I don't understand is why there should be a difference in implicit
conversion of python numbers depending on if it's used in a constructor,
a function or an operator. Is there a reason for that?

Cheers,
 Korbinian
_______________________________________________
Users mailing list
Users at lists.ironpython.com
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com



More information about the Ironpython-users mailing list