PDA

View Full Version : Sub-classing an object at run time: Obj-C




MacDonaldsd
Feb 20, 2008, 02:52 PM
Hi,

Is it possible to subclass an object at runtime. i.e. Can I create an object as the super class and decide what subclass it will become at a later date ?



Catfish_Man
Feb 20, 2008, 03:21 PM
Possible, but very tricky. I wouldn't recommend it if there's any alternative.

yeroen
Feb 20, 2008, 03:46 PM
Is this C++ you're talking about, or Java or Obj-C?

MacDonaldsd
Feb 20, 2008, 03:47 PM
Oh sorry forgot that :o

Objective -C

deathdruid
Feb 20, 2008, 03:58 PM
Certainly possible in Java.


Object o;
if(x == 1) {
o = new Integer();
} else {
o = new String();
}
System.out.println(o);


There should be something similar in Objective-C; maybe someone else can tell you how.

yeroen
Feb 20, 2008, 04:05 PM
Do you need to build the derived object 'on top of' the base class object, i.e. at the same starting memory address? Or is it sufficient to copy the contents of the base class object as part of a new derived object?

MacDonaldsd
Feb 20, 2008, 04:10 PM
Do you need to build the derived class 'on top of' the base class object, i.e. at the same starting memory address? Or is it sufficient to copy the contents of the base class as a component of a new derived class?

Im going to be using it within core data so it will be related to other objects.

But I was thinking the same as you, (well what i think your thinking).

Simply create a new object and copy the values across and remove the old object.

Krevnik
Feb 20, 2008, 05:49 PM
Okay, I am going to put forward what I think you said in the original post, and answer that. :)

I think what you are trying to do is create a 'Car' object, and then when you find out the 'Car' is really a 'Ford', change the type of the object so it is now a 'Ford'.

The catch is that even with dynamically typed languages like Obj-C, you can't change the type of an object once it has been created. What you /can/ do though is this: When you have the superclass object and want to turn it into the subclass, then /create/ a new copy of the subclass, and write an init method that can take the superclass and copy data from it. It is a copied object, but now it is a copied object of the type you want.

skinnybeans
Feb 20, 2008, 06:07 PM
Im not very familiar with objective c syntax, so I'll explain in c++ terms what you want to do.

You need to declare a pointer to the base class object. Using the car example above..

Car *theCar;

Then later when you know what kind of object you want to create:

theCar = new Ford();

Then you can pass the value of theCar where ever a car object can be used.

This is a classic example of inheritance and polymorphism. So if you want to understand this topic in more depth read up on those 2 areas.

Catfish_Man
Feb 21, 2008, 01:02 AM
Heh. I interpreted the request as being a much much more difficult one, transforming *a specific instance* of a class into an instance of another class.

Bar foo = new Bar();
Baz transformedFoo = foo.transformInto(Baz);

Which is possible in ObjC, but very tricky, and not without tradeoffs.

MacDonaldsd
Feb 21, 2008, 05:36 AM
Hi guys thanks for all your thoughts.

Il give an example of what I mean.

If I have a Person class with the attributes name and email


I then have two subclass Teacher and Student

Student has attributes year of study, course etc

Teacher has attributes degree, teaches etc.

Is it possible to create a Person with there attributes and decide latter whether there a student or a teacher.

P.S. I realise you wouldn't want to do that in real life its just a clear example

robbieduncan
Feb 21, 2008, 05:51 AM
Not easily. The simplest way would be to define a constructor for both Teacher and Student that accept a Person as an argument. Something like initWithPerson: and use that to create a Student or Teacher from the Person

lazydog
Feb 21, 2008, 11:13 AM
I'm not entirely sure this would work but I guess the way to transform a Person into a Student would be to overwrite in memory the old Person object with the new Student object at the exact same memory address. It would be tricky to do because you'd have to make sure the Student object would fit within the memory space of the original Person object. I think you could do it in C++ because you can overload the new() and delete() operators.

A way round this is to use, throughout your code, pointers to pointers for all your Person objects. You could then reallocate the underlying Person object as a Student or Teacher without affecting the references to it in your code.

A fancier way would be to use a proxy class, eg PersonProxy, that containsd as a member a Person, Student or Teacher instance member which you can change at any time. But I guess that's straying too far from your question.

Having said all that… I'm not entirely sure why you would want to do it!

I hope all that makes sense!

b e n

alaceo
Feb 21, 2008, 12:14 PM
I know this would work well on C++ through polymorphism and dynamic casting, but I'm not sure if dynamic casting is available/what it is like on ObjC. Maybe there's some dynamic casting info available on the Apple Dev site?

AlmostThere
Feb 21, 2008, 01:19 PM
Sounds to me like you want to use a delegate. You have a class Person that you want to adapt at runtime.

Some pseudo code (sorry, am not an Obj-C person):



// The SchoolAttendee interface has a function called goToClass
Interface SchoolAttendee:
function goToClass()

// A Teacher class provides an implementation where in class they teach()
Class Teacher implements SchoolAttendee:
function gotToClass() { teach() }

// By contrast, a student learn()s when they go to class
Class Student implement SchoolAttendee:
function goToClass() { learn() }

// your actual person (note: while not specified, this can implement goToClass())
Class Person:
SchoolAttendee schoolAction = null;

// the function enrollInClass sets the behaviour when the person is in class
// this behaviour could be set at creation time (I think in the wikipedia article)
function enrollInClass(SchoolAttendee action) { schoolAction = action }

function goToClass() { if schoolAction is not null: schoolAction.goToClass() }

// An example
main:
// At the start create a Person
Person person

// ... later in the program, the person enrols in a class
// ... in this case pass a Teacher object
person.enrollInClass(Teacher())

// when the person goesToClass, it will call the function teach()
person.goToClass()



Note, this example sets the behaviour at runtime, you can see some other examples, including Obj-C, at the wikipedia article ( http://en.wikipedia.org/wiki/Delegation_pattern ) but there are lots of ways to implement this.

A language like Python can handle this very elegantly, where you can add methods to a class at runtime.

I *think* that, from what little I have read about Obj-C, you would only need to provide a class that implements a function with the appropriate name (aka an informal protocol). I am sure someone here, or your Obj-C reference book, can give you the details.

Animalk
Feb 21, 2008, 01:49 PM
There are several possible patterns that can be used to create such functionality. I highly recommend you read up on the Factory pattern which is the general case of what you're essentially trying to do.

Happy coding :)

Krevnik
Feb 21, 2008, 01:50 PM
Sounds to me like you want to use a delegate. You have a class Person that you want to adapt at runtime.

Note, this example sets the behaviour at runtime, you can see some other examples, including Obj-C, at the wikipedia article ( http://en.wikipedia.org/wiki/Delegation_pattern ) but there are lots of ways to implement this.

I *think* that, from what little I have read about Obj-C, you would only need to provide a class that implements a function with the appropriate name (aka an informal protocol). I am sure someone here, or your Obj-C reference book, can give you the details.

Yes, I like this idea and hadn't considered it first off. :)

The catch is that this works /best/ when you want to override method behavior though. If you want to add data to the class as well, then things get trickier.

You can still get away with this using KVC for your data though, by letting the delegate also provide a KVC answer if the base class has none.

AlmostThere
Feb 21, 2008, 03:06 PM
Yes, fair point about the attributes, that will be more complicated.

MacDonaldsd
Feb 22, 2008, 07:05 AM
Thanks for everyone's input, it has turned into quite an intriguing discussion.

Im going to take the easier root and simple copy the the information from one object to another, and do this in a constructor in the subclass as robbieduncan suggested.

This is mainly down to the fact as once it has sub-classed it will stay as that class, and I will also be saving the object to manipulate it at a later date, so in the grand scheme of things it will make it much easier to do it like this.

Thanks for all the help and all the links :D

devman
Feb 23, 2008, 05:02 AM
Hi guys thanks for all your thoughts.

Il give an example of what I mean.

If I have a Person class with the attributes name and email


I then have two subclass Teacher and Student

Student has attributes year of study, course etc

Teacher has attributes degree, teaches etc.

Is it possible to create a Person with there attributes and decide latter whether there a student or a teacher.

P.S. I realise you wouldn't want to do that in real life its just a clear example

Inheritance is the wrong choice here. Teachers and Students aren't special kinds of people; they are roles that people play. What if a person is both a student and a teacher? (that's just one of several problems with inheritance here). Composition is the way to go. Look at the role pattern (Coad '95) which will also solve your problem of deciding later if a person is playing the role of teacher or student or both. Furthermore, your example focuses only on data (attributes). It is behavior (methods) that drive a good object model.

Eraserhead
Feb 23, 2008, 08:08 AM
Not easily. The simplest way would be to define a constructor for both Teacher and Student that accept a Person as an argument. Something like initWithPerson: and use that to create a Student or Teacher from the Person

Sounds like the way forward to me, I'd set it up to have a Person, Teacher and Student object in the model, then if you want a teacher you create a teacher object and link it to the person with a relationship, the same for a student.

In theory that may allow you to work with Postgraduates and other strange people who might be both teachers and students :p.