SandCastleIcon.png This article has links to websites or programs outside of Scratch and Wikipedia. Remember to stay safe while using the internet, as we cannot guarantee the safety of other websites.

Wikipedia-logo.svg  For more information, see Object-Oriented Programming on Wikipedia. Object-oriented programming, often shortened to OOP, is a programming paradigm. It revolves around data structures called objects, which consist of states and behaviors, and the interaction between them via message passing; messages and variables are the two main kinds of abstraction used in OOP.[1][2][3] Rather than write a set of procedures to manipulate members of each data type, the behavior becomes part of the data itself. This makes many kinds of program, particularly ones involving simulation or graphical interfaces, easier to write.

Class-Based OOP

The traditional form of object-oriented programming is called class-based OOP. A class represents a type; each object is an instance of a particular class. Each class has a set of instance variables, variables which are local to each instance, and instance methods, which define the behavior of its instances.[2] When a message is sent to an instance, the corresponding method of its class is invoked. Smalltalk, one of the most famous OOP languages, uses class-based OOP.

Prototype-Based OOP

Prototype-based OOP is a form of object-oriented programming that involves the decoration of objects.[3][4] Classes are not necessary; instead, objects extend other objects, called their prototypes, and variables and methods may be added to any object at any time. If an object does not understand a message, it is automatically delegated to its prototype.[5] Snap! is an object-oriented programming language that uses prototypes.

Inheritance

A key feature of OOP is inheritance. In a class-based OOP system, a class may inherit instance variables and methods from another class. The inheriting class is called the subclass and the inherited class is called the superclass.[2] For example, the class "VW Beetle" can inherit from "Car", specifying the car class to VW Beetle.

A more real-world example is that of morphs. A Morphic class always inherits from another Morphic class. So a ButtonMorph inherits from Morph, CancelButtonMorph inherits from ButtonMorph, etc. Similarly, ResizeHandleMorph inherits from DraggableMorph which inherits from Morph. The behavior common to all morphs only needs to be implemented once, in Morph.

Encapsulation

Encapsulation is the hiding of information. In object-oriented programming, an object's attributes may be hidden to prevent illegal state changes. Encapsulation is also used hide implementation details from the user.[6] Accessor methods return the value of an attribute, and mutator methods allow for modification of a hidden attribute. These attributes need not correspond directly to instance variables.

Polymorphism

Message passing allows different objects to respond to the same message in different ways, which is called polymorphism. This is invaluable when implementing operations that could be applied to objects of many related types, and for cases where one abstract data type could be represented by any of several data structures. For example, numbers, strings, distances, and times are all objects that can be compared, so they should all be able to understand a < message; this way, a sort method could sort a list of any of them. (Furthermore the sequence of values itself could be represented as either a dynamic array or a linked list.) In procedural programming this must be done by writing "generic procedures", which use the types of their arguments to decide what to do.

OOP in Scratch

Scratch is not an object-oriented programming language. It includes objects, the stage and sprites, with local state and whose behavior is defined by scripting, but these objects cannot send messages to one another (broadcasting is similar to message passing, but as the name suggests broadcasts are sent to all sprites) and it does not support true inheritance (the behavior of a clone is defined by the original parent.) However, object-oriented programming can still be done in Scratch.

Using text lists for OOP

Lists can be used to support custom objects. A list will act as a class, and each item will represent an instance. To begin, create a list called "Objects". Then add the following code:

when gf clicked
add [key/val/key2/val2] to [Objects v]

Replace key and key2 with your keys and val and val2 with your values. This registers your instance with the Object class.

To reference an object, we must parse (decode) it. To decode an object, use this code:

define decode object (instance)
set [n v] to (0)
delete (all v) of [Obj-decoded v]
repeat until <(n) = (length of (item (instance) of [Objects v]))>
    change [n v] by (1)
    if <(letter (n) of (item (instance) of [Objects v])) = [/]> then
        add [] to [Obj-decoded v]
    else
        replace item (last v) of [Obj-decoded v] with (join (item (last v) of [Obj-decoded v]) (letter (n) of (item (instance) of [Objects v])))
    end
end

Finally, to reference an object, use this code:

set [n v] to [2]
set [key v] to [key] // or whatever
repeat until <(item (n) of [Obj-decoded v]) = [key]>
    change [n v] by (2)
end
set [value v] to (item ((n) + (1)) of [Obj-decoded v])

Class-based OOP With Lists

In this implementation, each instance variable of an object is an item in a list. The naming scheme we will use is Class.attribute.

First, write a constructor for the class.

define new ExampleClass key1: (arg1) key2: (arg2)
add (arg1) to [ExampleClass.key1 v]
add (arg2) to [ExampleClass.key2 v]
...
add [init value] to [ExampleClass.keyn v]
set [new ExampleClass v] to (length of [ExampleClass.key1 v]) // The length of any attribute list of the class will work

This script allocates a new instance of the class and returns a pointer to it, the list index of the items added to the attribute lists.

Methods may be written like this:

define ExampleClass (this).setKey1(val)
replace item (this) of [ExampleClass.key1 v] with (val)

"This" is the pointer to the instance to operate on.

Data fields may be accessed with the list item block:

(item (pointer to object) of [ExampleClass.key1 v])

This expression may be chained:

(item (item (instance) of [Class1.meow v]) of [Class2.woof v])

is equivalent to instance.meow.woof in other languages, where instance is an instance of Class1, which has a data field of the type Class2 called meow, and Class2 has a data field called woof.

OOP in Snap!

BYOB3.png This article or section uses images made with Snap!, a Scratch Modification which allows script formatting. Differences include block multilining and zebra coloring.

Snap! is a prototype-based object-oriented programming language; each sprite is an object, and may, as in Scratch, have local variables; local blocks (created with Make a Block or the "+" button in the block palette) serve as methods, and sprites may send messages to one another using tell [ v] to ({} @addInput :: grey) :: control and (ask [ v] for (( :: control) @addInput :: grey) :: control); new objects are made with (a new clone of [ v] :: control), or by right-clicking on the sprite and selecting "clone". Unlike in Scratch, clones share attributes and blocks with their parent: if a parent changes a shared attribute the clone is affected too. Shared attributes and blocks appear "ghosted". The sharing ends when the block or attribute is changed; it can be restored with inherit [ v] :: variables. See chapter 7 of the Snap! Reference Manual for more information.

Snap! also has first-class procedures, which can be made using the ring block ({} @addInput :: grey). First-class procedures make message passing simple even in programming languages that do not include it. To create a class in Snap!, one would make a procedure which reports another procedure. This reported procedure is the object. It takes in a message as an argument, and based on the message provided, performs the method and returns the appropriate value. The following script creates a Counter class, with methods to increment, decrement, or just retrieve the value of the counter.

(make a counter :: grey) :: control hat
script variables ((value):: grey) @delInput @addInput :: grey // Value is the counter's value
set [value v] to [0]
report ({
    if <(message) = [increment]> then
        change [value v] by [1]
        report (value) :: control cap
    end
    if <(message) = [decrement]> then
        change [value v] by [-1]
        report (value) :: control cap
    end
    if <(message) = [retrieve]> then
        report (value) :: control cap
    end
} input names: ((message):: grey) @delInput @addInput :: ring grey) :: control cap // This script represents the counter itself. It is called with a message to be sent.

set [My Counter v] to (make a counter :: grey) // Creates the counter.
forever
    say (call (My Counter) with inputs [increment] @delInput @addInput :: control) for (2) secs // Increment the counter and say its value.
end

This implementation of OOP is possible because of lexical scoping. A procedure may "capture" variables that are bound outside the lambda expression, and they will continue to exist, and can be referenced and assigned to. See chapter 8 of the Snap! Reference Manual for more details, and an example of inheritance.

See Also

References

Cookies help us deliver our services. By using our services, you agree to our use of cookies.