Weird behavior of subclasses of Exception

Allison Randal allison at
Thu Mar 4 17:26:11 UTC 2010

Stephen Weeks wrote:
> The problem I'm seeing is that while that works fine for Exception
> instances, it looks like the keyed access and access using
> {get,set}attribute are going to different places in subclasses of
> Exception.

The two routes are indeed accessing different datastores. Because MyEx 
is a PIR subclass of a C PMC, it goes through a PMCProxy for Exception. 
Any instance of "MyEx" is actually an instance of the Object PMC, and 
you have to look at src/pmc/object.pmc and src/pmc/object.c for the 
vtable functions.

So, direct string key access calls 'get_pmc_keyed' and 'set_pmc_keyed'. 
In Object, these vtable functions (automatically generated, rather than 
implemented in Object) look for a delegated object named 'proxy' (an 
instance of Exception) stored as at attribute in the MyEx object. They 
store and retrieve on this delegated proxy object instead of directly on 
the attributes of the MyEx.

The opcodes 'setattribute' and 'getattribute' on the other hand, call 
'set_attr_str' and 'get_attr_str', which are implemented in the Object 
PMC to always store and retrieve from the object's attribute data store.

Here's where it gets tricky... when 'get_pmc_keyed' or 'set_pmc_keyed' 
is called on the proxy object it does correctly call the vtable function 
in Exception, which then correctly calls 'set_attr_str' and 
'get_attr_str' in Exception, and those in turn are correctly using the 
GET_ATTR/SET_ATTR macros rather than directly manipulating struct 
values. But, because of the way proxying works, at that point the code 
is invoking on a proxy object of type *Exception* rather than an Object 
of the MyEx class. The GET_ATTR/SET_ATTR macros correctly detect that 
they aren't operating on an Object, and so make a direct struct access 
instead of an object attribute store access.

That's the right behavior in most cases, but in this case we're trying 
to get keyed access to act just like attribute access in both the C PMC 
and the PIR subclass.

Overriding 'get_pmc_keyed' and 'set_pmc_keyed' resolves the problem by 
blocking the proxy-behavior and directly using MyEx's 'setattribute' and 

   .namespace ['MyEx']

   .sub 'set_pmc_keyed' :vtable
     .param string name
     .param pmc value
     say "in override of set_pmc_keyed"
     setattribute self, name, value

   .sub 'get_pmc_keyed' :vtable
     .param string name
     .local pmc res
     say "in override of get_pmc_keyed"
     res = getattribute self, name
     .return (res)

The long-term solution is to stop creating automatic delegated proxies 
for C PMC parent classes. We're not quite ready to take that step yet, 
as it requires more unification between C PMCs and PIR classes, but it's 
the direction we're heading.

In the meantime, we can either add 'set_pmc_keyed'/'get_pmc_keyed' 
overrides for each PIR subclass of Exception, or declare that only one 
of the two ways of accessing Exception attributes is part of the 
required API for exception-like objects. For that, I'd take a look at 
the languages we're supporting and decide what's least likely to 
interfere with their native behavior for exceptions. Do Ruby exceptions 
allow hash-key-like access to exception attributes? Do they allow 
object-attribute access to exception attributes? Do they have 
conflicting names with Parrot's exception object attributes? Same 
questions for other languages. I suspect that very few languages access 
exception attributes as hash-keys. It may be that Parrot's exception 
subsystem should be using 'inspect_str' for its access to 
parrot-specific exception attributes, to entirely avoid polluting the 
public API of the exception objects.


More information about the parrot-dev mailing list