FlightGear Newsletter April 2014: Difference between revisions

Jump to navigation Jump to search
m
→‎FlightGear/Oculus Rift Experiments: http://forum.flightgear.org/viewtopic.php?f=30&p=206855#p206855
m (→‎FlightGear/Oculus Rift Experiments: http://forum.flightgear.org/viewtopic.php?f=30&p=206855#p206855)
Line 86: Line 86:
Links to ongoing discussion at the development list:
Links to ongoing discussion at the development list:
[http://sourceforge.net/p/flightgear/mailman/message/32183541/] [http://sourceforge.net/p/flightgear/mailman/message/32185064/] [http://sourceforge.net/p/flightgear/mailman/message/32185188/] [http://sourceforge.net/p/flightgear/mailman/message/32185412/] [http://sourceforge.net/p/flightgear/mailman/message/32185690/] [http://sourceforge.net/p/flightgear/mailman/message/32185691/] [http://sourceforge.net/p/flightgear/mailman/message/32185923/]
[http://sourceforge.net/p/flightgear/mailman/message/32183541/] [http://sourceforge.net/p/flightgear/mailman/message/32185064/] [http://sourceforge.net/p/flightgear/mailman/message/32185188/] [http://sourceforge.net/p/flightgear/mailman/message/32185412/] [http://sourceforge.net/p/flightgear/mailman/message/32185690/] [http://sourceforge.net/p/flightgear/mailman/message/32185691/] [http://sourceforge.net/p/flightgear/mailman/message/32185923/]
=== Under the Hood of: Nasal OOP (by Philosopher & galvedro) ===
Nasal does not have the concept of "classes", understanding by a class an object definition that cannot exist as an instance on its own. What we always have in Nasal is hashes that perhaps reference other hashes via the parents vector.
The parents vector is just a symbol lookup trick. The only thing it does is to add other hashes as targets where Nasal can search for symbols that are not defined in the current hash. This servers for implementing object inheritance in a traditional way as long as:
# The symbols that you expect to be gathering from the parented hashes are functions. This is because when you are executing a function in a parent hash, the me symbol will allow you you to resolve the context back to the instance hash down the hierarchy.
# Non function members that are expected to be kept per instance, are defined in the instance hash. Otherwise those members might end up being shared across derived hashes due to the parents lookup mechanism.
# Members that are expected to be shared across different instances are defined in the template hash and not in the instances themselves. Which means that you have to be careful on how you write values to them or you will end up creating a new member in the instance hash that will shadow the shared member. (Mmm, this one is a dangerous pitfall, but I remember seeing this explained in the wiki, and is not that often that you need this...).
The me reference is a syntactic trick, and it can be dangerous to use depending on the usage pattern, so some good practices are in order, in particular
1. When writing a constructor in a template object, do not use me in the parents vector, because me will resolve to a hash reference only when the new() method is called, and which hash will it be depends on how the method is called.
2. When calling a "super" class method from an overriding method, use the Nasal call() library function, specifying the instance hash as the me parameter. If you use the parents vector directly, me will likely end up referring to a template hash instead and you will loose the instance context.
Basically you have an expression on the left side of a dot, and then a lvalue and parenthesis on the right side -- no exceptions! The expression is evaluated once, with the value being DUP'ed (duplicated/copied) and used both for the member get (i.e. what is the function contained in the hash) and as a special argument to the function (now a method) call. That "me" is then set as a symbol like an argument, originating from the left-hand expression, and is otherwise unset.
In other cases, using the call() builtin, it is possible to specify the me reference manually, but what "me" is, is otherwise a consequence of how it is called. If the syntax differs, there is no me local variable. (One common example is passing a MEMBER of an object to a function as a parameter or saving it to a variable - i.e. then it doesn't matter if it is a function or not.) (I use MEMBER here to distinguish from METHODS, where a METHOD uses "me" and a MEMBER doesn't.)
The thing with a func {} expression is that it delays evaluation, so it can keep the proper syntax for the method call and therefore pass the correct me reference, which is preserved in its closure.
Parents inheritance is really simple: to find a member you search for it in the current hash or try finding it in each parent (indexes 0..n), throwing an error if there is too much recursion. Basically, inheritance is implemented such that there's a mutable parents vector that maintains a list of hashes that are used for recursive symbol lookups, me will be defined per instance and point to the outer hash. Which is why shadowing can occur.
'''me''' is also mutable, i.e. if it isn't defined, it can be explicitly defined, or passed via call() - a mehod which we tend to use in MapStructure whenever we want to ensure that the proper instance is passed, i.e. no variable shadowing taking place.
* FUNC() -> no me
* OBJ.METHOD() -> me = OBJ
* (OBJ.MEMBER_FUNC)() -> no me
* (EXPR).METHOD() -> me = (EXPR)
Continue reading at [[Object oriented programming in Nasal]]...


=== FlightGear/Oculus Rift Experiments ===
=== FlightGear/Oculus Rift Experiments ===

Navigation menu