Phantasmal MUD Lib for DGD
|
Phantasmal Site > DGD > DGD LPC Reference > Create Funcs Create() Functions in DGDFrom: dgd at list.imaginary.com (Noah Gibbs) Date: Mon Oct 20 14:18:02 2003 Subject: [DGD] Some basics --- Nihilxaos wrote: > 1) When an object is compiled it's create is > called. Nope, but close. The first time a function is called on the object, create() is called first. So if you've just made an object called "bob" and want to initialize it, you can say "bob->NoSuchFunction()", which will return nil, and will do nothing but call create(), at least if the function doesn't exist. I think create() also gets called if you clone from it, but I'm not 100% sure. This is all written down somewhere :-) > Thus if I write a log > daemon logd.c (aliased by LOGD) and pull the usual > if (!find_object(LOGD)) > {compile_object(LOGD);} it sees if the logd object > has been loaded into memory, > and if not it compiles it and then runs create since > you obviously want to > create it. This right? Almost. Create isn't called yet. > It seems a little off to me, > but that seems to be how > things are working. Or is it more correct to say > that create is called once the > first call is made to one of the object's functions? Yup. > Basically this is going on the assumption > that inheriting brings the > inherited data types into the object, but keeps any > non-overridden code in a > separate object so it can be called from any of its > children. I'm not sure what you mean here. Inheriting from an object doesn't change that object, so yes, the code that you override in a child still exists in the parent. Is that what you're getting at? And functions that you don't override are callable from the child, but on the child's copy of the data. In the Kernel MUDLib it goes one step further -- a library NEVER has its create() function called. That means its data never gets instantiated, which is a *good* thing -- it's the key to being able to upgrade in place. > Thus when you > destruct an object it in turn destructs its > ancestors, You can make it do that. It doesn't happen automatically, at least not in that way. But the ObjectD could do that for you if you wanted. > not to ultimately wipe > out the ancestor such that it can't be called by > other like objects, but so it > removes the links between it and its ancestors. > (that make sense?) I think you mean the right thing. Yes, it destructs its ancestors... But even if they're destructed, they don't *really* go away until nobody references them (inherits from them) any more. That's why the ObjectD keeps a big list of destructed objects around. Those are libraries that somebody inherits from but that have been destructed already. When the last child of that library is recompiled (pointing at the new, non-destructed copy), the old destructed version goes away because nobody references it any more. From: dgd at list.imaginary.com (Stephen Schmidt) Date: Mon Oct 20 14:23:00 2003 Subject: [DGD] Some basics On Mon, 20 Oct 2003 Nihilxaos wrote: > 1) When an object is compiled it's create is called. This is not quite correct, as you've already deduced. Two things are true. First, as you wrote: > Or is it more correct to say that create is called once the > first call is made to one of the object's functions? Yes, create isn't run until it has to run, that is, when some other object wants to call into this one. Until then, this object is just sitting in The Void by itself doing no harm to anyone, so no need to run create() in it. The second caveat is that if you are recompiling the code of an existing object, create() will not be called in that case, even when a function is called, because presumably the object (which was not destructed) has some internal state that should be preserved. The object hasn't been recreated, just had its code recompiled. Whatever its variable values were, those should not change. Normally calling create() sets variable values to some default initial values, and you wouldn't want to do that if all you were doing was changing the code. In Melville, the update command has a flag (I don't remember exactly what, I think -c) to force calling the create function. So "update foo.c" updates the code but doesn't call create, while "update -c foo.c" does both. (I may have set it up so that there's also a flag that triggers destruction of the original object. You would want to call create() explicitly in that case too, probably.) This is, of course, a change in behavior from LPMud, and I think it's fair to say that I have gotten more bug reports from Melville caused by this issue (people not understanding why create() wasn't being called when they updated an object) than any other single source. > 2) When I inherit something, if it doesn't already exist I have to call it's > create function. I think not. create() should get called by the time you use the object for anything else. The only time you'd need to invoke create() yourself is when you have a logging line or something that you want invoked right when the object is created, instead of waiting until the object is first used. Of course, I'm guessing that is exactly the case here :) > Thus you'll see something like: > inherit foon FOON; > [...] > foon::create(); > Is that because we want to make sure that FOON has been loaded into > memory, or do I have to call create() to make sure that the inherited > object is properly configured for this object and not for something > that may have inherited it before? I'm not sure I understand this correctly, but if I do, then this is for configuration. You probably want to do this in the form: inherit foon FOON; void create() foon::create(); } so that foon's create runs when this object's create does. Anything else could result in bizzare behavior. For example, say foon is container.c, and it tracks where the container is open or closed, and create() in foon initializes all newly-created containers to be closed. If you invoked foon::create() from anywhere other than the inheriting object (say, treasure_chest.c)'s create() function, then the chest would snap shut when create() in foon was called. Be a pity if the key was inside, wouldn't it? :) > Basically this is going on the assumption that inheriting brings the > inherited data types into the object, but keeps any non-overridden code in a > separate object so it can be called from any of its children. That, I think, is correct, and actually the overridden code is there too. But I'm not totally sure of this. > Thus when you > destruct an object it in turn destructs its ancestors, not to ultimately wipe > out the ancestor such that it can't be called by other like objects, but so it > removes the links between it and its ancestors. (that make sense?) This is where garbage collection comes in. When 10 objects inherit foon.c, and of those 10 objects, 1 has 20 clones, then you can't destruct foon.c until all 20 clones and the 10 objects are gone. And when you recompile foon.c so you can change behavior in one of those 10 objects, do you keep the old behavior in the other 9 objects, or not? This is an area where I understand the problems but not the exact solutions, so I'm going to turn discussion over to the driver gurus at this point. Steve From: dgd at list.imaginary.com (Erwin Harte) Date: Mon Oct 20 14:27:01 2003 Subject: [DGD] Re: Some basics On Mon, Oct 20, 2003 at 12:17:33PM -0700, Noah Gibbs wrote: > --- Nihilxaos wrote: > > 1) When an object is compiled it's create is > > called. > > Nope, but close. The first time a function is > called on the object, create() is called first. So if > you've just made an object called "bob" and want to > initialize it, you can say "bob->NoSuchFunction()", > which will return nil, and will do nothing but call > create(), at least if the function doesn't exist. I'd go for this instead: call_other(bob, "") Less chance of NoSuchFunction() accidentally (or intentionally, if someone is trying to break things) existing. [...] > > Basically this is going on the assumption > > that inheriting brings the > > inherited data types into the object, but keeps any > > non-overridden code in a > > separate object so it can be called from any of its > > children. If with 'data types' you mean 'non-private variables', then yes. Erwin. -- Erwin Harte From: dgd at list.imaginary.com (Stephen Schmidt) Date: Wed Mar 20 23:46:01 2002 Subject: Re[2]: [DGD] Inherits. On Thu, 21 Mar 2002, Vladimir I. Lazarenko wrote: > hmm. let's take my situation as an example. > I have a thingie called channel_d (Melville mudlib). > If i make changes to channel_d and then issue 'update channel_d.c' > my changes are not there. > Am I doing anything wrong? Sorta. When an existing object is updated in DGD, create() is not called in the object. Because, in the channel_d, the data is loaded in create, when you update it, the data is not there. There are several fixes: 1) Change your update command to invoke create() if the object existed before, or at least, have a flag so the user can invoke that behavior; 2) Change the channel daemon so that, when any call is made into it, it will check to see if its data is loaded, and load it if not; 3) Create a new command, like the update command, that invokes create() when you want to. All of these have drawbacks. The soul daemon has the same problem (in fact, that's usually the one people notice first). Steve From: dgd at list.imaginary.com (Erwin Harte) Date: Wed Mar 20 23:54:01 2002 Subject: [DGD] Inherits. On Thu, Mar 21, 2002 at 12:17:05AM -0500, Stephen Schmidt wrote: > On Thu, 21 Mar 2002, Vladimir I. Lazarenko wrote: > > hmm. let's take my situation as an example. > > I have a thingie called channel_d (Melville mudlib). > > If i make changes to channel_d and then issue 'update channel_d.c' > > my changes are not there. > > Am I doing anything wrong? > > Sorta. When an existing object is updated in DGD, create() is > not called in the object. Because, in the channel_d, the data > is loaded in create, when you update it, the data is not there. I'm not sure you and I are talking about the same DGD here, then. DGD's compile_object() never calls any functions in the object that it returns, the create() (or _F_create() or whatever the creator function is that you use for Melville) function is called just before someone or something calls a function in the object for the first time. If you're _recompiling_ an object, all you're doing is replace the code, you don't want to go and call create() functions in there, you could very likely damage important data in there when all you did was fix an if-statement condition or something like that. Perhaps you could add something to your command so that if you're recompiling an object instead of compiling one that didn't exist before, you call a different function like upgraded(), from a 0-call_out (because the new code won't be effective until after the thread finishes). Hope that helps, Erwin. -- Erwin Harte |