Object oriented programming in Nasal: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
(wip - adding my forum posting here as a stub for later improvement)
 
mNo edit summary
Line 34: Line 34:


Of course, one may still use objects like conventional variables for passing and returning parameters.
Of course, one may still use objects like conventional variables for passing and returning parameters.
[[Category:Nasal]]

Revision as of 08:32, 4 October 2011

"Object Oriented Programming" is all about creating "things" (i.e. a cloud) with "actions" (transform,draw,update) (or "messages"). Where a class (or hash in Nasal) is the "template" for a "thing" containing a number of member fields. So the class only describes the "layout" or properties of objects that can be created. To actually use a class, it has to be "instantiated" which means creating an object using a specific "template class" (or even several different classes).

These member fields can be variables (e.g. lat, lon, alt) or functions (setAlt, setPos). And the actual instance (cloud[n] in the property tree) of such a thing is then called an "object". Functions that work with instance specific state are called "methods", they may refer to instance specific state using a "self reference" (me) in Nasal, that ensures that access to a field or method is using the right instance specific data.

In OOP, internal state is managed by wrapping everything in a class using accessor functions for modifying and getting internal values. So internal state would in turn only be modified by an abstract interface: class "methods", instead of directly accessing class-internal fields.

This provides a way for managing access to a member variable (field), such an abstract interface is also useful for keeping logics private, and internal. For example, the name of a variable "altitude" can be easily changed internally to "altitude_ft", without having to rename all users of the class - simply because all other code will refer to the methods providing access to the field.

For example, instead of doing something like cloud.lat=10.22; cloud.lon=43.22; you would have a method accepting lat/lon variables: cloud.setPos(lat, lon);

That means that the actual variables containing the values for lat/lon are not exposed or used outside the actual object. This is called encapsulation and provides you with a way to manage state and ensure that internal state is valid at all times, because other code may only use the external interface.

This allows you for example to simply rename a class variable, without having to change any of the code that uses the object, because other code only uses class methods.

Another important thing in OOP is separation of concerns, i.e. you don't want to end up with huge bloated "super classes" that manage all sorts of different state, but instead use different classes where appropriate to split code into abstract "modules" with well defined responsibilities.

So, one of the very first steps to convert procedural code to OOP code would be to group your code into a number of logical "classes" (e.g. cloud, cloud field ).

Classes may be composed of other classes, i.e. a "cloud field" class would in turn contain "cloud" classes. This is then called "composition".

Another way is inheritance, where a type may inherit properties (fields:variables and methods) from a "parent" class. Imagine it like taking a "template" for the class and then saying "make a new class using this template".

Inheritance has the added advantage of providing a means to customize class behavior without having to modify the actual class, because all member fields can be parametrized.

For example, a "cumulus" cloud class could be derived from the "cloud" class, just by parametrizing it (different cloud model, different texture, different transformations), without touching anything in the actual "cloud" class.

This is basically how OOP may be understood: things are classified according to "is a" or "has a" relationship.

Of course, one may still use objects like conventional variables for passing and returning parameters.