Schwab,Wilhelm K wrote:
Ben,

That's a lot to read. If I'm getting the message, you want to subclass ODBCRow and are concerned about Metacello.
Point taken. In hindsight too much background info and a mixed message. Actually it wasn't not a question about Metacello - though my other recent mention of ConfigurationOfODBC was. I only mentioned ConfigurationOfODBC here to distinguish it from the ODBC in DBXTalk - and in hindsight that is not the core question. The short version is "how do I change the class of existing object into one of its subclasses". I've got it working, but not if I add an instance variable to the subclass.
FWIW, I suspect I would make some type of wrapper class for the rows rather 
than subclass - the goal being to strive for uses-a vs. is-a.
I had considered that briefly but was concerned that the wrapped class needed to understand every message that the wrapped-class understood. I wanted to use the existing ODBCResultTable which holds the ODBCRows to contain my new subclass of ODBCRow. I will think further about this.
Idealistically (and perhaps naively) yours,
More than I would know. Thanks for your time. -Ben
Bill


________________________________________
From: [email protected] 
[[email protected]] on behalf of Ben Coman 
[[email protected]]
Sent: Tuesday, December 27, 2011 11:46 PM
To: [email protected]
Subject: [Pharo-project] changing the class of an existing object to a  subclass

greetings all,

I am using ConfigurationOfODBC in Pharo 1.3.  I have had success with
getting an ODBCResultTable(OrderedCollection) containing ODBCRow
containing about 30 fields.  By default the fields are accessed by "row
at: #fieldName" but I wanted to add some convenience methods to instead
go "row fieldName."  My searching and experimentation led me to
subclassing ODBCRow as EAPPackage and then using "adoptInstance:" on
each ODBCRow to convert it to the subclass.  This was to avoid having to
having to understand and change any of the ConfigurationOfODBC code.  I
had tried copyFrom: but some of the instance variables inherited from
ODBCRow were not filled in, generating exceptions in some of the
inherited methods. I had also considered "become:" but that didn't seem
appropriate.

Using "adoptInstance:" worked fine until I added a new instance variable
to EAPPackage.  Subsequently for "<primitive: 160 error: ec>", ec =
#'bad receiver'.  The "adoptInstance:" method comment says it follows
the same rules as "primitiveChangeClassTo:" (yet note that
"primitiveChangeClassTo:" never worked)
The "primitiveChangeClassTo:" method comment says "The primitive will
fail in most cases that you think might work [...] The facility is
really provided for certain, very specific applications (mostly related
to classes changing shape) and not for casual use" so I wondered if
there was another way to achieve this.

The full code is hopefully not too long to include for reference below.
The use of "adoptInstance:" in the last section listed.
------
ODBCRow subclass: #EAPPackage
    instanceVariableNames: 'parent'   "note adoptInstance works without
this instance variable, and not with"
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BTC-EA-Explore'
------
EAPPackage >> name
    ^ self at: #Name
------
ODBCResultTable subclass: #EAPPackages
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'BTC-EA-Explore'
------
EAPPackages class >> newFromConnection: connection
    | packages parent |
    packages := (connection query: 'select * from t_package;') execute
asTable.
    self adoptInstance: packages.

    packages do: [ :row | EAPPackage adoptInstance: row. ].

    ^packages.
------
In a Workspace I successfully evaluate the following three lines without :
   connection := ODBCConnection dsn: 'CIM' user: '' password: ''.
   packages := EAPPackages newFromConnection: connection.
   connection close.
------

I found the ODBCRow instance creation to ODBCResultSet>>fetchRow.  One
alternative I've considered is to somehow pass through a custom
SomeClass in a variable to replace the hard reference to ODBCRow - but I
don't want to chase back all the cascading call references.

Is there another way to change an existing object to another class, such
that it can be specialised with both additional  methods and instance
variables?
I would appreciate any pointers.

regards, Ben





Reply via email to