Is there a language that does "downclassing"/instance morphing?

Pages: 123
How do you not add the other ones when you con't even have the source to them? Did you even read my use case?


Then I suppose I'm not sure what the problem you have is. Just use the 'C' classes everywhere and if a B is needed somewhere then you can just pass it and inheritance will take care of turning it into a B for you.
But when you need t convert B into C, it is more convenient to have a language feature than to coordinate with three separate developers,
¿coordinate what?
1
2
3
4
void change_behaviour_to_c(){
   delete this->behaviour;
   this->behaviour = new C();
}



For the second part
1
2
3
4
a := Bar new
b := a //¿what do you want here?
a := Foo new //¿how is `b' affected?
b := c //¿how is `a' affected? 
closed account (o1vk4iN6)
Yah I don't see what has to be coordinated between 3 devs, perhaps an example of what each developer is responsible for (using your minecraft case) ?

In any case I disagree that a feature should be included simply to standardize a single case. The other 2 devs should follow the standard/method used by the first.
Last edited on
I found the opening post a bit difficult to follow, but if I understand correctly you were asking if there are languages which allow you change the behavior of object instances dynamically. If I got that right, then you might be interested in actor programming languages, like Humus.

Actor Languages
http://c2.com/cgi/wiki?ActorLanguages

Humus Overview
http://www.dalnefre.com/wp/humus/humus-overview/

In Humus, the BECOME statement tells an instance to use a new behavior when responding to a message.

Andy

PS While I've seen mention of these actor languages from time to time, and read a bit about them, I've never tried to use one. And though the ideas been around a fair while, it' never been popular.

Why has the actor model not succeeded?
http://www.doc.ic.ac.uk/~nd/surprise_97/journal/vol2/pjm2/
http://www.doc.ic.ac.uk/~nd/surprise_97/journal/vol2/pjm2/
Last edited on
--[[

Maybe Lua [1] is what you're looking for.

(BTW, you can feed this post to a Lua interpreter as it is, and get meaningful output. I did it several times as I was writing it.)

Lua doesn't have built-in support for OOP, but it offers some powerful features that allow one to easily emulate it. These features also allow one to do what I think you want here.

In Lua, everything that represents some kind of non-primitive data is a table. You can store anything you want (numbers, strings, functions, other tables) in a table and you can also use anything you want as an index to a table. Not surprisingly, the most straightforward way to emulate a C++ class is to use a table:

]]

Entity = {}             -- Entity is an empty table (BTW, this is a single-line comment)
Entity.name = "no name" -- same as Entity["name"] = "no name"
Entity.level = 0        -- same as Entity["level"] = 0

function Entity.toStr(self)
  local str =          "Name  : " .. self.name  -- .. concatenates stuff
        str = str .. "\nLevel : " .. self.level -- into a single string
  return str .. "\n"
end

-- The above is equivalent to Entity["toStr"] = function (self) --[[ ... ]] end
-- BTW, --[[ and ]] mark the beginning and end of multiline comments, respectively.
-- But I'm sure you've already figured that out.

Entity.__index = Entity -- more on this in a while...

--[[

Notice that I didn't actually define a type here. I just created an object with the properties I wanted. If I want to create more Entities, I'll have to copy the one I created here [2]. Well, not actually copy it. Just set it as the metatable to the newly created Entities:

]]

e1 = {}                 -- new, empty table
setmetatable(e1,Entity) -- now, e1 is an Entity with
                        -- default  name == "no name" and
                        -- default level == 0
print(e1.toStr(e1))     -- just to be sure...

e1.name = "LB"
e1.level = 100

print(e1:toStr())       -- more convenient syntax

--[[

Setting e1's metatable and Entity's __index member to Entity has the following consequence: Whenever you try to read data from e1 using an index that doesn't exist in e1, the Lua interpreter tries to access the Entity table using that index before returning nil (the Lua non-value).

Now, the very same features that allow emulation of classes, also allow emulation of inheritance:

]]

Ranger = {}
Ranger.dexterity = 10
Ranger.__index = Ranger
setmetatable(Ranger, Entity)

-- let's override toStr...

function Ranger:toStr()
  return  "Name      : " .. self.name ..
        "\nLevel     : " .. self.level ..
	"\nDexterity : " .. self.dexterity .. "\n"
end

-- let's test the new class

e2 = {}
setmetatable(e2, Ranger)

-- First checks e2 for name,
-- then checks Ranger for name,
-- and then checks Entity for name:

print("e2's name is ... " .. e2.name .. "\n")

-- now, let's make e1 a Ranger too!

setmetatable(e1, Ranger) -- that's all it takes!

e1.dexterity = 9001

print(e1:toStr())

--[[

[1] http://www.lua.org/
[2] http://en.wikipedia.org/wiki/Prototype-based_programming

]]
Last edited on
1
2
3
4
5
6
7
8
9
10
void DealWithAnObject(A *a)
{
    B *b = dynamic_cast<B *>(a);
    if(b == 0) return; //not what we're here for
    if(dynamic_cast<C *>(b) == 0)
    { //we know it's a B instance but not a C instance
        b->C::C(/*constuctor args*/); //convert object into a C instance
    }
    //done, a now behaves like a C object, and dynamic_cast<C *>(a) works
}
Now if that would be possible.

Imagine that you pass a pointer to an object that does perfectly what you want to a function and all of a sudden it does something else! The consequences would be that programming becomes a game of pure chance
I don't understand where I went so wrong.

cire wrote:
As far as I can tell that's the first time.
http://www.cplusplus.com/forum/lounge/84738/#msg454302
http://www.cplusplus.com/forum/lounge/84738/#msg454287
http://www.cplusplus.com/forum/lounge/84738/#msg454249
As far as I can tell it was the fourth time...

cire wrote:
After asking if there's a language that solves this problem without the use of a design pattern, then asking about design patterns in other languages, one might assume you meant languages other than the (possible) one in your first question. C++ would be one of those, and it certainly looks like you were asking for a design pattern.
I gave the thread a title...

firedraco wrote:
Then I suppose I'm not sure what the problem you have is. Just use the 'C' classes everywhere and if a B is needed somewhere then you can just pass it and inheritance will take care of turning it into a B for you.
How can you do that when you don't control the construction of the objects? They already exist...

ne555 wrote:
¿coordinate what?
Coordinate following the behavior design pattern. If one of the devs doesn't do anything in his code to support behaviors...

xerzi wrote:
Yah I don't see what has to be coordinated between 3 devs, perhaps an example of what each developer is responsible for (using your minecraft case) ?
None of the developers should have to be responsible for anything...

xerzi wrote:
In any case I disagree that a feature should be included simply to standardize a single case. The other 2 devs should follow the standard/method used by the first.
It's the first two devs that, without this feature, would have to follow the standard/method used by the third...

andywestken wrote:
I found the opening post a bit difficult to follow, but if I understand correctly you were asking if there are languages which allow you change the behavior of object instances dynamically.
You seemed to describe something close to what I was looking for, but seeing what Actor languages are doesn't seem anything close to what I was asking for. Thank you for at least suggesting a language as I originally asked...

m4ster r0shi wrote:
Maybe Lua [1] is what you're looking for.
That's really nifty! I am familiar with LUA. Unfortinately, it's not a language featue that you have shown, but a design pattern...

coder777 wrote:
Imagine that you pass a pointer to an object that does perfectly what you want to a function and all of a sudden it does something else! The consequences would be that programming becomes a game of pure chance
Java has a concept of a final class; one which cannot be extended by other classes. This feature alone would be enough to resolve your proposed problem. A simple contract that says "do no more than this." Maybe it could even be per-instance.


I'm really confused how I cam across so unclear. I thought that by specifying what I was looking for in the thread title and in the post, plus a one-use fallback in the post, I could perchance get the attention of someone who happened to know more than me and happened to know of such a language. Instead, I got the single-use fallback a multitude of times in various languages.

I've decided such a language must not exist for the feature in it to be so confusing and unheard of that only design patterns could allow for it.

And in case it still is not clear, I was looking for an entire language that had the feature I described as a built-in language feature, not as a design pattern. Design patterns solve problems that languages don't solve, and considering I gave specific emphasis to looking for a language, I don't feel bad for hammering on the design patterns you all gave.

Thank you for your time, everyone, and sorry for wasting it.
Last edited on
How can you do that when you don't control the construction of the objects? They already exist...


Then you can simply create C's from the B's since the C's by definition have no other data members.

I just don't think that such a feature would exist because it would only help in a very specific case but could easily cause issues without tons of checks for other cases.
firedraco wrote:
Then you can simply create C's from the B's since the C's by definition have no other data members.
The new behavior given by C may (does) require data members. And on top of that, you've completely ignored the problem: the original instance is unaffected. Its behavior has not changed, its internal state has not changed, and its run time type has not changed. This is an enormous problem, and is the whole reason I am looking for this language feature, but people seem to be pretending the problem does not exist.

firedraco wrote:
I just don't think that such a feature would exist because it would only help in a very specific case[...]
I've needed this kind of thing many, many times.
firedraco wrote:
[...] but could easily cause issues without tons of checks for other cases.
I am being ignored, now, it seems.
LB wrote:
Java has a concept of a final class; one which cannot be extended by other classes. This feature alone would be enough to resolve your proposed problem. A simple contract that says "do no more than this." Maybe it could even be per-instance.
A mature language would solve your proposed problem. Since one such language does not exist, I opt for the optimistic view.
Last edited on
The new behavior given by C may (does) require data members. And on top of that, you've completely ignored the problem: the original instance is unaffected. Its behavior has not changed, its internal state has not changed, and its run time type has not changed. This is an enormous problem, and is the whole reason I am looking for this language feature, but people seem to be pretending the problem does not exist.


Ok, I think I see what you are saying now...

I think the problem is that you want to have two (possibly separate) objects that both can reference the same data "base" except that one of the objects hasn't made provisions for that.

You could try making the 'C' class just contain a pointer or something to the B "base" class and have a conversion to a B (so that it could be converted easily), but that's just another design pattern.

I'm not completely sure why you *need* a language feature for this though. It's sort of like saying you want a language feature for converting an integer to a string and back. Not bad or anything but not having it doesn't prevent you from doing it.
Those are two completely unrelated things. Converting between strings and numbers is, essentially, changing the representation of a serialized form from one type to another unrelated type so that it is easier to deal with the serialized form as needed. The two types are unrelated and have different representations in memory, along with incompatible behaviors and public interfaces.

Allowing for an existing instance to be converted, in-place from the perspective of the code and the programmer, to an instance of a subtype, is, essentially, enabling new behavior that previously was not possible, and this new behavior is fully compatible because the public interface is the same and does not affect code that expects it to be at the very least a more abstract type.

Obviously giving a string to a function that expects a number primitive or a number primitive to a function that expects a string will cause serious problems. But with the language restrictions imposed on classes, it is no problem to give a std::ofstream to a function that expects a std::ostream.

The idea is that design patterns solve problems that are not solved by the language and have no trivial solution within the bounds of the language's features. If a design pattern has to be used at all, you're not using the correct language, or the language is flawed in terms of the language's goals.

Theoretical use-case based on real-world scenario:
Minecraft has a Block class. The Buildcraft mod has a TransportPipe class that somehow extends the Block class, because transport pipes are blocks. The MorePipes addon mod has a FastTransportPipe class that somehow extends the TransportPipe class. It is necessary, due to popular request by lazy users, to be able to change existing transport pipes into fast transport pipes without manually breaking and replacing the existing pipes and causing items being transported to spill out. Due to the poor design of the no-longer-maintained Buildcraft mod, which is still compatible with Minecraft and still highly popular with no alternative, the only way to implement the feature requested is to literally call functions to break the pipe and place the new one in its place, except you have no way of preserving the state of that pipe. Thankfully, Minecraft, Buildcraft, and MorePipes all used the XYZ language, which allows for converting existing instances into further-derived class instances, so the TransportPipe object can be converted into a FastTransportPipe object, changing it's physical appearance to players and allowing it to transport items more quickly. If they hadn't used language XYZ for their code, they'd have all been screwed.

Unfortunately language XYZ doesn't exist so they are all screwed. Thankfully this scenario is fictional and the Buildcraft mod is under active development, so the MorePipes mod author can ask the Buildcraft mod author to implement a design pattern that allows the feature. This should not be needed, however, because it completely violates basic OO principles. You shouldn't have to accommodate every possible extension to a class you make; the language you use should. I can't imagine having to write a class and then write code to account for every single possible class that could ever be created to extend my class. That completely goes against the ideas behind Object Oriented Programming. If no class/OO contracts are violated, no changes should have to be made to code. If a class or instance does not say "you can't extend me!" then you should be able to extend it without changing what you are extending.

Many of the design patterns that have been suggested involve accounting for expansion to the original via behaviors stored in the individual instances of the original class. It's a clever design pattern, but it completely bypasses object oriented programming with classes and inheritance and language features that can do it with less hassle and more chance for compiler optimization.

My point is, it doesn't violate anything, it has a use, it fixes a problem otherwise solved by design patterns. It's a language feature, and should be, which is why I originally asked if there was a language that had such a feature.

You've all shown me there is not such a language for it.

It is clear to me there is not such a language for it.

I can use design patterns.

I can create my own language.

All I asked for was practicality, all I got was hard reality.

Can I be left alone now? You all clearly do not agree with my idea and can't see any benefit to it. I'm tired of asking for white-chocolate ice cream and getting chocolate and vanilla ice cream with white-chocolate sprinkles.
Last edited on
My point is, it doesn't violate anything, it has a use, it fixes a problem otherwise solved by design patterns. It's a language feature, and should be, which is why I originally asked if there was a language that had such a feature.


Wait. So I thought you had to keep the original B objects around even though you had created the new C object? If you don't, then why can't you just replace the B object with the C object (made from the B object)? Where a B object is needed it will be converted for you because C is a B.

Can I be left alone now? You all clearly do not agree with my idea and can't see any benefit to it.


I just don't understand how your idea requires a new language feature. It seems like just deriving C from B would work fine to me, but obviously I'm missing something that prevents that from working.
firedraco wrote:
Wait. So I thought you had to keep the original B objects around even though you had created the new C object? If you don't, then why can't you just replace the B object with the C object (made from the B object)? Where a B object is needed it will be converted for you because C is a B.
Because in many languages with reference semantics and garbage collection, you can't know where an object is referred to to change every reference to it to point to the new instance. This is the serious problem I have been repeating. Do I honestly have to give every single detail in the same post? Is spreading it across several posts too difficult for everyone to comprehend?

firedraco wrote:
I just don't understand how your idea requires a new language feature. It seems like just deriving C from B would work fine to me, but obviously I'm missing something that prevents that from working.
Just deriving C from B is all you have to do, as long as you have the language feature. If you don't have the language feature, you have to use a design pattern to accomplish the same thing. Again, I've explained this before, I don't understand why once is not enough. Maybe I'm just horrible at conveying thoughts and ideas and therefore would be a horrible teacher.
Last edited on
So basically what you want is to be able to modify B "in place" to turn it into a C but still allow all of the previous B references to stay valid (pointing at the new C), right?

I guess the only way you would be able to do it is go through all the list of references that point to that B and point them to the new C that you just made. You could try using placement new on the address of the B to construct that C with the B (maybe making a copy to make sure you don't screw anything up) but that would assume that C doesn't have any extra data or that you have enough room to do it.

I would assume that if it was present as a language feature that you would have to do some form of the above steps somewhere.

EDIT: But like you said, I don't think there is a language that has this as a feature.
Last edited on
firedraco wrote:
I would assume that if it was present as a language feature that you would have to do some form of the above steps somewhere.
No. Language feature means it is completely handled for you and you simply specify deviations from normal behavior. In a high-level language it would not make sense to have to reflectively iterate over all references to the old instance and point them to the new one; it would be the completely wrong way to solve the problem and would be using low-level tactics. The language implementation would be responsible for that iteration and adjustment, if they so chose to implement it that way.
so why can't the B object be "downclassed" or morphed into a C object?

Because C may have more members than B, so to convert B into C it would need to grow in memory when there may not be enough space.
Like I said, it has to be a language feature. The language implementation would account for all that.
The language implementation would be responsible for that iteration and adjustment, if they so chose to implement it that way.


That's what I meant. The implementation would have to do it for you at some point. Obviously you wouldn't see it.
Ah, sorry - misunderstood.
Doesn’t every dynamic language worthy this name have this "feature"? I mean, in Python, for example, an object contains some special fields: __class__ specifies its type, and __dict__ references a dictionary with the object’s attributes. By changing those fields you can easily morph an arbitrary object into an object of any other type. There is no need for the creator of that other type to do anything unusual. This way you can accomplish your goal without any design pattern. Or am I missing something?

>>> class Timer:
	def start(self):
		cnt = 1
		while True:
			print cnt
			cnt += 1

			
>>> class TimeBomb:
	def start(self):
		cnt = 10
		while cnt > 0:
			print cnt
			cnt -= 1
		print "BOOM!!! You're dead!"

		
>>> timer = Timer()
>>> timer.__class__ = TimeBomb
>>> timer.start()
10
9
8
7
6
5
4
3
2
1
BOOM!!! You're dead!
>>> 
Last edited on
Pages: 123