In Python, you can do this simply by re-assigning the __class__. I'm
not convinced that your type system makes sense, here though. Any
reasonable ORM should be able to persist and reload an object without
losing the type information. Perhaps it's just a blind spot in the way
I think about types. Assuming that the limitations of your ORM are
external and out of your control, I would still ensure that whatever
generic objects are being loaded from the ORM are converted into
"real" objects of the correct type as soon as possible. For example,
if you're persisting a file, you might just save the filename, and
your ORM might return a string of the filename. I would want to
convert that back into a file object ASAP, rather than writing all my
code to accept either a FLO or a string and converting then.
If you know what to upcast something to, then you know what type it
is. If you know what type it is, then (in Python) you can simply
assume it is of that type.
Probably being more specific would help in this case ;-)
What I'm doing is implementing an object-publishing mechanism in my
template engine (Breve). The type decision isn't known until the moment
of rendering (i.e. in the template itself). Say for instance a set of
records is pulled from the ORM (SQLAlchemy in this case) and that these
records represent articles in a blog. These records, until they hit the
template, have no real representation in HTML. The decision about how
to present them is up to the template. The dispatch mechanism I
referred to earlier is a way that I allow users of the template system
to register how a particular object should be rendered in HTML (a
"flattener"). This allows commonly represented objects to be used
without a lot of template clutter.
However, if you consider the case of a blog, then if the template
receives a list of articles, it would seem reasonable to present those
articles in at least two ways: first as a table of contents in the page
gutter, and then perhaps as two or three summaries in the main part of
the page. But this isn't known to the lower layers of the application,
only to the template. Therefore it would be nice if the template user
could register two classes with the flattener, both representations of
the original object but simply with a different type.
I'll give a concrete example:
class Person: # assume this is something from the ORM
name = "Kenny"
class PersonRow ( Person ):
pass
def flatten_person ( p ):
return "<span>omg, you've killed %p</span>" % p.name
def flatten_personrow ( p ):
return "<tr><td>%s</td></tr>" % p.name
register_flattener ( PersonRow, flatten_personrow )
register_flattener ( Person, flatten_person )
Now, assuming a list of Person records were passed in as 'persons', then
in the template the template author could simply use:
div [
# show the first person
persons [ 0 ],
# show a table of all persons
table [
[ PersonRow ( p ) for p in persons ]
]
]
What you're describing is a disjoint between your actual type system
(that is, the one you have in code) and your theoretical type system
(the one that you model your code around). To me, this is a huge red
warning flag.
What I'm describing is a disjoint between how I want my template engine
to be used (I tend to build backwards, writing the desired template code
and then the engine code to support that use) and what can be easily and
efficiently achieved. But yes, in a way you are correct since my
theoretical type system is constrained by Python's type system (Breve
templates are Python expressions).
That being said, I'm certain I'll come up with a solution that doesn't
bug me too much, it's just that the "obvious" solution doesn't exist
(type casting).