4page wrote:Not sure if this is a bug or not. When using a mixin on a class which also inherits from a different class I realized they both (the mixin and the parent class) had a function with the same name. The game ran fine, and when I checked it seemed that it was running the mixin version of the function. I was told this might be a bug and to make an example to post here, but when I made the example it would only run the parent class function. And if there are 2 mixins that have the same function as the parent class then the game won't run as it sees the duplicate between the parent and the 2nd mixin, but not the first.
This is indeed not a bug, and it's not related to mixins, either.
For specifics on what's going on here: This is called
function hijacking, or
shadowing¹. ZScript² allows you to define a new non-virtual function with the same name as one in a base class. However, since it's not virtual³, the only way for the compiler to know it exists is if the variable or expression is typed as the type that shadows the function or one of its descendants.
The reason it can still call the "correct" function when typed as the shadowing type is because the compiler first searches for the symbol⁴ in the class' own list of symbols - if not found, it then looks for it in the parent's list, then the parent's parent's list, and so on. Since the class' own list is searched first, the function that's doing the shadowing is also the one that's found first.
Code: Select all
class Foo {
void SomeFunction () { /* [...] */ }
}
class Bar : Foo {
// This shadows the original SomeFunction defined in "Foo"
void SomeFunction () { /* [...] */ }
}
class Baz {
void A () {
Foo a = new ("Foo");
Bar b = new ("Bar");
Foo c = bar;
a.SomeFunction (); // This will call Foo's SomeFunction
b.SomeFunction (); // This will call Bar's SomeFunction
c.SomeFunction (); // This will call Foo's SomeFunction
}
}
¹: Also known as
"symbol⁴ hijacking" or "symbol shadowing" in the general case.
²: And many other languages too. However, as far as I know nowadays it's not too common in new languages, because it only leads to bugs - there's not really any situation in which it won't cause needless confusion.
³: This is because virtual functions work differently than non-virtual ones - it chooses the function that needs to be called entirely at runtime, usually through something called a
vtable, which is a list containing pointers to all the virtual functions of the type.
⁴: This is a term used to refer to the names of things like variables, functions, classes, etc.