Class Thing<T> wizardry

wick

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?
 

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
852
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:

SLotman

Active member
3rd Party Module Dev
Joined
Jul 3, 2017
Messages
174
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:

Gerry Quinn

Active member
Tutorial Author
Joined
Jun 24, 2017
Messages
151
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!
 
Top Bottom