Mixins + Inheritance

Forum rules
Please don't bump threads here if you have a problem - it will often be forgotten about if you do. Instead, make a new thread here.

Post a reply

Smilies
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :geek: :ugeek: :!: :?: :idea: :arrow: :| :mrgreen: :3: :wub: >:( :blergh:
View more smilies

BBCode is OFF
Smilies are ON

Topic review
   

Expand view Topic review: Mixins + Inheritance

Re: Mixins + Inheritance

by phantombeta » Mon Apr 04, 2022 5:50 am

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.

Re: Mixins + Inheritance

by Graf Zahl » Mon Apr 04, 2022 5:22 am

This behaves as would be expected. The mixin function takes priority due to how mixins are handled by the compiler.

Mixins + Inheritance

by 4page » Sat Feb 12, 2022 9:09 am

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.

Spawn the Test_Child class, or uncomment the Test_Mixin2 line to see.

Code: Select all

Mixin Class Test_Mixin1
{
	void Test_Function()
	{
		console.printf(string.format("This is the mixin #1"));
	}
}

Class Test_Parent : ACTOR
{
	void Test_Function()
	{
		console.printf(string.format("This is the Parent Actor"));
	}
	Default
	{
		+NOINTERACTION;
	}
	States
	{
		Spawn:
			TNT1 A 0 Nodelay Test_Function();
			Stop;
	}
}

Mixin Class Test_Mixin2
{
	void Test_Function()
	{
		console.printf(string.format("This is the mixin #2"));
	}
}

Class Test_Child : Test_Parent
{
	Mixin Test_Mixin1;
	//Mixin Test_Mixin2;
}

Top