Help request with b = Class(a)

Hello.
I am trying to use some generic classes a = Class() then b = Class(a). This way i am supposed to have some inheritance mechanism from a to b. If i write a simple (1) b = Class() then everything works fine. But when i do (2) b = Class(a), i get a lot of errors. It seems that when a function uses self with (1) everything is ok, but with (2) self seems to mean different things at different places. Some fields like self.timers that appear in a function, still have value nil while i just called a function that defines self.timers and checked it is not nil. It is probably due to the fact that self.timer is nil at compilation time, but it works well with (1) and not any more with (2). I just cant get what i am doing wrong. And the wiki article about class does not help very much: the solution is probably in the lua description of the class, but it is too complex for me, i dont understand this part at all.
Can anyone who went through the same problems help me? Or show me a link to a class tutorial that will help me to understand what is going on? That is so frustating! Of course I could write everything flat, but i’d like to understand how to use this (2) feature…
HEEEEELP!
PS: and because class implementation is CODEA specific, i cant find the solution on the web (what i usually do)

I found an old post http://twolivesleft.com/Codea/Talk/discussion/comment/393#Comment_393 where things are a bit explained. I think the key is in Simeons comment
I think the key line is how to initialise the base class, it’s Base.init( self, … ).
This syntaxt is weird, i dont understand why the usual Base:Init() does not work, nor why the Base.init() function has to be called at all… But i wonder if this is it? Are there some other caveats when we use base classes that make thing not Working, with respect to usual syntax? What are they? And how to avoid having any problem at all?
Oh, btw, my problem is not a tab order problem, which seemed to be the main source of nil values in the previous posts on class.

Can you post your code so we can get an idea of what you might be doing wrong? I suspect a tab order issue, but it’s hard to say until I can verify there aren’t issues with your code.

When you do b = Class(a) then b inherits the methods of a but if you want to assign variables then you have to call as constructor on b. However, you probably want to do this from within bs init function which has overwritten the one inherited from a. That’s why you have to call a.init(self) explicitly.


a = class()

function a:init(s)
    self.s = s
    self.t = "base"
    self.u = "random"
end

function a:show()
    print(self.s)
end

function a:whoami()
    print(self.t)
end

b = class(a)

function b:init(s)
    a.init(self,s)
    self.t = "child"
end

function b:listall()
    for k,v in pairs(self) do
        print(k .. ": " .. v)
    end
end

function setup()
    ma = a("first")
    mb = b("second")
    mb:listall()
    ma:show()
    mb:show()
    ma:whoami()
    mb:whoami()
end

function draw()
end

Thank you both for your help.
You explanation is clear and concise @Andrew_Stacey, thanks. It confirms the conclusions i had come to, after doing almost the same program as you did (with almost the same text var!). Some more questions:
A/
Could you explain why (1)a.init(self,s) works and (2) a:init(s) doesnt, while in principle it should?
Is it because in (1) self refers to b and in (2) self refers to a? If this is correct, why does self refer tob in the methods declared in a then?
B/
(1) is called in b:init(s), but there is no explicit declaration of a, so what is a referring to in this function? Is it: (3) a local-to-b copy of a or (4) the global description of a? Then does the init applies to all subclass of a or just to b? My own experiment seem to conclude (3). Is the line b=class(a) the line that first uses a as a global variable, copies all its methods into b, then defines a local-to-b variable called also a, which points to the same copied methods?
C/
Is there any other subtilities about using class(a) or is it all there? I mean: once i have called (1), does b behaves exactly as any other class, the variables and methods defined in a being simply accessible, with the same meaning of self in a, exactly as if the code of a had been simply pasted in b, just after the b=class(a) definition? Or are there still some cases where a methods will behave akwardly?
Oh, btw, the root cause of my post was an error in my code, but my questions still hold anyway.

good questions, Jmv38

A/ I can see that a:init(s) would be referring to a’s self, and we want it to be b, hence the need for a.init(self,a).

I’m guessing that once you’ve declared b=class(a), then Codea makes a copy of the a class for b, so self refers to b after that

B/ I’m guessing that the a in a;init(self,s) refers to a generic a, not a specific instance, because there is none at this point. The a class is just a template

My take on this is that the only need for a.init(self,s) is that if you write a function called b:init, it overrides the init function inherited from a, so you have to call a’s init function “manually” and rather clumsily.

Why not do this instead - take all the code out of a:init, then there’s no need to call a at all.

a=class{}
function a:init(s)
    self:settings(s)
end

function a:setting(s,t,u)
  self.s=s 
  self.t=t or "base"
  self.u=u or "random"
end
--------rest of a's code -----

b=class(a)
function b:init(s)
  self:setting(s,"child") 
end


A. As Ignatz says, the a is not an instance of class a so calling a:init() makes no sense in any situation. In general, if x is an instance of class c then calling x:function(args) is the same as calling c.function(x,args). So calling a:init(args) will call a.init(a,args). If doing this from within b’s init function then we cannot call self:init(args) because that will call b’s init function again (and, in all probability, get into an infinite loop). So we need to call a’s init function explicitly because we have no other way to refer to it.

Ignatz method gets round this by ensuring that b has a way to refer to a’s init method by making a’s true init method is not called init and so is not overwritten by defining b’s init method.

Incidentally, another way around it would be for b not to define an init method at all. You could have:

a = class()
function a:init(s)
    self.s = s
    self:settings(s)
end

function a:settings(s)
end

b = class(a)

function b:settings(s)
    self.ns = s .. "wibble"
end

Here, a defines a “generic” settings method that does nothing. b puts some substance into it.

B. It’s the global copy. One thing you could do is put lots of print(a) print(b) print(self) statements all over the place. This will tell you the table number of each and give you a way to track which was which.

Issuing b = class(a) does the first step of what you describe in that it copies all of the methods of a to b. But it doesn’t create a local copy of a. You can see this by modifying the a:init() function after calling b = class(a). Calling a.init(self) inside b’s init function uses the modified version not the original one.

C. I’m always hesitant at saying that there aren’t any further complications, but I think you’ve got the main ones there so I would proceed on that assumption.

Thank you both.
I think i’ll use the recommendation of @ignatz for the init: i had come to the same conclusion as @Andrew first, but i was annoyed because then the only way to test my supercalss was to create a subclass of it, then test the subclass. it makes the test process more complex.
[EDIT] i suppressed a variant posted here, that was just full nonsense…[EDIT]
I think the last trick that may come into the way is that the inherited methods are all pointing to the original class methods. So if i change a method a.m=f1 of a to a.m=f2 after doing b=class(a), then b.m will still be f1, not f2. This would not be the case if i had done directly b.m=f2. This is ok (it is a feature, not a bug) but it is different from the basic behavior that we would expect naively.
Subclasses are not good for naive persons like me…

This was really an informative discussion!! I also had issues with classes since there is little documentation on how to use them in Lua. So, based on the above talking points (correct me if I’m wrong), the following example would be the simplest way to implement inheritance:

a = class()

function a.init(self,...)
    self.setting(self,...)
end

function a:setting(...)
    s,t,u = ...
    self.s = s 
    print("self.s = ", self.s)
    self.t=t or "base"
    print("self.t = ", self.t)
    self.u=u or "random"
    print("self.u = ", self.u)
end

function a:show()
    print("Show = ", self.s)
end

function a:whoami()
    print("WhoamI = ", self.t)
end

-------- Then in the Main Tab -------------
b = class(a)

function b:init(s)
  self:setting(s,"child", "unrandom")
end

function setup()
    ma = a("first")
    mb = b("second")
    ma:show()
    mb:show()
    ma:whoami()
    mb:whoami()
end

function draw()
end

Ric, I’ve just done a post on this topic here

http://coolcodea.wordpress.com/2013/04/15/33-class-inheritance-in-codea/

and if you look back to my post 7 & 8

http://coolcodea.wordpress.com/2013/03/22/7-classes-in-codea/

you’ll find a detailed discussion of classes, and especially “self”, which had me puzzled for a long time at first

@Ignatz… Well done. Those are excellent tutorials. That’s probably the best explanation of ‘self’ I’ve read. Now, I just need to study your other 36 tutorials.