Learning Object-Oriented Programming - Sample Chapter
Learning Object-Oriented Programming - Sample Chapter
ee
Learning
Object-Oriented
Programming
is
an
easy-to-follow guide full of hands-on examples of
solutions to common problems with object-oriented
code in Python, JavaScript, and C#. It starts by helping
you to recognize objects from real-life scenarios and
demonstrates that working with them makes it simpler
to write code that is easy to understand and reuse. You
will learn to protect and hide data with the data
encapsulation features of Python, JavaScript, and C#.
You will explore how to maximize code reuse by writing
code capable of working with objects of different types,
and discover the advantage of duck typing in both Python
and JavaScript, while you work with interfaces and
generics in C#. With a fair understanding of interfaces,
multiple inheritance, and composition, you will move on
to refactor existing code and to organize your source
for easy maintenance and extension.
Learning Object-Oriented
Programming
"Community
Experience
Distilled"
Gastn C. Hillar
pl
C o m m u n i t y
E x p e r i e n c e
D i s t i l l e d
Learning Object-Oriented
Programming
Explore and crack the OOP code in Python, JavaScript, and C#
Sa
m
Gastn C. Hillar
was 8 years old. In the early 80s, he began programming with the legendary Texas
TI-99/4A and Commodore 64 home computers. Gaston has a bachelor's degree
in computer science and graduated with honors. He also holds an MBA, in which
he graduated with an outstanding thesis. At present, Gaston is an independent IT
consultant and a freelance author who is always looking for new adventures around
the world.
He has been a senior contributing editor at Dr. Dobb's and has written more
than a hundred articles on software development topics. Gatson was also a former
Microsoft MVP in technical computing. He has received the prestigious Intel Black
Belt Software Developer award seven times.
He is a guest blogger at Intel Software Network (http://software.intel.com).
You can reach him at [email protected] and follow him on Twitter at
http://twitter.com/gastonhillar. Gastn's blog is http://csharpmulticore.
blogspot.com.
He lives with his wife, Vanesa, and his two sons, Kevin and Brandon.
Preface
Object-oriented programming, also known as OOP, is a required skill in absolutely
any modern software developer job. It makes a lot of sense because object-oriented
programming allows you to maximize code reuse and minimize the maintenance
costs. However, learning object-oriented programming is challenging because it
includes too many abstract concepts that require real-life examples to make it easy
to understand. In addition, object-oriented code that doesn't follow best practices
can easily become a maintenance nightmare.
Nowadays, you need to work with more than one programming language at the
same time to develop applications. For example, a modern Internet of Things
project may require the Python code running on a board and a combination of
C#, JavaScript, and HTML code to develop both the web and mobile apps that
allow users to control the Internet of Things device. Thus, learning object-oriented
programming for a single programming language is usually not enough.
This book allows you to develop high-quality reusable object-oriented code in
Python, JavaScript, and C#. You will learn the object-oriented programming
principles and how they are or will be used in each of the three covered
programming languages. You will also learn how to capture objects from real-world
elements and create object-oriented code that represents them. This book will help
you understand the different approaches of Python, JavaScript, and C# toward
object-oriented code. You will maximize code reuse in the three programming
languages and reduce maintenance costs. Your code will become easy to understand
and it will work with representations of real-life elements.
Preface
Learn an object's lifecycle and how object constructors and destructors work
Customize the process that takes place when you create instances in Python,
C#, and JavaScript
Customize the process that takes place when you destroy instances in
Python, C#, and JavaScript
[ 13 ]
Let's move to the world of our best friends, the dogs. If we want to model an
object-oriented application that has to work with dogs and about a dozen dog
breeds, we will definitely have a Dog abstract class. Each dog breed required in
our application will be a subclass of the Dog superclass. For example, let's assume
that we have the following subclasses of Dog:
TibetanSpaniel: This is a blueprint for the dogs that belong to the Tibetan
Spaniel breed
So, each dog breed will become a subclass of Dog and a type in the programming
language. Each dog breed is a blueprint that we will be able to use to create
instances. Brian and Merlin are two dogs. Brian belongs to the Tibetan Spaniel
breed, and Merlin belongs to the Smooth Fox Terrier breed. In our application,
Brian will be an instance of the TibetanSpaniel subclass, and Merlin will be an
instance of the SmoothFoxTerrier subclass.
As both Brian and Merlin are dogs, they will share many attributes. Some of
these attributes will be initialized by the class, because the dog breed they belong
to determines some features, for example, the area of origin, the average size, and
the watchdog ability. However, other attributes will be specific to the instance, such
as the name, weight, age, and hair color.
[ 14 ]
Chapter 2
So, for example, before you can call the CalculateArea method, you want the Width
and Height attributes for each new Rectangle instance to have a value initialized
to 0. Constructors are extremely useful when we want to define the attributes of the
instances of a class right after their creation.
Sometimes, we need specific arguments to be available when we are creating an
instance. We can design different constructors with the necessary arguments and use
them to create instances of a class. This way, we can make sure that there is no way
of creating specific classes without using the authorized constructors that ask for the
necessary arguments.
At some point, your application won't need to work with an instance anymore. For
example, once you calculate the perimeter of an ellipse and display the results to the
user, you don't need the specific Ellipse instance anymore. Some programming
languages require you to be careful about leaving live instances alive. You have to
explicitly destroy them and de-allocate the memory that it was consuming.
The runtimes of Python, C#, and JavaScript use a garbage-collection mechanism that
automatically de-allocates memory used by instances that aren't referenced anymore.
The garbage-collection process is a bit more complicated, and each programming
language and runtime has specific considerations that should be taken into account
to avoid unnecessary memory pressure. However, let's keep our focus on the object's
life cycle. In these programming languages, when the runtime detects that you aren't
referencing an instance anymore and when a garbage collection occurs, the runtime
executes the code specified within the instance's destructor.
You can use the destructor to perform any necessary cleanup before
the object is destroyed and removed from memory. However, take
into account that JavaScript doesn't provide you with the possibility
to customize a destructor.
For example, think about the following situation. You need to count the number of
instances of a specific class that are being kept alive. You can have a variable shared
by all the classes. Then, you customize the class constructor to atomically increase
the value for the counter, that is, increase the value of the variable shared by all the
classes of the same time. Finally, you customize the class destructor to automatically
decrease the value for the counter. This way, you can check the value of this variable
to know the objects that are being referenced in your application.
[ 15 ]
For example, when we enter the following lines in a Python console, we create a new
instance of the int class. The console will display <class 'int'> as a result of the
second line. This way, we know that area is an instance of the int class:
area = 250
type(area)
When we type the following lines in a Python console, we create a new instance of
the function class. The console will display <class 'function'> as a result of the
second line. Thus, calculateArea is an instance of the function class:
def calculateArea(width, height):
return width * height
type(CalculateArea)
Let's analyze the simple calculateArea function. This function receives two
arguments: width and height. It returns the width value multiplied by the height
value. If we call the function with two int values, that is, two int instances, the
function will return a new instance of int with the result of width multiplied by
height. The following lines call the calculateArea function and save the returned
int instance in the rectangleArea variable. The console will display <class 'int'>
as a result of the third line. Thus, rectangleArea is an instance of the int class:
rectangleArea = calculateArea(300, 200)
print(rectangleArea)
type(rectangleArea)
[ 16 ]
Chapter 2
The class keyword followed by the class name (Rectangle) and a colon (:)
composes the header of the class definition. In this case, the class doesn't have
a parent class or a superclass. Therefore, there aren't superclasses enclosed in
parentheses after the class name and before the colon (:). The indented block of
statements that follows the class definition composes the body of the class. In
this case, there is just a single statement, pass, and the class doesn't define either
attributes or methods. The Rectangle class is the simplest possible class we can
declare in Python.
Any new class you create that doesn't specify a superclass will be
a subclass of the builtins.object class. Thus, the Rectangle
class is a subclass of builtins.object.
The following line prints True as a result in a Python console, because the Rectangle
class is a subclass of object:
issubclass(Rectangle, object)
The following lines represent an equivalent way of creating the Rectangle class
in Python. However, we don't need to specify that the class inherits from an object
because it adds unnecessary boilerplate code:
class Rectangle(object):
pass
[ 17 ]
The following lines create a Rectangle class and declare an __init__ method
within the body of the class:
class Rectangle:
def __init__(self, width, height):
print("I'm initializing a new Rectangle instance.")
self.width = width
self.height = height
This method receives three arguments: self, width, and height. The first argument
is a reference to the instance that called the method. We used the name self for
this argument. It is important to notice that self is not a Python keyword. It is just
the name for the first argument, and it is usually called self. The code within the
method prints a message indicating that the code is initializing a new Rectangle
instance. This way, we will understand when the code within the __init__ method
is executed.
Then, the following two lines create the width and height attributes for the instance
and assign them the values received as arguments with the same names. We use
self.width and self.height to create the attributes for the instance. We create
two attributes for the Rectangle instance right after its creation.
The following lines create two instances of the Rectangle class named rectangle1
and rectangle2. The Python console will display I'm initializing a new
Rectangle instance. after we enter each line in the Python console:
rectangle1 = Rectangle(293, 117)
rectangle2 = Rectangle(293, 137)
[ 18 ]
Chapter 2
The preceding screenshot shows the Python console. Each line that creates an instance
specifies the class name followed by the desired values for both the width and the
height as arguments enclosed in parentheses. If we take a look at the declaration of
the __init__ method within the Rectangle class, we will notice that we just need to
specify the second and third arguments (width and height). Also, we just need to skip
the required first parameter (self). Python resolves many things under the hood. We
just need to make sure that we specify the values for the required arguments after self
to successfully create and initialize an instance of Rectangle.
After we execute the previous lines, we can check the values for rectangle1.width,
rectangle1.height, rectangle2.width, and rectangle2.height.
The following line will generate a TypeError error and won't create an instance
of Rectangle because we missed the two required arguments: width and height.
The specific error message is TypeError: __init__() missing 2 required
positional arguments: 'width' and 'height'. The error message is shown
in the following screenshot:
rectangleError = Rectangle()
[ 19 ]
Before Python removes an instance from memory, it calls the __del__ method.
Thus, we can use this method to add any code we want to run before the instance is
destroyed. We can think of the __del__ method as the equivalent of a destructor in
other object-oriented programming languages.
The following lines declare a __del__ method within the body of the Rectangle
class. Remember that Python always receives self as the first argument for any
instance method:
def __del__(self):
print('A Rectangle instance is being destroyed.')
=
=
=
=
Rectangle(293, 117)
Rectangle(293, 137)
None
None
[ 20 ]
Chapter 2
You can add some cleanup code within the __del__ method. However,
take into account that most of the time, you can follow best practices to
release resources without having to add code to the __del__ method.
Remember that you don't know exactly when the __del__ method
is going to be executed. Even when the reference count reaches 0, the
Python implementation might keep the resources until the appropriate
garbage collection destroys the instances.
The following lines create a rectangle3 instance of the Rectangle class and then
assign a referenceToRectangle3 reference to this object. Thus, the reference
count to the object increases to 2. The next line assigns None to rectangle3,
and therefore, the reference count for the object goes down from 2 to 1. As the
referenceToRectangle3 variable stills holds a reference to the Rectangle instance,
Python doesn't destroy the instance, and we don't see the results of the execution of
the __del__ method:
rectangle3 = Rectangle(364, 257)
referenceToRectangle3 = rectangle3
rectangle3 = None
However, it is very important to know that you don't need to assign None to a
reference to force Python to destroy objects. In the previous examples, we wanted to
understand how the __del__ method worked. Python will automatically destroy the
objects when they aren't referenced anymore.
[ 21 ]
Now, imagine that we want to have a function that receives the width and height
values of a rectangle and returns the calculated area. We can take advantage of the
Rectangle class to code this new function. We just need to create an instance of the
Rectangle class with the width and height received as parameters and return the
result of the call to the calculate_area method. Remember that we don't have to
worry about releasing the resources required by the Rectangle instance, because the
reference count for this object will become 0 after the function returns the result. The
following lines show the code for the calculateArea independent function, which
isn't part of the Rectangle class body:
def calculateArea(width, height):
return Rectangle(width, height).calculate_area()
print(calculateArea(143, 187))
Notice that the Python console displays the following messages. Thus, we can see
that the instance is destroyed and the code within the __del__ method is executed.
The messages are shown in the following screenshot:
I'm initializing a new Rectangle instance.
A Rectangle instance is being destroyed.
26741
[ 22 ]
Chapter 2
Declaring classes in C#
Throughout this book, we will work with C# 6.0 (introduced in Microsoft Visual
Studio 2015). However, most of the explanations and code samples are also
compatible with C# 5.0 (introduced in Visual Studio 2013). If a specific example uses
C# 6.0 syntax and isn't compatible with C# 5.0, the code will be properly labeled
with the compatibility warning. We will use Visual Studio Community 2015 as the
main IDE. However, you can also run the examples using Mono or Xamarin.
The following lines declare a new minimal Circle class in C#:
class Circle
{
}
The class keyword followed by the class name (Circle) composes the header of
the class definition. In this case, the class doesn't have a parent class or a superclass.
Therefore, there aren't any superclasses listed after the class name and a colon (:).
A pair of curly braces ({}) encloses the class body after the class header. In this case,
the class body is empty. The Circle class is the simplest possible class we can declare
in C#.
Any new class you create that doesn't specify a superclass will be a
subclass of the System.Object class in C#. Thus, the Circle class
is a subclass of System.Object.
The following lines represent an equivalent way of creating the Circle class in C#.
However, we don't need to specify that the class inherits from System.Object,
because it adds unnecessary boilerplate code:
class Circle: System.Object
{
}
Customizing constructors in C#
We want to initialize instances of the Circle class with the radius value. In order
to do so, we can take advantage of the constructors in C#. Constructors are special
class methods that are automatically executed when we create an instance of a given
type. The runtime executes the code within the constructor before any other code
within a class.
[ 23 ]
We can define a constructor that receives the radius value as an argument and use
it to initialize an attribute with the same name. We can define as many constructors
as we want. Therefore, we can provide many different ways of initializing a class. In
this case, we just need one constructor.
The following lines create a Circle class and define a constructor within the
class body.
class Circle
{
private double radius;
public Circle(double radius)
{
Console.WriteLine(String.Format("I'm initializing a new Circle
instance with a radius value of {0}.", radius));
this.radius = radius;
}
}
The constructor is a public class method that uses the same name as the class:
Circle. The method receives a single argument: radius. The code within the
method prints a message on the console, indicating that the code is initializing
a new Circle instance with a specific radius value. This way, we will understand
when the code within the constructor is executed. As the constructor has an
argument, it is known as a parameterized constructor.
Then, the following line assigns the radius double value received as an argument
to the private radius double field. We use this.radius to access the private radius
attribute for the instance and radius to reference the argument. In C#, the this
keyword provides access to the instance that has been created and the one we want
to initialize. The line before the constructor declares the private radius double field.
At this time, we won't pay attention to the difference between the private and
public keywords. We will dive deep into the proper usage of these keywords in
Chapter 3, Encapsulation of Data.
The following lines create two instances of the Circle class: circle1 and circle2.
The Windows Console application will display I'm initializing a new Circle
instance with a radius value of, followed by the radius value specified in the
call to the constructor of each instance:
class Chapter01
{
public static void Main(string[] args)
{
[ 24 ]
Chapter 2
var circle1 = new Circle(25);
var circle2 = new Circle(50);
Console.ReadLine();
}
}
Each line that creates an instance uses the new keyword, followed by the desired
value for the radius as an argument enclosed in parentheses. We used the var
keyword to let C# automatically assign the Circle type for each of the variables.
After we execute the two lines that create the instances of Circle, we can use
an inspector, such as the Autos Window, the Watch Window, or the Immediate
Window, to check the values for circle1.radius and circle2.radius.
The following line prints "System.Object" as a result in the Immediate Window in
the IDE. This is because the Circle class is a subclass of System.Object:
circle1.GetType().BaseType.ToString()
[ 25 ]
The following line won't allow the console application to compile and will display
a build error. This is because the compiler cannot find a parameterless constructor
declared in the Circle class. The specific error message is ConsoleApplication
does not contain a constructor that takes 0 arguments. The following
screenshot displays the var circleError = new Circle(); error:
Customizing destructors in C#
We want to know when the instances of the Circle class are removed from memory,
that is, when the objects go out of scope and the garbage-collection mechanism
removes them from memory. Destructors are the special class methods that are
automatically executed when the run time destroys an instance of a given type. Thus,
we can use them to add any code we want to run before the instance is destroyed.
The destructor is a special class method that uses the same name as the class, but
prefixed with a tilde (~): ~Circle. The destructor must be parameterless, and it
cannot return a value.
[ 26 ]
Chapter 2
The following lines declare a destructor (a ~Circle method) within the body of the
Circle class:
~Circle()
{
Console.WriteLine(String.Format("I'm destroying the Circle instance
with a radius value of {0}.", radius));
}
The code within the destructor prints a message on the console indicating that the
runtime is destroying a Circle instance with a specific radius value. This way, we
will understand when the code within the destructor is executed.
If we execute the console application after adding the code for the destructor to the
Circle class, we will see the following lines in the console output. The first two lines
will appear before we press a key. After we press a key, we will see the two lines
indicating that the code within the destructor has been executed. This is because the
two variables circle1 and circle2 have run out of scope and the garbage collector
has destroyed the objects:
I'm initializing a new Circle instance with a radius value of 25.
I'm initializing a new Circle instance with a radius value of 50.
I'm destroying the Circle instance with a radius value of 50.
I'm destroying the Circle instance with a radius value of 25.
[ 27 ]
The method doesn't require arguments to be called. It returns the result of the
multiplication of by the square of the radius field value (this.radius). The
following lines show a new version of the Main method. These lines create two
instances of the Circle class: circle1 and circle2. The lines then display the
results of calling the CalculateArea method for the two objects. The new lines
are highlighted, as follows:
class Chapter01
{
public static void Main(string[] args)
{
var circle1 = new Circle(25f);
var circle2 = new Circle(50f);
Console.WriteLine(String.Format("The area for circle #1 is {0}",
circle1.CalculateArea()));
Console.WriteLine(String.Format("The area for circle #2 is {0}",
circle2.CalculateArea()));
Console.ReadLine();
}
}
Now, imagine that we want to have a function that receives the radius value
of a circle and has to return the calculated area. We can take advantage of the
Circle class to code this new function. We just need to create an instance of the
Circle class with the radius received as a parameter and return the result of the
call to the CalculateArea method. Remember that, we don't have to worry about
releasing the resources required by the Circle instance, because the object will go
out of scope after the function returns the result. The following lines show the code
for the new CalculateCircleArea function that isn't part of the Circle class body.
The function is a method of the Chapter 1, Objects Everywhere class body, which also
has the Main method:
class Chapter01
{
private static double CalculateCircleArea(double radius)
{
return new Circle(radius).CalculateArea();
}
static void Main(string[] args)
{
double radius = 50;
Console.WriteLine(String.Format("The area for a circle with a
radius of {0} is {1} ", radius, CalculateCircleArea(radius)));
Console.ReadLine();
}
}
[ 28 ]
Chapter 2
The Windows command line displays the following messages. Thus, we can see that
the instance is destroyed and the code within the destructor is executed:
I'm initializing a new Circle instance with a radius value of 50.
The area for a circle with a radius of 50 is 7853.98163397448
I'm destroying the Circle instance with a radius value of 50.
The calculateArea function receives two arguments: width and height. It returns the
width value multiplied by the height value. The following line calls the calculateArea
function and saves the returned number in the rectangleArea variable:
var rectangleArea = calculateArea(300, 200);
console.log(rectangleArea);
Functions are special objects in JavaScript that contain code and that you can invoke.
They contain properties and methods. For example, if we type the following line, the
JavaScript console will display the value for the name property of the function object,
that is, the calculateArea function:
console.log(calculateArea.name);
The preceding lines created an empty object. Therefore, the result of the last line
shows Object {} on the console. There are no properties or methods defined in the
object. However, if we enter myObject. (myObject followed by a dot) in a JavaScript
console with autocomplete features, we will see many properties and methods listed,
as shown in the following screenshot. The object includes many built-in properties
and methods:
[ 30 ]
Chapter 2
The following lines of code create an object named myRectangle with two key-value
pairs enclosed within a pair of curly braces ({}). A colon (:) separates the key from
the value and a comma (,) separates the key-value pairs. The next line checks the
type of the variable (object) and prints the key-value pairs that define the object
on the JavaScript console:
var myRectangle = { width: 300, height: 200 };
typeof(myRectangle);
myRectangle
The preceding lines created an object with two properties: width and height.
The result of the last line shows Object {width: 300, height: 200} on the
console. Thus, the width property has an initial value of 300, and the height
property has an initial value of 200. If we enter myRectangle. (myRectangle
followed by a dot) in a JavaScript console with autocomplete features, we will
see the width and height properties listed with the built-in properties and
methods, as shown in the following screenshot:
So far, we have been creating independent objects. The first example was an empty
object, and the second case was an object with two properties with their initial values
initialized. However, if we want to create another object with the same properties but
different values, we would have to specify the property names again. For example,
the following line creates another object named myRectangle2, with the same two
keys, but different values:
var myRectangle2 = { width: 500, height: 150 };
[ 31 ]
However, we are repeating code and can have typos when we enter the key names,
that is, the names for the future properties of the instance. Imagine that we had
written the following line instead of the preceding line (notice that the code
contains typos):
var myRectangle2 = { widh: 500, hight: 150 };
The previous line will generate widh and hight properties instead of width and
height. Thus, if we want to retrieve the value from myRectangle2.width, we would
receive undefined as a response. This is because myRectangle2 created the widh
property instead of width.
We want to initialize new rectangle objects with the values of both the width and the
height. However, we don't want a typo to generate problems in our code. Thus, we
need a blueprint that generates and initializes properties with the same names. In
addition, we want to log a message to the console whenever we have a new rectangle
object. In order to do so, we can take advantage of the constructor function. The
following lines declare a Rectangle constructor function in JavaScript:
function Rectangle(width, height) {
console.log("I'm creating a new Rectangle");
this.width = width;
this.height = height;
}
The constructor function receives two arguments: width and height. The code within
the function is able to access the new instance of the current object that has been
created with the this keyword. Thus, you can translate this to the current object.
The code within the function prints a message on the JavaScript console, indicating
that it is creating a new rectangle. The code then uses the received width and height
arguments to initialize properties with the same names. We use this.width and
this.height to create the properties for the instance. We create two properties for
the instance right after its creation. We can think of the constructor function as the
equivalent of a constructor in other object-oriented programming languages.
[ 32 ]
Chapter 2
The following lines create two Rectangle objects named rectangle1 and
rectangle2. Notice the usage of the new keyword to call the constructor function,
with the width and height values enclosed in parentheses. The Python console will
display I'm initializing a new Rectangle instance. after we enter each line
in the Python console:
var rectangle1 = new Rectangle(293, 117);
var rectangle2 = new Rectangle(293, 137);
Each line that creates an instance uses the new keyword followed by the constructor
function and the desired values for both the width and the height as arguments
enclosed in parentheses. After we execute the previous lines, we can check the
values for rectangle1.width, rectangle1.height, rectangle2.width, and
rectangle2.height.
Enter the following two lines in the console:
rectangle1;
rectangle2;
It is very clear that we have created two Rectangle objects and not just two Object
objects. We can see that the constructor function name appears before the key-value
pairs.
[ 33 ]
The console will display true as a result of the evaluation of the previous expression,
because rectangle1 is an instance of Rectangle. This way, we can determine
whether an object is a Rectangle object, that is, an instance created using the
Rectangle constructor function.
If we enter the following line, the JavaScript console will display the same code
we entered to create the new version of the Rectangle constructor function. Thus,
we might create a new Rectangle object by calling the rectangle3.constructor
function in the next line. Remember that the constructor property is automatically
generated by JavaScript, and this property in is a function:
var rectangle4 = new rectangle3.constructor(300, 200);
[ 34 ]
Chapter 2
Now, imagine that we want to have a function that receives the width and height
values of a rectangle and returns the calculated area. We can take advantage of a
Rectangle object to code this new function. We just need to create a Rectangle
object using the Rectangle constructor function with width and height received
as parameters. We then need to return the result of the call to the calculateArea
method. Remember that we don't have to worry about releasing the resources
required by the Rectangle object, because the variable will go out of scope after the
function returns the result. The following lines show the code for the calculateArea
independent function, which isn't a part of the Rectangle constructor function:
function calculateArea(width, height) {
return new Rectangle(width, height).calculateArea();
}
calculateArea(143, 187);
Summary
In this chapter, you learned about an object's life cycle. You also learned how object
constructors and destructors work. We declared classes in Python and C# and used
constructor functions in JavaScript to generate blueprints for objects. We customized
constructors and destructors, and tested their personalized behavior in action. We
understood different ways of generating instances in the three programming languages.
Now that you have learned to start creating classes and instances, we are ready
to share, protect, and hide data with the data-encapsulation features of Python,
JavaScript, and C#, which is the topic of the next chapter.
[ 35 ]
www.PacktPub.com
Stay Connected: