Problems creating a class based on ComplexContainer

I’m new to TADS 3 and trying to create a Desk class which you can put things both on and under. ComplexContainer plus a Surface and an Underside works great, as long as I copy/paste the nested object properties onto every static object. But I’m trying to generalize this to a Desk class, to reduce duplication, and running into problems.

Basically, it’s clear that my Surface and Underside exist only on class Desk itself and are shared by all objects for which Desk is the prototype. What’s the best way to define a Desk class such that all the parts of the ComplexContainer are created fresh for every static object that inherits from it?

Here’s a minimal example, a desk with a rock on it:

gameMain: GameMainDef
    initialPlayerChar = me
;

room: Room 'room' 'room'
    "You're in a minimal example with a desk. "
;
+ me: Actor;

class Desk: ComplexContainer, Heavy
    // These nested objects appear to exist only on the "class".
    subSurface: ComplexComponent, Surface { }
    subUnderside: ComplexComponent, Underside { }
;

desk: Desk {
    vocabWords = 'desk'
    name = 'desk'
    desc = "It's a desk that doesn't seem to work right. "
    // All is well when I add the nested objects on the instance like so:
    // subSurface: ComplexComponent, Surface { }
    // subUnderside: ComplexComponent, Underside { }
    location = room
}

rock: Thing {
    vocabWords = 'rock'
    name = 'rock'
    desc = "It's a rock that's not so hot either. "
    location = desk.subSurface
}

I have a couple specific problems. First one is that this prints:

Room
You’re in a minimal example with a desk.
On the is a rock. On the is a rock.

Not sure what’s going on there, but I assume it shakes out of some of my other bad assumptions. The blank name seems to be because it’s using the name on class Desk, not my instance. If I give class Desk an initial value for name, then it prints that, and not the instance’s name.

Secondly, if I create more instances of Desk as static objects, it’s clear the nested Surface and Underside objects are being shared by all the objects (the rock is “already on” each of the Desks when trying to move it around).

I thought I could solve this with a constructor to instantiate the Surface and Underside, but apparently constructors aren’t called in static object instantiations, only in dynamic instantiation with new. What’s the usual way to do what I’m after here? And getting craftier, what’s a good way with debugging tools or logging statements to inspect the state of the game world so I can check my hypothesis?

1 Like

Yeah, these inner objects are going to be static to the class. There’s probably a way to do what you want with something like:

class DeskSubUnderside: ComplexComponent, Underside;

class Desk: ComplexContainer, Heavy
    initializeThing()
    {
        inherited();
        subSurface = DeskSubSurface.createInstance();
        subSurface.location = self;
    }
;

But it’s kind of a nightmare to get it right. I recommend just declaring these inner objects in each object instead.

1 Like

You can see an example of a class with nested objects at my post here: (TADS3) I don't understand why inner classes are doing this.

That has a lot of added complexity by allowing different properties to be set (I preferred that over requiring each instance to override the preinitThing method). I’m happy to answer any questions you have!

For anyone still wondering how to do this:

class ComplexSurface : ComplexComponent, Surface
;
class ComplexUnderside : ComplexComponent, Underside
;
class ComplexRearContainer : ComplexComponent, RearContainer
;
class ComplexRearSurface : ComplexComponent, RearSurface
;
class ComplexInnerContainer : ComplexComponent, Container
;


class Table : ComplexContainer, Heavy
    subSurface = perInstance(new ComplexSurface())
    subUnderside = perInstance(new ComplexUnderside())
    initializeThing() {
        subSurface.moveInto(self);
        subUnderside.moveInto(self);
        subSurface.targetObj = self;
        subUnderside.targetObj = self;
        inherited();
    }
    contentsListed = nil
;

Hopefully this helps.