ID:2245433
 
Applies to:DM Language
Status: Open

Issue hasn't been assigned a status value.
module
ai
var/tmp/mob/ai/master

human
var/tmp/override/mob/ai/human/master

animal
var/tmp/override/mob/ai/animal/master


The idea is the override keyword would allow one to redefine a previously defined variable.

In my example, the base module type has a master variable using a base ai type. Getting into more unique systems, such as the animal module, the master variable is redefined to properly represent the type it'll be using.

The main benefit of this feature would be avoiding code duplication of all forms.
On that note, the ability to for static variables to store seperate versions for children, most likely by just defining an overridden version of that variable. (but maybe some way to specify this on the parent, and/or override it on children)
I'm not really sure about this language feature.

C# has variable hiding with the "new" modifier, even though it's usually not necessary since most fields are private and not accessible to sub-types.

I think this particular example can be done with a different approach. Is inheritance really correct, in the first place? Or, should the base "ai" type even have a "master" variable?

For example, the base "ai" type could be abstract, with a set of procs that it can use but aren't implemented so they don't explicitly depend on a master.
module
// An AI is something that thinks.
ai
proc
Think()

// A Human AI makes a human think.
ai/human
var
mob/ai/human/human

New(mob/ai/human/human)
src.human = human

Think()
view(human) << "[human]: Hmmm..."

// An Animal AI makes an animal think.
// It just so happens that there seems to be repeated code here,
// but it's... not really.
// Animal AIs happen to require a reference to a particular animal,
// but not all AIs work this way.
ai/animal
var
mob/ai/animal/animal

New(mob/ai/animal/animal)
src.animal = animal

Think()
view(animal) << "[animal]: ..."

// A God AI just thinks, but needs no reference.
ai/god
Think()
world << "Hmm."

Either way, even in C#, the "new" keyword (which lets you "hide" an inherited member with a new member of the same name/signature), the new variable isn't actually the same as the hidden variable; they're two separate variables. If the code of the parent type sets its master variable, the child type's master variable isn't affected.

In C#, another solution for your example would be to use "generics". Basically, the base AI type comes with a generic type (which you can limit to types of /mob/ai), and define the "master" variable in terms of that type:
class AI<T> where T : AIMob {
protected T master;
}
class HumanAI : AI<HumanAIMob> {
// Here, "master" is declared with the type HumanAIMob
}
class AnimalAI : AI<AnimalAIMob> {
// Here, "master" is declared with the type AnimalAIMob
}

If it were a choice between adding this "override" modifier and adding generics to the language... I think anyone would choose generics.
In response to Kaiochao
I very much want generics, but what would you do for the syntax?

Class: Generic works nice in C#, but class/type definitions are quite different.

Something like this? :
/datum/ai<T as /mob/ai> //reusing "as" since it's already a byond keyword people will know

/datum/ai</mob/ai/dog>/dog_ai

/datum/ai</mob/ai/cat>/cat_ai


Tricky one I think.
Kaiochao said:
...

In hindsight (after a night's rest), I agree with you. For what I was doing (isolating certain AI behavior), using datums wasn't necessary (although it could work); there are simpler approaches I overlooked.

I still think something similar to the feature request would be beneficial though. For example:

MrStonedOne said:
On that note, the ability to for static variables to store seperate versions for children, most likely by just defining an overridden version of that variable. (but maybe some way to specify this on the parent, and/or override it on children)

I completely agree.