• Dear Cerberus X User!

    As we prepare to transition the forum ownership from Mike to Phil (TripleHead GmbH), we need your explicit consent to transfer your user data in accordance with our amended Terms and Rules in order to be compliant with data protection laws.

    Important: If you accept the amended Terms and Rules, you agree to the transfer of your user data to the future forum owner!

    Please read the new Terms and Rules below, check the box to agree, and click "Accept" to continue enjoying your Cerberus X Forum experience. The deadline for consent is April 5, 2024.

    Do not accept the amended Terms and Rules if you do not wish your personal data to be transferred to the future forum owner!

    Accepting ensures:

    - Continued access to your account with a short break for the actual transfer.

    - Retention of your data under the same terms.

    Without consent:

    - You don't have further access to your forum user account.

    - Your account and personal data will be deleted after April 5, 2024.

    - Public posts remain, but usernames indicating real identity will be anonymized. If you disagree with a fictitious name you have the option to contact us so we can find a name that is acceptable to you.

    We hope to keep you in our community and see you on the forum soon!

    All the best

    Your Cerberus X Team

Class Thing<T> wizardry

olive

Member
3rd Party Module Dev
Tutorial Author
Patreon Bronze
Joined
Jul 17, 2017
Messages
76
I just found out that I can do a thing with classes that I didn't realize was possible & wanted to share it. I've never really played with the "Class Thing<T>" structure (I don't know the name of it) so didn't know exactly what I could do with the given T.

Well, apparently, you can make new instances of that T and then cast that to other object types, including abstract ones!

Cerberus:
Class Generator Abstract
    Method name$() Abstract Property
    Method Init:Void(file$) Abstract
End


Class GeneratorManager<GeneratorType>
    'A map of created generators keyed by their file name.
    Field loadedGenerators:= New StringMap< Generator >

    'This is where the magic is. Being able to create a NEW OBJECT of an
    'ARBITRARY TYPE and then cast it to an ABSTRACT CLASS (which I can
    'then call methods on??) seems like dark magic to me.
    Method Create:Generator(file$)
        local g:Generator = Generator(New GeneratorType)
        g.Init(file)
        loadedGenerators.Add(g.name, g)
        return g
    End

    'Gets a loaded generator ~OR~ creates a new one if it doesn't exist
    Method Get:GeneratorType(file$)
        local g:Generator = loadedGenerators.Get(file)
        if g = Null then g = Create(file)
        Return GeneratorType(g)
    End
End

So I can now make generators for any of the classes in my game, and load and cache them all the same way. It just blows my mind that the same exact same method (the manager's Get) can end up returning a different object type.

Cerberus:
Class LimbGenerator Extends Generator
    Field script:LimbScript

    Method name$() Property
        return script.name
    End

    Method Init:Void(file$)
        script = New LimbScript(file)
    End

    Method MakeLimb:Limb()
        Local limb:= New Limb
        script.SetupLimb(limb)
        return limb
    End
End

' -- make some limbs -- '
local limbGeneratorManager:= New GeneratorManager<LimbGenerator>

local armGenerator:LimbGenerator = limbGeneratorManager.Get("arm.mc")
local arm:Limb = armGenerator.MakeLimb()

local legGenerator:LimbGenerator = limbGeneratorManager.Get("leg.mc")
local leg:Limb = legGenerator.MakeLimb()


' -- make some neurons -- '
local neuronGeneratorManager:= New GeneratorManager<NeuronGenerator>

local motorGenerator:NeuronGenerator = neuronGeneratorManager.Get("motor.mc")
local motor:Neuron = motorGenerator.MakeNeuron()

local reflexGenerator:NeuronGenerator = neuronGeneratorManager.Get("reflex.mc")
local reflex:Neuron = reflexGenerator.MakeNeuron()

I guess that lists and stuff have been doing this all along (e.g. a Stack<Limb>'s Pop() returns a Limb) but I never realized that this same power could be mine to command.

Does anybody else use the <T> pattern much? Are there other tips or pitfalls I should watch out for?
 
you can make new instances of that T and then cast that to other object types, including abstract ones!
I think the term used is a class factory.
 
Last edited:
You know you have a method "New" that returns a new object, right? You don't need to have a "create" or "init" and return something.

For example, instead of your Create method that creates a local Generator and returns it you could just use:

Code:
Method New(file$)
    Init(file)
    loadedGenerators.Add(name, Self)
End
 
Last edited:
I guess that lists and stuff have been doing this all along (e.g. a Stack<Limb>'s Pop() returns a Limb) but I never realized that this same power could be mine to command.

Does anybody else use the <T> pattern much? Are there other tips or pitfalls I should watch out for?

Generics are pretty useful for a lot of things, but many coders will get along happily with the pre-made ones.

They don't really have too much in the way of subtle pitfalls that I know of, generally if the code compiles it will work as intended!
 
Back
Top Bottom