Howto:Understand Namespaces and Methods

From FlightGear wiki
Jump to navigation Jump to search

Namespaces

A namespace is a "context", i.e. an environment where a certain symbol (variable) is valid.

Imagine, three identical houses with rooms: Even otherwise identical rooms are kept in separate "environments", i.e. you have to refer to a certain "environment" (namespace) to uniquely identify a certain room, even though the design/architecture of each house is 100% identical, because they are all based on the sampe template (plan).

For example, imagine three bath rooms in these three houses: house1, house2, house3.

Now, imagine the users of the houses wanting to refer to each bath room using just the word (symbol/variable) "bath". To be able to resolve this properly, they will also need to qualify what house they are referring to, i.e. if it's house1, house2, house3.

house1.bath
house2.bath
house3.bath

Here, houseX is the enclosing namespace/context, i.e. "bath" is a member or "field" of the namespace.

Basically, namespaces make it possible to have identically named variables/symbols without them possibly "clashing" or "polluting" the global namespace. Imagine a namespace to be a container with its own variables and scope. So certain variables are only valid within that particular namespace.

Otherwise, you would have to use different symbols with explicit naming conventions, such as:

house1_bath
house2_bath
house3_bath

As you can see, these naming conventions can become awkward and inflexible pretty quickly:

      var wp1 = 0;
      var wp1alt = 0;
      var wp1dist = 0;
      var wp1angle = 0;
      var wp1length = 0;
      var wp1id = "";
      var wp1brg = 0;

      var wp2 = 0;
      var wp2alt = 0;
      var wp2dist = 0;
      var wp2angle = 0;
      var wp2length = 0;
      var wp2id = "";
      var wp2brg = 0;

      var wp3 = 0;
      var wp3alt = 0;
      var wp3dist = 0;
      var wp3angle = 0;
      var wp3length = 0;
      var wp3id = "";
      var wp3brg = 0;

      var wp4 = 0;
      var wp4alt = 0;
      var wp4dist = 0;
      var wp4angle = 0;
      var wp4length = 0;
      var wp4id = "";
      var wp4brg = 0;

      var wp5 = 0;
      var wp5alt = 0;
      var wp5dist = 0;
      var wp5angle = 0;
      var wp5length = 0;
      var wp5id = "";
      var wp5brg = 0;

Before namespaces were used, there were only such "global variables", so whenever some piece of code referred to a variable, it was possible to clash with some other similar or even unrelated uses of the variable (imagine a counter variable) somewhere else in the source code.

That's when people started providing a surrounding "context" to embed variables properly. In Nasal space, variables declared in functions will by default be specific to the function's scope and not be directly accessible:

    var hello = func {
      var x =100; # x is local variable specific to the scope of the currently executing function
    }

Here, x is declared to be specific to the "hello" function and its namespace, 'x' will only be valid and visible during the lifetime of function, i.e. at execution time. Consequently, this means that accesses to such variables will be invalid:

    var hello = func {
      var x =100; # x is local variable specific to the scope of the currently executing function
    }
    hello();
    print(x);

In Nasal, a namespace is just a conventional hash, which is a fancy word for a dictionary. A dictionary stores values in the form of key/value pairs, each value is linked to a key that can be used to look up said value:

 var foo = {};

To add members or fields to this "context" (or namespace), you can use several different notations, such as using conventional assignment:

 foo.altitude = 100; 
 foo["altitude"] = 100;

or even specify fields during initialization using a key, colon, value notation (key:value):

 var foo = { altitude:100 };

To add multiple keys to such a dictionary, you just separate them using a comma:

 var foo = { altitude:100, latitude:0, longitude:0 };

To make this easier you can always add a trailing comma, which is still valid Nasal:

 var foo = { altitude:100, latitude:0, longitude:0, };

In addition, it is valid to omit the key's value too:

 var foo = { altitude:, latitude:, longitude:, };

Which will be equivalent to initializing the value to nil:

 var foo = { altitude:nil, latitude:nil, longitude:nil, };

In order to access these fields or "members" of a namespace, you need to provide a valid namespace first:

print ( foo.altitude );

So, basically namespaces are all about organizing and structuring your variables and the overall symbol space. In object oriented programming, this concept is very powerful because you cannot only have hash-specific variables but also hash-specific functions. This makes it possible to create new objects by using a template hash and inheriting fields and behavior (methods).

Just imagine it like an "area code", where people living in different countries, states, districts, counties, towns get a DIFFERENT prefix code, even though they may have the same telephone number otherwise. The international prefix number (i.e. 001 for the US) makes it obvious that the following number is a US number, same goes for local area codes (752, 642, 543).

See Nasal scripting language#Namespaces for more information.

Methods

Methods are somewhat related to "namespaces" in that they are class-specific functions (OOP), i.e. functions that are specific to a certain instance of an already instantiated class. In Nasal space, this means that the function is embedded inside a Nasal hash and that it makes use of instance data (using "me") or accessing the parents vector.

For example, to switch off the lights in the bath room, there could be a method "switch_off_lights" in the "house" class:

house.bath.switch_off_lights

Obviously, this will only work if the switch off routine (method!) has some house to work with. The class itself really is just a "template" for functionality, before it can be used it needs to be instantiated, i.e. a new object (house) must be created using the template, and then the member functions (methods) can be called for that object.

See Nasal scripting language#More on methods for more information.

A tutorial along with source code examples going into more detail is available here: Howto: Start using vectors and hashes in_Nasal.

External links

Resources

For more detailed info on nasal namespaces see Nasal Namespaces in-depth

This article would not have been possible without FlightGear forum member Hooray and this topic.