Function Reference: Difference between revisions

Jump to navigation Jump to search
1,555 bytes removed ,  15 January 2013
imported>Ereksen
mNo edit summary
imported>Lofgren
Line 22: Line 22:
|-
|-
|style="border-style: solid; border-width: 0"|[[Image:InDepth.jpg|48px]]
|style="border-style: solid; border-width: 0"|[[Image:InDepth.jpg|48px]]
|style="border-style: solid; border-width: 0"|If you're wondering what is a "Self" variable, it is a natural consequence of object oriented programming which propagates, along with everything else, the concept of a class and an instance of that class, also called an object. A very common example for explaining the class/instance relationship is the difference between a blueprint of a car and the actual car which is made from that blueprint. You can have a bunch of cars based upon a single blueprint. For anything useful, you can't know all the cars that are going to be created from your blueprint, so you need a method of determining upon which car has some function been invoked/used. To be direct, you can't turn on the radio of a blueprint, it's a piece of paper. But you can do it in a real car, made from the blueprint. One might tune in to a hard rock station. And another car could tune to a station that plays Rebecca Black's song "Friday" all day. Now, Replace the word "blueprint" with "class" and "car" with "instance/object" in your head. That difference is crucial, capture it. The way you find out which object is being possibly modified by a function is by silently pushing in an additional hidden parameter to a function which contains the memory address of the "victim" object, of the logical name "Self". In some languages, '''self''' is called '''this'''.
|style="border-style: solid; border-width: 0"|
<br>
The "self" variable is a natural consequence of object oriented programming. Object oriented programming relies on the concept of an abstract ''class'' and an ''instance'' of that class (An instance may also be called an ''object''.)


On a serious note, one could ask: "'''Why should I ever want to use this "Self" variable when I can simply change any variable I want directly? I know they exist in the blueprint, therefore they are also in the instance. That's the whole point, is it not?'''" Sort of, young samurai. But not really, everything you do actually is resolved by the compiler to use the '''this/self''' pointer. If you change an integer member variable '''something''' to 5, what you do is: "'''something = 5;'''". What actually happens internally is "'''self->something = 5;'''". '''Self''' is your silent guardian, a watchful protector... A dark knight.
The relationship between a class and an instance is similar to the difference between a blueprint of a car and the actual car that is made from that blueprint. A single blueprint may be the basis for many cars. The blueprint is an abstraction. You cannot interact act with it. For example, you can't turn on the radio of the car in the blueprint. It's a piece of paper. In order to turn on the radio, you need to interact with the actual car. The blueprint is the class, and the car is the object. The way you find out which object is being acted upon by a function is to refer to the self. For example, ''self.TurnOn(theRadio)'' will turn on the radio of the car that calls that function, and only that one car.


Here's just a simple taste from general programming which includes '''Self''''s explicit usage, imagine that you've got a function invoked on an object (sometimes called a '''non-static member function/method''' or perhaps an '''instance-level member function/method''') that takes a parameter that points to an object of the same class. And you want to make sure you're not being fed the very object the function has been invoked upon. That mouthful is referred to as "self-reference". With "Self", you can check whether pObject is equal to Self and prevent damaging or unnecessary code from executing. If you can't think of a useful application of this example, it comes in handy with dynamic memory management and functions called setters.
All functions are actually resolved by the compiler to use the '''this/self''' pointer. If a script changes an integer variable '''someInt''' to 5, what it looks like to us is: '''someInt = 5'''. Internally, that variable is labeled with, and considered a component of, the object that calls it, which could be written as '''self.something = 5'''


Here, let's pretend that you are trying to change an object crucial to your application and you want to release the old one because you're a good memory citizen who cares about his users and their limited memory resources. So, you want to first release the old object and then set the pointer to the new one, right? But what if a nasty scenario occurs where you replace the object with itself? You release the old object, set the pointer to the memory address of the "new" object (which is, actually, the old object), try to dereference it (a fancy word for "use it") and boom - a wild unicorn appears and destroys your application '''if you're lucky'''. Usually, the memory is just cleared to be overwritten, the system might not use it immediately, therefore, in some cases - your application could work and make your life miserable by reports of crashing. You made a dangling pointer which references an object that was released (by you, a moment ago). Do you, perhaps, see how you could solve this? Yes, exactly. If newObject is NOT equal to Self (newObject != Self), then release the object referenced by Self and change the Self pointer/variable to point to newObject (Self = newObject). And you've solved all of your life's troubles. Kittens are purring. Birds are singing. And gamers are cursing at the dragon that killed them because your game or mod is awesome.  
A simple example: imagine a function invoked on an object that takes a parameter that points to another object of the same class: '''car1.Ram(car2)''' (which should ram your car into another car). Obviously, the car cannot ram itself. By using the "Self" variable, we can ensure that car2 is not equal to Self and prevent damaging or unnecessary code from executing:
<br>
<source lang="papyrus">
;The function is called on one car like this.
Car1.Ram(car2)
 
;Then we write the function:
function Ram(object someVehicle)
 
;if someVehicle is the same as the car that the function was initially called on, kill the function and do not proceed to ram it.
if(someVehicle == self)
    return
else
    self.Moveto(someVehicle)
endIf
endFunction
</source>
<br>
Another example is a script that is trying to release an object it no longer needs so that the reference no longer consumes memory. However due to the its complexities, the script may accidentally end up referencing the same object. This is a dangling pointer, a reference to an object that was expected to be released. By comparing newObject to Self (''if(newObject != Self)''), we can be sure that when the old object is released it will be properly replaced by newObject.
|}
|}


Anonymous user

Navigation menu