Page 1 of 1

30log is not polymorphic?

Posted: Thu Jan 11, 2018 12:09 pm
by Marty
Hiho lövely fellows,

it seems that 30log does not follow all definitions of OOP, thus not fulfilling my desire. Maybe I lack to know how this is done right in 30log, so I want to ask for advice.

Polymorphic code allows child classes to effectively override functions of the parent classes. The object itself ends up with different/new implementations of the base functions. If the parent class code executes a function that is overridden in the child class, it will jump into the child implementation, since the base implementation is not existent on the object, anymore.

Here is a brief example how it should work, written in C# (because its OOP and its syntax is easy):

Code: Select all

using System;

class A {
	public A() {
		Console.WriteLine(test());
	}
	protected virtual string test() {
		return "A";
	}
}
class B : A {
	public B() : base() {
	}
	protected override string test() {
		return "B";
	}
}
public class Program
{	
	public static void Main()
	{
		new A(); // prints "A"
		new B(); // prints "B"
	}
}
.NET Fiddle to test the code: https://dotnetfiddle.net/F6vpbM

Here is a similar implementation of the above code using lua and 30log:

Code: Select all

local class = require "30log"

local A = class("A")
function A:init()
  print(self.test())
end
function A:test()
  return "A"
end

local B = A:extend()
function B:init()
  B.super:init()
end
function B:test()
  return "B"
end

A() -- prints "A"
B() -- should print "B", but prints "A"
Repl.it to test the code: https://repl.it/repls/GivingFuchsiaDamselfly (it includes 30log, scroll down for the code)

The problem is very obvious. The constructor of B calls the constructor of A. The constructor of A prints the returned value of the test function. Since the test function is overridden in B, it should use the test function of B, even when called by A, since the object is B that inherits from A, not A. 30log, however, does not do this. It uses only the implementation on the class that it was called from.

Since lua has no real OOP and just works with tables, I see the problem. the super table of B has the test implementation of A. Imo, it should somehow know that the test function was overridden in B and call this instead, or do I do something wrong here?

Re: 30log is not polymorphic?

Posted: Thu Jan 11, 2018 12:29 pm
by Marty
For anybody facing the same issue, I got help on Discord by alloyed.

The problem is how I call the base constructor. Instead of

Code: Select all

B.super:init()
I've to use

Code: Select all

B.super.init(self)
otherwise I give super to the base and super does not include my overridden implementations.

Re: 30log is not polymorphic?

Posted: Thu Jan 11, 2018 2:20 pm
by zorg
modiX wrote: Thu Jan 11, 2018 12:29 pm I've to use

Code: Select all

B.super.init(self)
otherwise I give super to the base and super does not include my overridden implementations.
Note that self isn't magic in that context; you'd need to do

Code: Select all

B.super.init(B)
(which is what you wanted) at the call site, since self as an implicit thing can only exist in a function definition if it's done with the colon syntax. In short, B wasn't named self, so it wouldn't have worked that way.

Re: 30log is not polymorphic?

Posted: Sat Jan 13, 2018 12:51 am
by Marty
zorg wrote: Thu Jan 11, 2018 2:20 pm Note that self isn't magic in that context; you'd need to do

Code: Select all

B.super.init(B)
(which is what you wanted) at the call site, since self as an implicit thing can only exist in a function definition if it's done with the colon syntax. In short, B wasn't named self, so it wouldn't have worked that way.
What? I'm confused. When I call B() anywhere outside self is B, it's not? I think I still lack understanding how 30log really works under the hood, can you clarify even more?

Re: 30log is not polymorphic?

Posted: Sat Jan 13, 2018 4:38 am
by zorg

Code: Select all

local class = require "30log"

local A = class("A")
function A:init()
  print(self.test())
end
function A:test()
  return "A"
end

local B = A:extend()
function B:init()
  B.super.init(B) -- <- talking about this;
end
function B:test()
  return "B"
end

A() -- prints "A"
B() -- should print "B", but prints "A"
although now i realize that self does work here, but again, it's way more clearer to write it out completely in my opinion.

Re: 30log is not polymorphic?

Posted: Thu Jan 18, 2018 2:49 pm
by kikito
I don't know the internals of 30log, but in middleclass you have to pass self to superclass constructors, not the class. I remember giving this a great deal of thought back in the day, and there was no other way. self is indeed "magical" inside constructors.

I would be very surprised if 30log worked in a different way, as zorg is suggesting. I think you must pass self.

Re: 30log is not polymorphic?

Posted: Sat Jan 20, 2018 10:09 pm
by Marty
So in my test passing B didn't work, but passing self did. I agree with you, kikito.