Livecode Wiki
Advertisement

LiveCode is an object based language. It uses many different types of objects - buttons, windows, cards, stacks, fields, graphics, etc. But all of those are User Interface objects, each with its built-in properties and methods.

LiveCode is not an object oriented language, but it is flexible enough to allow programmers to add many object oriented features. However this takes careful planning, because its the programmer who will be responsible for setting up and maintaining those features.

This is the an article on Object Oriented Programming, which follows Inheritance. This is easy to setup and use, the costs come later when you have to deal with a whole class tree to take advantage of inheritance.

Classes[]

  • OOP - A class contains attributes and methods. An attribute is like a variable and a method is like a subroutine.  Usually, methods are public, meaning that they can be accessed by another method in any class. Usually, attributes are private, meaning that they cannot be accessed by another method except if that method is in the same class. A class must also contain a constructor method that creates an object of that class, also known as an instance of the class.
  • Implementation - In LiveCode, a class can only be implemented as a button or a stack. For convenience we will use a button. Therefore a button must be created for each class. The custom message handlers of that button will become the methods of the class and the custom properties will become the attributes of the class.
  • Creation - Since the user interface properties of a class are not used, classes must be hidden from the user. An easy way to do this is to create all the classes on a card which is never shown to the user. We will use a card called "Hidden". To create a class, build it manually using the IDE. Each class will be given a name by setting the built-in name property. The programmer can then keep track of each class by name.  

Inheritance[]

  • OOP -  Any class can inherit attributes and methods from another class. The class that inherits is called the child class. The class it inherits from is called the parent class. A parent class can have any number of child classes or none. At the top is the base class, a parent class over all the classes. It has several child classes and they in turn each have several child classes, and so on and so on. The classes fan out into a tree shape and they all inherit from the generations of classes before them, all the way back to the base class. A program usually involves several class trees, also called a forest.
  • Methods - To create the inheritance path from the parent class to its child class, set the behavior of the child class to the long ID of its parent class. Notice that while the inheritance path goes from the base class down the class tree to all the child classes, the message paths go in the opposite direction.
  • Attributes - All attributes must have a setter method to set its value and a getter method to get its value. When inheritance is set up, those methods will be inherited. It is recommended to create the attributes of a class by executing all the setter methods soon after setting up the inheritance of the classes. This will establish the attributes and give all of them an initial value. The use of setter and getter methods makes the classes more modular and self-contained.   

Objects[]

  • OOP - A class can have any number of objects or none. With the classes forming a tree, the objects are the leaves on that tree. Although usually, the objects are the instances of the lowest row of the class objects. Each object inherits the attributes and methods from its parent class, some of which might be inherited from classes further up the tree.  An object may also contain attributes and methods of its own. Each object has its own values for each of its attributes. Classes and objects are very similar, but it is the objects that are the active portion of the program and the classes only gets involved tangentially.
  • Implementation -  In LiveCode, an object can be implemented from any User Interface control. But for convenience we will use a button. Therefore a button must be created for each object. The custom message handlers of the button will become the methods of the object and the custom properties will become the attributes. An object will Inherit methods from its class by setting its behavior to the long ID of its class. When a message is sent to an object, it will follow the message path from the object to its class, then up the tree toward the base class looking for a method to execute.
  • Creation - Since objects do not use any user interface properties, they must be hidden from the user. An easy way to do this is to create the objects on the same hidden card as the classes. To create an object use the Constructor method of that class. The objects are usually not named, so the programmer should save a reference to the object to keep track of them. This is easily done by keeping such a list of objects in the base class.
  • Methods - An object will inherit all the methods of its class. Not often will it have any methods of its own. When a message is sent to an object by the send command, that object becomes the target. The message will continue from that object to its class and up the class tree until it finds an appropriate method. When that method is executed, the context remains with the object which first received the message, the target.
  • Attributes - An object usually does not have any attributes of is own. The setter and getter methods for the attributes are inherited from its class. It is recommended to create the attributes by executing all the setter methods soon after setting up the inheritance of the objects. This will establish each attribute and give them an initial value. The use of setter and getter methods makes the objects more modular and self-contained.  

Encapsulation[]

  • OOP - Encapsulation means that only the setter and getter methods for an attribute can access that attribute. This is also called data hiding, because its not possible to access the attributes directly. Therefore the rest of the code can only use the setter and getter methods to access the attributes of that object. In other words, the setter and getter methods are public and the attribute is private.
  • Setter methods - To make a private attribute put it on a customPropertySet which will never be set except by its setter methods. We will use the customPropertySet called Private, then all setter methods would have the following 4 steps.
First, set the customPropertySet to "Private". Second, validate the type and range of the value, this is optional. Third, set the attribute to the value. And fourth, set the customPropertySet back to empty. The programmer is responsible to not use the Private customPropertySet except with the setter and getter methods.
  • Getter methods - To make a private attribute put it on a customPropertySet which will only be getting by its getter methods. We will use the customPropertySet called Private, then all getter methods would have the following 4 steps.
First, set the customPropertySet to "Private". Second, get the value of the attribute. Third, set the customPropertySet back to empty. And fourth, return the value of the attribute. The programmer is responsible to not use the Private customPropertySet except with the setter and getter methods.

Interface[]

  • OOP - If an attribute or method can only be accessed from a method in the same object, that method or attribute is called private. If an attribute or method can be accessed from a method in any object, that method or attribute is called public. All public attributes and methods of an object are called the interface of an object.
  • Public methods - To make a public method, use a message handler. All such methods are public and are part of the interface of the object.
  • Private methods - To make a private method, use a private command handler. All such methods are private and are not part of the interface of the object. A private command handler cannot be inherited.
  • Public attributes -  To make a public attribute, put it on the default customPropertySet. All such attributes are part of the interface of the object. The setter and getter methods for those public attributes would have the following 4 steps.
First, set the customPropertySet to empty, this will make sure the attributes are public. Second, if this is a setter method, validate the type and range of the value, this is optional. Third, access the attributes by using the set or get commands. Fourth, if this is a getter method, return the value of the attribute.
  • Private attributes - To make a private attribute, use the explanation in the Encapsulation section above. All such attributes are private and not part of the interface of the object.

Overriding[]

  • OOP - An object inherits methods from its class by sending a message to the class and from there up thru the class tree toward the base class. The first method that matches the message is the one that is executed. This method overrides any otherwise inherited methods from further up the tree.
  • Methods - If inheritance is implemented by using behaviors, then overriding is a natural consequence.

Instantiation[]

  • OOP - The Constructor method (also called the Instantiation method) is the class method that creates an object of the class. Creating an object is also called making an instance of its class. Each class has a Constructor method of its own, overriding any other inherited Constructor method.  
  • Objects - In order to create an object, the Constructor method must do the following 6 steps. First, create a button which will become the object. This button will be created on a hidden card where the classes are also located. Second, a reference to the button is saved so that the programmer can keep track of that object. Third, the behavior of the object is set to the long ID of its class. This will setup the inheritance of the methods.
  • Methods - Fourth, create any new methods for this object. These methods will override any inherited class methods of the same name.
  • Attributes - Fifth, create the setter and getter methods for any new attributes of this object. Sixth, execute the setter methods for all attributes, including the inherited attributes. This will create all the attributes for the object and give them initial values.
  • Persistence - All attributes, methods, objects and classes will exist longer than the program. When the program resumes running, they will be the same as when the program ended before.

Polymorphism[]

  • OOP - Polymorphism means that two or more objects from different classes can have the same method name. Then the same message can be sent to all such objects and they will each execute their own method. The methods executed may be different, depending on the class the object is a member of.        
  • Methods - If inheritance is implemented by using behaviors, then polymorphism is a natural consequence.

Example[]

Now its time for an example program to show the ideas talked about above.

  • Create a new program named "Example"
Open up LiveCode. Click on the File menu -> New Stack -> Default Size. Using Property Inspector, name the main stack Example. Click on File menu -> Save. Unless you change it, the name of the main stack will become the name of the new program.
  • Name the first card of the "Example" stack as "Dashboard"
Using Property Inspector, name the first card Dashboard.
  • Create two fields on the Dashboard card and name them "Objects" and "Methods"
Using the Tools Palette, drag two fields onto the Dashboard card. Using the Property Inspector, name the first field as Objects. It will be used to display the messages to create objects. Using the Property Inspector, name the second field as Methods. It will be used to display the messages to execute methods.
  • Create a button on the "Dashboard" card, name it "Create" and add the mouseUp script below
Using the Tools Palette, drag a button onto the Dashboard card. Using the Property Inspector, name the button Create. Using the Edit Script, put the following script into the button Create.
on mouseUp
  send "getAllObjects" to button "base" of card "Hidden"
  put the result into objectList
  if the number of lines of objectList > 3 then exit mouseUp # Exit if > 3 objects
  
  put "Constructor 2" into message1                          # Create first object
  put message1 & return into field "Objects" of this card    # Display message1
  send message1 to button "Noise" of card "Hidden"           # Send message1
  
  put "Constructor 4" into message2                          # Create second object
  put message2 & return after field "Objects" of this card   # Display message2
  send message2 to button "Garbage" of card "Hidden"         # Send message2
  
  put "Constructor 6" into message3                          # Create third object
  put message3 & return after field "Objects" of this card   # Display message3
  send message3 to button "Garbage" of card "Hidden"         # Send message3
end mouseUp


The above method will send a message to the Noise class to instantiate an object. It will also send two messages to the Garbage class, each to instantiate an object. The three messages will be displayed in the Objects field. Additional clicking on the Create button will not create any more objects.
  • Create a button on the "Dashboard" card, name it "Run" and add the mouseUp script below
Using the Tools Palette, drag a button onto the Dashboard card. Using the Property Inspector, name the button Run. Using the Edit Script, put the following script into the button Run.
on mouseUp
  send "getAllObjects" to button "Base" of card "Hidden"
  put the result into objectList
  if objectList = empty then exit mouseUp                   # Exit if no objects
  
  put empty into field "Methods" of card "Dashboard"        # Clear Display
  put "Doing 2" into message1                               # message to all objects
  repeat for each line oneObject in objectList
     put message1 & return after field "Methods" of card "Dashboard"  
     send message1 to oneObject                             # Send message to object
  end repeat                                                # repeat for next object
  put empty into field "Methods" of card "Dashboard"        # Clear Display
end mouseUp
The above method will send all the objects the same message, "Doing 2". The object of the Noise class will execute its inherited Doing method and beep. The objects of the Garbage class will execute their inherited Doing method and display Garbage. The three messages will be displayed in Methods field until execution is finished, then the field will be cleared. The Run button may be clicked any number of times for the same action.
  • Create a button on the "Dashboard" card, name it "Delete" and add the mouseUp script below
Using the Tools Palette, drag a button onto the Dashboard card. Using the Property Inspector, name the button Delete. Using the Edit Script, put the following script into the button Delete.
on mouseUp
  send "getAllObjects" to button "Base" of card "Hidden"
  put the result into objectList
  if objectList <> empty then                              # Exit if no objects
     
     repeat for each line oneObject in objectList
        delete oneObject                                   # delete one object
     end repeat                                            # repeat for next object
     send "setAllObjects empty" to button "Base" of card "Hidden"
     put empty into field "Objects" of card "Dashboard"
     
  end if
end mouseUp
The above method will send a message to all objects to delete themselves. A message will also be sent to the Base class to clear the allObjects attribute. Another message will be sent to clear the field "Objects".
Now save the Example program.
  • Create a second card on stack "Example", name it "Hidden"
Click on the Object menu -> New Card. Using Property Inspector, name the second card Hidden.
  • Create a class on card "Hidden", name it "Base" and add script
Using the Tools Palette, drag a button onto the Hidden card,  Using the Property Inspector name the new button Base. Using Edit Script, put the following scripts into the button Base.
on Constructor Amount                             # Instantiation method
  create button in card "Hidden" of this stack
  put it into oneObject                           # it is a reference to object
  set the behavior of oneObject to the long ID of target   
  send "setHowMany Amount" to oneObject           # puts amount into howMany
  send "setAllObjects oneObject" to oneObject     # puts reference to object on list
end Constructor
on Doing myNumber
  send "getHowMany" to target 
  put the result into Many                      # get howMany
  beep (myNumber + Many)
end Doing
on setHowMany Amount                              # setter for private howMany
  put max(min(10,Amount),0) into Amount
  set the Private[howMany] of target to Amount
end setHowMany
on getHowMany                                     # getter for private howMany
  put the Private[howMany] of target into Amount
  return Amount
end GethowMany
on setAllObjects oneObject                        # setter for private allObjects
  if oneObject = empty then set the Private[allObjects] of button "Base" of card "Hidden" to empty
  else
     put the Private[allObjects] of button "Base" of card "Hidden" into myObjects
     put oneObject & return after myObjects
     set the Private[allObjects] of button "Base" of card "Hidden" to myObjects   
  end if
end setAllObjects
on getAllObjects                                  # getter for private allObjects
  put the Private[allObjects] of button "Base" of card "Hidden" into myObjects
  return myObjects
end getAllObjects


The Constructor method is used to instantiated an object. That object can be in the Noise class or the Garbage class. All objects are given an attribute "howMany" with an initial value. The behavior of each object is set to the long ID of its class. Each object will then inherit from its class.
The Doing method will beep a number of times. The exact number is the sum of the parameter and the custom property howMany.
The setHowMany method is the setter method for the howMany attribute of the objects. The getHowMany method is the getter method for the howMany attribute of the objects. The setter and getter methods are used to access the howMany attribute of the object and will be inherited from the Base class.
The setAllObjects method is the setter method for the allObjects attribute of the Base class. The getAllObjects method is the getter method for the allObjects attribute of the Base class. The setter and getter methods are used to access the Objects attribute in the Base class can be inherited by the other classes and all objects.
Its now time to complete the initialization of the Base class. Use the Message Box to execute the following command.

send "setAllObjects empty" to button "Parent" of card "Hidden" of this stack
The above command will create the allObjects attribute in the Base class and will empty it.
  • Create two classes on card "Hidden" and name one of them "Noise". Name the other class "Garbage" and add the Doing script below
Using the Tools Palette, drag two buttons onto the Hidden card,  Using the Property Inspector, name the one button Noise. Name the other one Garbage. Using Edit Script, put the following script into the class Garbage.
on Doing myNumber
  send "getHowMany" to target                    # Get value of private howMany
  put the result into Many
  put empty into Trash                           # empty the trash
  repeat (Many + myNumber)
     put "Garbage " after Trash                  # put Garbage into trash
  end repeat
  answer Trash                                   # Display trash
end Doing
The Doing method will display the word "Garbage" a number of times. The exact number is the sum of the parameter and the custom property howMany. This method will be inherited by every object of the Garbage class and override the method of the same name inherited from Base Class
Now save the Example program.
Click on View -> Go First. This should take you back to the Dashboard card of the Example main stack. Click on the Browse Tool to put the program into Run mode.
Click on the Create button to create the objects. Click on the Run button to execute the Doing methods. Click on the Delete button to delete the objects.

Summary[]

The Example program above shows the following object oriented features:
  • Classes - There are 3 classes. The Base class class contains one attribute (allObjects) and 6 methods - (Constructor, Doing, setAllObjects, getAllObjects, setHowMany, and getHowMany). The Noise class contains no attributes and no methods. The Garbage class contains no attribute and only one method - (Doing). All classes are created on the card "Hidden", not shown to the user.
  • Class Tree - All 3 of the above classes are in one class tree. The parent cass (Base class) is the first generation. The child classes (Noise and Garbage) are the second generation and inherit from the Base class.
  • Objects - The instantiated object of the Noise class contains the howMany attribute and no methods of its own. Both of the instantiated objects of the Garbage class contain the howMany attribute and no methods of their own. All objects are created on the card "Hidden", not shown to the user.
  • Inheritance - The object of the Noise class inherits all of its methods (Constructor, Doing, setAllObjects, getAllObjects, setHowMany, and getHowMany) from the Noise class, which inherits all of those same methods from the Base class. The Garbage class inherits the following methods from the Base class - (Constructor, setAllObjects, getAllObjects, setHowMany, and getHowMany). The Garbage class does not inherit the Doing method since it has its own. The objects of the Garbage class inherit all their methods from the Garbage class - (Constructor, Doing, setAllObjects, getAllObjects, setHowMany, and getHowMany). Since each class and object inherits from only one class, this is called single inheritance.
  • Encapsulation - There are four attributes in the class tree - the allObjects attribute of the Base class, the howMany attribute of the object in the Noise class and the howMany attributes of the two objects in the Garbage class. The only way to access any of these attributes is by using the setter and getter methods for that attribute. In other words, they are all private attributes.
  • Instantiation - The objects in the Noise and Garbage classes are created or instantiated by the Constructor method in the Base class. Usually there would be a Constructor method in the Noise class and another Constructor method in the Garbage class. But in this program, the objects in the Noise and Garbage classes are nearly the same. So it makes sense to combine them and put into the Base class.
  • Overriding - When a Doing message is sent to one of the objects in the Garbage class, the Doing method in the Garbage class is the one which is executed. As a result, it overrides the method of the same names otherwise inherited from the Base class.
  • Polymorphism - The same Doing message is sent to all the objects. Each object executes its inherited Doing method. But the Doing method inherited from the Noise class is very different from the one inherited from the Garbage class.
  • Interface - There are no public attributes or private methods in this example program. Also all the attributes in this example program are private. Therefore, the interface of the objects are only the following public methods - (Constructor, Doing, setAllObjects, getAllObjects, setHowMany, and getHowMany).
Advertisement