On Wed, Dec 28, 2011 at 12:08 PM, Ben Coman <btc@openinworld.com> wrote:
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


Just in case of interest, in DBXTalk you CAN access not only by index but by name.�

rawValueAt: anIndex
��� "It returns the value of the raw at the specified index. No conversion is here, so all values will be String"
��� ^rawValues at: anIndex

rawValueNamed: aString
��� "It returns the value of the raw with the specified name. No conversion is here, so all values will be String"
��� ^self rawValueAt: (self columnIndex: aString)


And you can also get the values and convert them to smalltalk objects:

valueAt: anIndex
��� "It returns the value of the raw at the specified index. Each string returned from openDBX will be converted, if supported, to Squeak types"
��� ^self convertValueAt: anIndex


valueNamed: aString
��� "It returns the value of the raw with the specified name. Each string returned from openDBX will be converted, if supported, to Squeak types"
��� ^self convertValueAt: (self columnIndex: aString).


Cheers
- 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: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] on behalf of Ben Coman [btc@openInWorld.com]
Sent: Tuesday, December 27, 2011 11:46 PM
To: Pharo-project@lists.gforge.inria.fr
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









--
Mariano
http://marianopeck.wordpress.com