[IronPython] Immutable value types, again

drew moore drew at astro.pas.rochester.edu
Wed May 16 14:40:35 CEST 2007


M. David Peterson wrote:
> Okay, I'm up for the task,
>
> Me: "you fool, you just need to cast it to a ref type and then you can
> mutate it all
> you want. When you need the val type, just cast it back. Didn't you read
> the tutorial??"
>   
Hee hee. Wish I'd thought of that.
I was poking around for some sort of way out in this direction, originally.
Perhaps this console session might help illustrate where I got stuck.

 >>> model = k3d.CModelClass()
 >>> sphere = model.CreateSphere(1.0)
 >>> pos = sphere.position
 >>> pos.X, pos.Y, pos.Z
(0.0, 0.0, 0.0)
 >>> pos.X = 3.0
Traceback (most recent call last):
File , line 0, in <stdin>##50
ValueError: Attempt to update field 'X' on value type 'tVector'; value 
type fields cannot be directly modified
 >>> pos.__class__
<type 'tVector'>
 >>> tVector = pos.__class__
 >>> pos = tVector(1,2,3)
Traceback (most recent call last):
File , line 0, in <stdin>##32
File , line 0, in DefaultNew##18
TypeError: default __new__ does not take parameters
 >>> pos = tVector((1,2,3))
Traceback (most recent call last):
File , line 0, in <stdin>##33
File , line 0, in DefaultNew##34
TypeError: default __new__ does not take parameters
 >>> pos = tVector(X=1,Y=2,Z=3)
Traceback (most recent call last):
File , line 0, in <stdin>##35
File , line 0, in DefaultNewClsKW##39
ValueError: Attempt to update field 'X' on value type 'tVector'; value 
type fiel
ds cannot be directly modified

Dang. That last one *almost* worked? (can you make just the KW 
constructor work, guys?)

 >>> dir(pos)
['Equals', 'Finalize', 'GetHashCode', 'GetType', 'MakeDynamicType', 
'MemberwiseC
lone', 'Reduce', 'ReferenceEquals', 'ToString', 'X', 'Y', 'Z', 
'__class__', '__d
oc__', '__init__', '__module__', '__new__', '__reduce__', 
'__reduce_ex__', '__re
pr__', '__str__']

I have no instance methods for getting and setting, so I appear to be 
out of luck. Value types are apparently always sealed, so I can't even 
subclass it in C# to add them. I need to write a proxy.
I have no idea if MakeDynamicType does what I imagine it might do. I'm 
pretty sure it won't, but it's the most promising thing I can see on my 
object. Easier to ask forgiveness!!

 >>> pos.MakeDynamicType()
Traceback (most recent call last):
File , line 0, in <stdin>##52
TypeError: MakeDynamicType() takes exactly 0 arguments (1 given)
 >>> pos.MakeDynamicType
<built-in method MakeDynamicType of tVector object at 0x000000000000002D>
 >>> tVector.MakeDynamicType()
Traceback (most recent call last):
File , line 0, in <stdin>##55
TypeError: descriptor 'MakeDynamicType' of 'object' needs an argument
 >>> tVector.MakeDynamicType(pos)
Traceback (most recent call last):
File , line 0, in <stdin>##56
TypeError: MakeDynamicType() takes exactly 0 arguments (1 given)
 >>>

I'm shooting in the dark here.
In any event, the last two errors seem to contradict each other, don't they?

I'm guessing that

http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython&title=Value%20Types

has my answer:
> This renders value types “mostly” immutable; updates are still 
> possible via instance methods on the value type itself.
I have no instance methods on this struct. Therefore, I can't mutate it 
in *any* way from IronPython, even though mutating it is some of the 
most trivial code imaginable in C#. I'd be ready to crawl under a rock 
if I was trying to sell IronPython to some C# programmers and I had to 
explain this one!
> This is where you come in: we’d like to know whether these changes 
> impact your scenarios and if so what facilities we could provide in 
> order to address the situation. We’d also appreciate knowing that this 
> change doesn’t impact you at all so we can get a clearer view of the 
> big picture.
I *do* think the "draconian" immutable value types decision was the 
right (ok, safe) one to make *at the time.* Without *some* facility for 
creating new instances of value types from pure IronPython, (like a 
working KW args constructor) I'm not sure it is a good long-term solution.

Clearer big picture: After one year, we have learned that not many 
people are having trouble with this. That means, perhaps, that not many 
people are using value types from IronPython? (good interfaces avoid 
them!) That means, perhaps, if value types *were* mutable in IronPython, 
not many people would notice *that* either?

Hey, here's another try. "It's Python. Its a dynamic language. We *have* 
to write unit tests. The bug we are trying to prevent will not stay in 
our code for very long, because our unit tests will catch it."

;-)

cheers

Drew




More information about the Ironpython-users mailing list