Board index FlightGear Development Nasal

Inheritance in Nasal  Topic is solved

Nasal is the scripting language of FlightGear.

Inheritance in Nasal

Postby xcvb » Sun Feb 11, 2018 9:53 am

I just don't get how inheritance works in Nasal. I have the following example:

Code: Select all
var Parent = {
   new: func(id=0) {
      var obj = {parents: [Parent]};
      obj.id = id;
      return obj;
   },
   getInfo: func {
      print("no info\n");
   },
   getId: func {
      print("id: ", me.id, "\n");
   }
};

var Child = {
   new: func(id=0) {
      var obj = {parents: [Child, Parent]};
      Parent.id = id;
      return obj;
   },
   getInfo: func {
      print("I am a Child\n");
   }
};

var Dog = {
   new: func {
      var obj = {parents: [Dog, Parent]};
      return obj;
   }
};

var child1 = Child.new(1);
var child2 = Child.new(2);
var dog = Dog.new();

child1.getInfo();
child1.getId();
child2.getInfo();
child2.getId();
dog.getInfo();
dog.getId();


I expected the following result:
I am a Child
id: 1
I am a Child
id: 2
no info
id: 0


But I get:
I am a Child
id: 2
I am a Child
id: 2
no info
id: 2


I wonder what I do wrong.
xcvb
 
Posts: 77
Joined: Sat Mar 14, 2015 2:08 pm
Version: 2018.1.1
OS: Fedora 27

Re: Inheritance in Nasal

Postby Hooray » Sun Feb 11, 2018 12:40 pm

Note that you are not just asking about "inheritance" here, but about "multiple inheritance".
In Nasal, there is basically only hashes and two important keywords: parents and me.
parents is a hash-specific vector that contains a list of other hashes (treated as classes) that are used as "templates", me refers to the instance of a particular class, i.e. the equivalent of a this pointer.

Traversal of the parents vector happens in the list order - which is to say that any classes preceding your parent class, will also be looked up first.

http://wiki.flightgear.org/Object_Orien ... with_Nasal
http://wiki.flightgear.org/Howto:Start_ ... s_in_Nasal
http://wiki.flightgear.org/Object_orien ... g_in_Nasal
http://wiki.flightgear.org/Howto:Unders ... nd_Methods
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11124
Joined: Tue Mar 25, 2008 8:40 am

Re: Inheritance in Nasal

Postby xcvb » Sun Feb 11, 2018 1:25 pm

Thanks for your help Hooray!

It's a little strange for me that you call this "multiple inheritance", but ok, I had to derive from the base class and from itself to get access to all variables (in c++ this would be just single inheritance).

I see, unlike c++ the base class is not merged into the child class. Instead there separate parent and child instances and all children share the same parent instance. I guess this means duplicate code but I don't see how I can avoid this.
xcvb
 
Posts: 77
Joined: Sat Mar 14, 2015 2:08 pm
Version: 2018.1.1
OS: Fedora 27

Re: Inheritance in Nasal  

Postby xcvb » Sun Feb 11, 2018 1:31 pm

OK, this way it works:

Code: Select all
var Parent = {
   new: func(id=0) {
      var obj = {parents: [Parent]};
      obj.id = id;
      return obj;
   },
   getInfo: func {
      print("no info\n");
   },
   getId: func {
      print("id: ", me.id, "\n");
   }
};

var Child = {
   new: func(id=0) {
      var obj = {parents: [Child, Parent.new(id)]};
      Parent.id = id;
      return obj;
   },
   getInfo: func {
      print("I am a Child\n");
   }
};

var Dog = {
   new: func {
      var obj = {parents: [Dog, Parent.new(0)]};
      return obj;
   }
};

var child1 = Child.new(1);
var child2 = Child.new(2);
var dog = Dog.new();

child1.getInfo();
child1.getId();
child2.getInfo();
child2.getId();
dog.getInfo();
dog.getId();
xcvb
 
Posts: 77
Joined: Sat Mar 14, 2015 2:08 pm
Version: 2018.1.1
OS: Fedora 27

Re: Inheritance in Nasal

Postby Hooray » Sun Feb 11, 2018 1:36 pm

Actually, I said that ordering matters:

untested pseudo code:
Code: Select all

var Animal = {
new: func() {
return {parents:[Animal] };
},

};

var Carnivore = {

};

var Dog = {
new: func() {
return {parents:[Animal, Carnivore]};
}
};


Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11124
Joined: Tue Mar 25, 2008 8:40 am

Re: Inheritance in Nasal

Postby xcvb » Sun Feb 11, 2018 1:46 pm

Hooray wrote in Sun Feb 11, 2018 1:36 pm:Actually, I said that ordering matters:[/code]


The ordering was fine. Otherwise I cannot call the child implementation of getInfo. The solution was to create new parent instances for each child.
xcvb
 
Posts: 77
Joined: Sat Mar 14, 2015 2:08 pm
Version: 2018.1.1
OS: Fedora 27

Re: Inheritance in Nasal

Postby Hooray » Sun Feb 11, 2018 2:32 pm

I am not sure we're talking about the same thing here - I actually touched a bunch of Nasal tutorials over the years, some I created from scratch. It's great if you have found something that works for you - but Nasal OOP is not really sophisticated at all.

I suppose you will find the answer you're looking for by referring to the tutorials I posted (sorry, I am really only skimming most postings these days)
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11124
Joined: Tue Mar 25, 2008 8:40 am

Re: Inheritance in Nasal

Postby xcvb » Sun Feb 11, 2018 3:24 pm

All I wanted to do is to implement the general stuff like id-handling in the base class and the specific functionality in the derived classes.
This didn't work at first because:

Code: Select all
var obj = {parents: [Child, Parent]};

creates only one parent instance for all children so they all have the same id then. This can be solved in this way:

Code: Select all
var obj = {parents: [Child, Parent.new(id)]};

Now each child gets its own parent instance. I marked the issue as solved.
xcvb
 
Posts: 77
Joined: Sat Mar 14, 2015 2:08 pm
Version: 2018.1.1
OS: Fedora 27

Re: Inheritance in Nasal

Postby Hooray » Sun Feb 11, 2018 3:51 pm

Yes, the constructor of the parent class is not automatically called - however, what exactly are you trying to do in your Child class by accessing the Parent hash there and assigning it there ? The point being, that this would be equivalent off accessing a static (=shared) member in a C++ class.


That being said, id() is also a reserved keyword/library function in Nasal
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11124
Joined: Tue Mar 25, 2008 8:40 am

Re: Inheritance in Nasal

Postby xcvb » Sun Feb 11, 2018 4:25 pm

I'm not talking about the constructors. The issue is that all child instances share the same parent instance (same memory). So if I want to store the id in the parent class all children have the same id. This is not the case in C++. This is how the corresponding code would look like (no static members):

Code: Select all
#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(int id) : Id(id)
    {}

    void getId()
    {
        std::cout << Id << std::endl;
    }

private:
    int Id;
};

class Child : public Parent
{
public:
    Child(int id) : Parent(id)
    {}
};

int main(int argc, char *argv[])
{
    Child child1(1);
    Child child2(2);

    child1.getId();
    child2.getId();
    return 0;
}

Output:
1
2
xcvb
 
Posts: 77
Joined: Sat Mar 14, 2015 2:08 pm
Version: 2018.1.1
OS: Fedora 27

Re: Inheritance in Nasal

Postby Hooray » Sun Feb 11, 2018 4:30 pm

I do understand what you say - however, keep in mind that even your C++ code is actually calling the constructor that you have provided (C++ new keyword is unrelated to this, i.e. you are creating the object on the stack) - Nasal's CLASS.new() approach is just syntactic sugar for setting up a fresh hash instance - i.e. the names new() and del() are just used by convention.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11124
Joined: Tue Mar 25, 2008 8:40 am

Re: Inheritance in Nasal

Postby xcvb » Sun Feb 11, 2018 5:04 pm

OK, but something must be different with the memory. When I use parent.new it gives me the correct result but when I just use parent it does not.
xcvb
 
Posts: 77
Joined: Sat Mar 14, 2015 2:08 pm
Version: 2018.1.1
OS: Fedora 27

Re: Inheritance in Nasal

Postby Hooray » Sun Feb 11, 2018 5:47 pm

Yes, new memory for the hash/object is really only being allocated when the corresponding expressions is evaluated, i.e. var x = {};
Like I said previously, the sole purpose of the parents vector is to serve as a lookup method for hashes that are to be used as templates to look up the requested fields.
It's basically telling the engine a list of hashes that are to be traversed for symbol lookup
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11124
Joined: Tue Mar 25, 2008 8:40 am

Re: Inheritance in Nasal

Postby xcvb » Sun Feb 11, 2018 6:03 pm

Which is the best implementation to force the allocation of a new parent instance/object/hash then?
xcvb
 
Posts: 77
Joined: Sat Mar 14, 2015 2:08 pm
Version: 2018.1.1
OS: Fedora 27

Re: Inheritance in Nasal

Postby Hooray » Sun Feb 11, 2018 7:27 pm

You are doing this already, because the function used as the constructor (new) does evaluate the corresponding expresssion. Just don't mix up the purpose of the parents vector with object/memory allocation - it's primarily a vector that contains hashes to be traversed/used for symbol lookup purposes.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11124
Joined: Tue Mar 25, 2008 8:40 am

Next

Return to Nasal

Who is online

Users browsing this forum: No registered users and 1 guest