|
|
(8 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
| {{User:Merlin11188/Templates/NoEdit}} | | {{User:Merlin11188/Templates/NoEdit}} |
|
| |
|
| ==[[Fields]] and [[Methods]]==
| |
| Object-Oriented Programming, often called ''OOP'', is a type of programming that focuses primarily on '''objects''', or [[Data_Types|data types]] that have fields and methods. Fields are like [[variables]], and [[methods]] are like functions; however, there is one fundamental difference: [[fields]] and [[methods]] are stored inside of an object, to be called through that object. This definition corresponds perfectly to [[tables]] in Lua. A class refers to the type of object. Let's say that we want to create an object class named {{`|account}}, with the field {{`|balance}}, and the methods {{`|input}} and {{`|withdraw}}. The first thing to do is to make a prototype with these fields and methods:
| |
| {{Code and output|fit=output|code=
| |
| account = {
| |
| balance = 0, -- Declare field 'balance'
| |
| input = function(self, amount) -- We want this to be a method, so we set it up like one
| |
| -- Test the validity of value passed to parameter 'amount'
| |
| amount = (type(amount) == "number" and amount) or (type(amount) == "string" and tostring(amount)) or error("Invalid amount", 2)
| |
| self.balance = self.balance + amount
| |
| end,
| |
| withdraw = function(self, amount) -- Method, set it up like one
| |
| -- Test the validity of value passed to parameter 'amount'
| |
| amount = (type(amount) == "number" and amount) or (type(amount) == "string" and tostring(amount)) or error("Invalid amount", 2)
| |
|
| |
| -- Is it possible to get this much money from your account?
| |
| if self.balance >= amount then
| |
| self.balance = self.balance - amount
| |
| return self.balance
| |
| else
| |
| error("Attempt to overdraw account!", 2)
| |
| end
| |
| end
| |
| }
| |
|
| |
|
| print(account.balance) -- Fields use periods
| | {{Stub}} |
| account:input(300) -- Methods use colons
| | {| |
| print(account.balance)
| | |[[File:Home_Subpage.png|frame|A picture of the 'Home' tab on the submenu in 'My ROBLOX'.]] <br/> |
| account:withdraw(175)
| | |} |
| print(account.balance)
| | __TOC__ |
| |output= | |
| 0
| |
| 300
| |
| 125
| |
| }}
| |
|
| |
|
| That worked! We input 300 and then withdrew 175. But there's a problem. What if we want to add a second account? We might do something like this:
| |
| {{Code and output|fit=output|code=
| |
| account:input(150)
| |
| print(account.balance)
| |
| |output=
| |
| 275}}
| |
| What happened there? {{`|account}} '''still refers to the other account'''. So, how do we solve this problem? Using '''constructors'''
| |
|
| |
|
| ==Constructors== | | ===Character and Notifications=== |
| Constructors are functions that are called when you ''create'' a new object. Using the previous example, a constructor might look like this:
| | {| |
| <code lua>
| | |On the far left of the page there is a picture of [[My_Character|your character]]. Underneath, there is a link to your system notifications. |
| accou
| | |[[File:Avatar_Notifications.png|frame|A picture of [[My_Character|your character]] with system notifications beneath it.]] |
| | |} |
|
| |
|
| ----
| | ===Best Friends=== |
| This definition creates a new function and stores it in field withdraw of the Account object. Then, we can call it as <br> | | {| |
| | |Underneath of your avatar and notification box is your [[Friends#Best_Friends|best friends]] list. Here you can see what your best friends are doing (from their [[My_Home#Status_Update|shout box]]) and whether or not they're online. |
| | |[[File:Best_Friends.png|frame|This a list of your [[Friends#Best_Friends|best friends]] and their most recent shouts!]] |
| | |} |
|
| |
|
| <code lua>
| | ===Status Update=== |
| Account.withdraw(100.00)
| | {| |
| print(Account.balance)
| | |You can use this so that people who visit your profile can see what you're up to. |
| </code>
| | |[[File:Status Update.png|frame|This is the status update bar. People who have you as their [[Friends#Best_Friends|best friend]] will see it on their [[My_Home|home]]!]] |
| | |} |
|
| |
|
| This kind of function is almost what we call a method. However, the use of the global name Account inside the function is a bad programming practice. First, this function will work only for this particular object. Second, even for this particular object the function will work only as long as the object is stored in that particular global variable; if we change the name of this object, withdraw does not work any more:
| | ===Feed=== |
| | {| |
| | |Your feed is in the center of the page, just beneath your status update box. Your feed is a way to keep you updated with all of your groups. Every time someone uses the shout box in one of your [[groups]], you're updated here! |
| | |[[File:Feed bar.png|frame|This is for your feed—all of your [[groups]]' shouts go here.]] |
| | |} |
|
| |
|
| <code lua>
| | ===Recently Played Games=== |
| a = Account; Account = nil
| | {| |
| a.withdraw(100.00) -- ERROR! | | |On the far right is the 'Recently Played Games' box. Your most recently played games can be seen here. If you want a larger list, you can click the '''See More''' button. |
| </code>
| | |[[File:Recently_Played_Games.png|frame|This is a list of your most recently played [[game]]s.]] |
| | |} |
|
| |
|
| Such behavior violates the previous principle that objects have independent life cycles.
| | ===Facebook Connect=== |
| A more flexible approach is to operate on the receiver of the operation. For that, we would have to define our method with an extra parameter, which tells the method on which object it has to operate. This parameter usually has the name self or this:
| | {| |
| | |On the far right, underneath of the 'Recently Played Games' box is the Facebook connect box. If you have a Facebook account, you can link it to your ROBLOX account! See [[connecting your account to Facebook]] for more info. |
| | |[[File:FacebookConnect_Unconnected.png|frame|Facebook connect. You can use this to link your Facebook account to your [[Roblox|ROBLOX]] account! Your personal info will '''not''' be shared with other users!]] |
| | |} |
|
| |
|
| <code lua> | | <!-- |
| function Account.withdraw(self, v)
| | {| class="wikitable" style="border-spacing: 0px; padding: 0px;" |
| self.balance = self.balance - v
| | |- |
| end
| | |[[File:Avatar + Notifications]] |
| </code>
| | |[[File:Status_Update.png]] |
| | | |[[File:Recently_Played_Games.png|287px]] |
| Now, when we call the method we have to specify on which object it has to operate:
| | |- |
| | | |[[File:Best_Friends.png]] |
| <code lua>
| | |<div style="top:0px;">[[File:Feed_bar.png]]</div> |
| a1 = Account; Account = nil
| | |[[File:FacebookConnect_Unconnected.png]] |
| ...
| | |}--> |
| a1.withdraw(a1, 100.00) -- OK
| |
| </code>
| |
| | |
| With the use of a self parameter, we can use the same method for many objects:
| |
| | |
| <code lua>
| |
| a2 = {balance=0, withdraw = Account.withdraw}
| |
| ...
| |
| a2.withdraw(a2, 260.00)
| |
| </code>
| |
| | |
| This use of a self parameter is a central point in any object-oriented language. Most OO languages have this mechanism partly hidden from the programmer, so that she does not have to declare this parameter (although she still can use the name self or this inside a method). Lua can also hide this parameter, using the colon operator. We can rewrite the previous method definition as
| |
| | |
| <code lua>
| |
| function Account:withdraw (v)
| |
| self.balance = self.balance - v
| |
| end
| |
| </code>
| |
| | |
| and the method call as
| |
| | |
| <code lua>
| |
| Account:withdraw(100.00)
| |
| </code>
| |
| | |
| The effect of the colon is to add an extra hidden parameter in a method definition and to add an extra argument in a method call. The colon is only a syntactic facility, although a convenient one; there is nothing really new here. We can define a function with the dot syntax and call it with the colon syntax, or vice-versa, as long as we handle the extra parameter correctly:
| |
| | |
| <code lua>
| |
| Account = {
| |
| balance=0;
| |
| withdraw = function (self, v)
| |
| self.balance = self.balance - v
| |
| end
| |
| }
| |
| | |
| function Account:deposit (v)
| |
| self.balance = self.balance + v
| |
| end
| |
| | |
| Account.deposit(Account, 200.00)
| |
| Account:withdraw(100.00)
| |
| | |
| print(Account.balance)
| |
| </code>
| |
| | |
| Now our objects have an identity, a state, and operations over this state.
| |
| | |
| == Constructors ==
| |
| So far, we've shown how to create a single once-use object. However, we might want to manage multiple accounts. Here's how we do it:
| |
| | |
| <code lua>
| |
| Account = {}
| |
| function Account.new(balance)
| |
| return setmetatable({balance = balance}, Account})
| |
| end
| |
| Account.__index = Account
| |
| </code>
| |
| | |
| This creates the constructor {{`|Account.new(balance)}}, which returns a new account object. The {{`|setmetatable}} makes it so the new account will look in the {{`|Account}} table for its metamethods, and the metamethod {{`|Account.__index = Account}} makes it look in the {{`|Account}} table for its methods. Let's add some methods then!
| |
| <code lua> | |
| function Account:withdraw(v)
| |
| self.balance = self.balance - v
| |
| end
| |
| function Account:deposit(v)
| |
| self.balance = self.balance + v
| |
| end
| |
| function Account:__tostring()
| |
| return "Account(" .. self.balance .. ")"
| |
| end
| |
| </code> | |
| | |
| To use it:
| |
| | |
| {{code and output|code=
| |
| local a = Account.new(100)
| |
| local b = Account.new(200)
| |
| print(a, b)
| |
| | |
| a:withdraw(20)
| |
| b:deposit(40)
| |
| print(a, b)
| |
| |output=
| |
| Account(100) Account(200)
| |
| Account(80) Account(240)
| |
| }}
| |
| | |
| == See also ==
| |
| | |
| *[http://www.lua.org/pil/16.html Programming in Lua: Object-Oriented Programming]
| |
| *[http://lua-users.org/wiki/ObjectOrientationTutorial lua-users wiki: Object Orientation Tutorial]
| |