Skip to content

Commit

Permalink
encapsulation chapter: perl => DONE
Browse files Browse the repository at this point in the history
  • Loading branch information
kariminf committed Aug 15, 2018
1 parent 4d1ae31 commit ee83d3e
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 63 deletions.
2 changes: 2 additions & 0 deletions REF.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
* https://perldoc.perl.org/perlootut.html
* http://ods.com.ua/win/eng/program/Perl5Unleashed/ch5.phtml
* https://www.perl.com/pub/2002/11/14/exception.html/
* https://www.perlmonks.org/?node_id=571509
* https://www.perlmonks.org/?node_id=8251

## Php

Expand Down
3 changes: 2 additions & 1 deletion book/cite.bib
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ @article{1993-kay
acmid = {155364},
publisher = {ACM},
address = {New York, NY, USA},
}
}
113 changes: 99 additions & 14 deletions book/encapsulation.tex
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@
\chapter{Encapsulation}

\begin{introduction}
Encapsulation is one important concept of OOP.
Encapsulation is an important concept of OOP.
It is the mechanism of restricting direct access to some members of a class.
It helps managing complexity when debugging source code.
If a field is accessed everywhere in your source code, this makes it difficult to find errors related to this field.
Also, if a field of a class (A) is used by a class (B) then we changed it (either its name or how it gets assigned), we have to change all the code where it appears in (B).
In this chapter, we will show different visibility modes and how they are implemented in each language.
You will see that there are two views: "Many programmers are irresponsible, dim-witted, or both." and "Programmers are responsible adults and capable of good judgment".
You will see that there are two views: ``Many programmers are irresponsible, dim-witted, or both." and ``Programmers are responsible adults and capable of good judgment".
So, a programming language may fall into one or another.
\end{introduction}
Some languages have just public fields, and it is up to programmers to decide if they want to access it directly.

\section{Public members}

Expand Down Expand Up @@ -55,7 +56,7 @@ \subsection{Java}

Every public member in Java must preceded by the keyword \keyword{public}.

\lstinputlisting[language=Java, linerange={1-5,12-12,18-20,27-29}, style=codeStyle]{../codes/java/src/encapsulation/core/Person.java}
\lstinputlisting[language=Java, linerange={1-5,12-12,18-20,27-27,34-34}, style=codeStyle]{../codes/java/src/encapsulation/core/Person.java}

These members can be accessed anywhere
\lstinputlisting[language=Java, linerange={1-8,10-10,14-14,16-18}, style=codeStyle]{../codes/java/src/encapsulation/main/App.java}
Expand Down Expand Up @@ -96,7 +97,20 @@ \subsection{Lua}

\subsection{Perl}

%\lstinputlisting[language=Perl, linerange={4-4}, style=codeStyle]{../codes/perl/person.pl}
\begin{kodequote}{Larry Wall}
Perl doesn't have an infatuation with enforced privacy.
It would prefer that you stayed out of its living room because you weren't invited, not because it has a shotgun.
\end{kodequote}

I guess you get the idea: all members are public.
But, in Perl, there is always a hack to limit visibility.
Let's see the normal case where every field and method are public.

\lstinputlisting[language=Perl, linerange={1-18}, style=codeStyle]{../codes/perl/encapsulation/public.pl}

They can be accessed outside the class

\lstinputlisting[language=Perl, linerange={20-22}, style=codeStyle]{../codes/perl/encapsulation/public.pl}

\subsection{PHP}

Expand Down Expand Up @@ -124,7 +138,7 @@ \subsection{Ruby}
By default methods are public except for \keyword{initialize} method and the global methods defined under the object class which are private always.
If desired, you can use the keyword \keyword{public} in a line and all methods defined after it are public.
Fields are not public unless they are constants.
To access them like public in other languages, you have to define an accessor methods (the fields have to be properties).
To access them like public in other languages, you have to define accessor methods (the fields have to be properties).
In Ruby, public getters and setters are called \nameword{attribute readers} and \nameword{attribute writers}.

\lstinputlisting[language=Ruby, linerange={1-1,5-5,9-9,13-13,15-15,17-17,22-22,34-35,39-39,46-46}, style=codeStyle]{../codes/ruby/encapsulation/person.rb}
Expand All @@ -137,6 +151,10 @@ \subsection{Ruby}

\section{Protected members}

Protected visibility mode is used to access a member of a class from the class itself and its subclasses.
For fields as for methods, it is used to allow subclasses accessing them directly.
If you define a member as protected, keep in mind that changing it later may break subclasses.

\subsection{C++}

Protected members are defined inside the class header using the modifier \keyword{protected}.
Expand All @@ -156,7 +174,7 @@ \subsection{Java}

Protected members are prefixed each by the keyword \keyword{protected}.
A protected member is visible inside the class and its subclass, and also to other classes in the same package.
There is no difference between visibility modes of fields and those of methods; they are the same.
The protected methods can be defined the same.

\lstinputlisting[language=Java, linerange={1-3,7-7,34-34}, style=codeStyle]{../codes/java/src/encapsulation/core/Person.java}

Expand All @@ -180,7 +198,7 @@ \subsection{Javascript}

There is no protected members in Javascript.
You can find some hacks on the web, but they can be expensive in term of memory and processing power.
To emulate such mechanism, you have to know the caller object
To emulate such mechanism, you have to know the caller object.
If you insist on having protected and private members, some libraries can be helpful such as \nameword{mozart}\footnote{mozart: \url{https://github.com/philipwalton/mozart}}.

% https://philipwalton.com/articles/implementing-private-and-protected-members-in-javascript/
Expand All @@ -192,7 +210,25 @@ \subsection{Lua}

\subsection{Perl}

%\lstinputlisting[language=Perl, linerange={4-4}, style=codeStyle]{../codes/perl/person.pl}
Perl can capture the caller (the location or package where a function was called) using the keyword \keyword{caller}.
Also, the base class \keyword{UNIVERSAL} provides a method \keyword{isa} which returns true if the object is blessed to the given type or inherits from it.
Adding to it the keyword \keyword{\_\_PACKAGE\_\_} which captures the current package and exception management \keyword{die}, Bingo! we can limit access.
We cannot limit visibility: the method is still visible, but we raise an exception if the access does not serve our purpose.

\begin{lstlisting}[language=Perl, style=codeStyle]
package Person;
# ...
sub protected_fct {
die "protected_fct is protected!" unless caller->isa(__PACKAGE__);
# ... The rest of the code
}
1;
\end{lstlisting}

As for fields, you can hide them entirely (private) then use getters and setters to access them.
Since these getters/setters are methods, you can limit their access.

%\lstinputlisting[language=Perl, linerange={4-4}, style=codeStyle]{../codes/perl/encapsulation/person.pl}

\subsection{PHP}

Expand Down Expand Up @@ -255,6 +291,10 @@ \subsection{Ruby}

\section{Private members}

Fields are set to be private so they can not be changed directly, instead setters and getters are more appropriate for that.
Private methods are a good way to break tasks into smaller pieces of code.
Also, they can prevent duplication in case many other public functions needs to do the same thing in some point.

\subsection{C++}

Private members are defined inside the class header using the modifier \keyword{private}.
Expand All @@ -275,13 +315,13 @@ \subsection{Java}
Private members are prefixed each by the keyword \keyword{private}.
A private member (field or method) is visible only inside the class.

\lstinputlisting[language=Java, linerange={1-3,7-7,34-34}, style=codeStyle]{../codes/java/src/encapsulation/core/Person.java}
\lstinputlisting[language=Java, linerange={1-3,9-9,34-34}, style=codeStyle]{../codes/java/src/encapsulation/core/Person.java}

It cannot be accessed from a subclass

\lstinputlisting[language=Java, linerange={3-3,5-6,10-13}, style=codeStyle]{../codes/java/src/encapsulation/core/Student.java}

And sure cannot be accessed from another class
Also, it cannot be accessed from another class

\lstinputlisting[language=Java, linerange={5-8,12-12,16-18}, style=codeStyle]{../codes/java/src/encapsulation/main/App.java}

Expand All @@ -293,9 +333,9 @@ \subsection{Javascript}

There is a convention to use underscore \keyword{\_} as a mean to signal a class member as private.
But the member still accessible as public.
Another way is to use closures (the combination of a function and the lexical environment within which that function was declared), by defining a field inside the constructor using the keyword \keyword{var} or \keyword{let}.
Another way is to use closures (\textit{the combination of a function and the lexical environment within which that function was declared}), by defining a field inside the constructor using the keyword \keyword{var} or \keyword{let}.
But, any method using this variable must be defined inside the constructor.
This means each time you create a new instance (object), a new function will be created for this object.
This means each time you create a new instance (object), a new method will be created for this object.

\lstinputlisting[linerange={1-3,5-14}, style=codeStyle]{../codes/javascript/encapsulation/person.js}

Expand All @@ -312,13 +352,58 @@ \subsection{Lua}
\lstinputlisting[language={[5.2]Lua}, linerange={1-6,8-12,19-19}, style=codeStyle]{../codes/lua/encapsulation/person.lua}

You cannot access it outside the class.
But, you can create a new public field dynamically, but it will not replace the internal one.
But, you can create a new public field dynamically which will not replace the internal one.

\lstinputlisting[language={[5.2]Lua}, linerange={1-3,7-8}, style=codeStyle]{../codes/lua/encapsulation/app.lua}

\subsection{Perl}

%\lstinputlisting[language=Perl, linerange={4-4}, style=codeStyle]{../codes/perl/person.pl}
There is a convention to start private members with underscore \keyword{\_}, but they still are accessible.
For methods, you can use \keyword{caller}, \keyword{eq}, \keyword{\_\_PACKAGE\_\_} and \keyword{die} to limit access though they still are visible.
If the method is not called from inside the package (which is the class in our case), it will raise an exception and stop executing.

\begin{lstlisting}[language=Perl, style=codeStyle]
package Person;
# ...
sub private_fct {
die "private_fct is private!" unless caller eq __PACKAGE__;
# ... The rest of the code
}
1;
\end{lstlisting}

As for fields, you can hide them entirely (private) using many ways.

\subsubsection{Using scope and object reference}

This is a method I thought of in order to hide internal fields of an object.
Using a container hash, each object's reference is considered as a key and the value is another hash containing private fields names and their values.
The hash must be defined using \keyword{my} and not \keyword{our} so it will not be accessible outside the package.
You can put your package inside a code block so the container hash will not be accessible to the rest of code in the same file.
You can consider this hash as a private static member.
To get an object's reference in memory, you can use \keyword{refaddr} function.

\lstinputlisting[language=Perl, linerange={2-4,6-6,8-16,22-23,56-57}, style=codeStyle]{../codes/perl/encapsulation/private.pl}

Then, you can access any field of an object using the instruction \textbf{\$private\{refaddr \$obj\}->\{name\}}.
You can, also, create a private getter/setter if you do not want to repeat that instruction every time you want to access a private field.

\lstinputlisting[language=Perl, linerange={2-5,25-32,43-47,56-57}, style=codeStyle]{../codes/perl/encapsulation/private.pl}

If you want a protected access, just modify the setter/getter to do so.
In addition, if you want to prevent modifying the content of a protected field from a subclass, just delete the setter code block.

\subsubsection{Using closures}

This solution is what you will find on the web. %ref to https://www.perlmonks.org/?node_id=8251
Instead of using hashes as objects, you may implement them as closures.
A closure is a subroutine reference that has access to the lexical variables that were in scope when it was created.
The idea is to define a subroutine that will act as an setter/getter method and bless it into the class instead of the hash.
The solution presented here is a simplified one, with some restrictions on closure.
Here I forbid access outside the class to make all fields private, then you can create second hand setters/getters for those you want to grant access to.

\lstinputlisting[language=Perl, linerange={1-28,49-49}, style=codeStyle]{../codes/perl/encapsulation/Person.pm}


\subsection{PHP}

Expand Down
10 changes: 5 additions & 5 deletions codes/java/src/encapsulation/core/Person.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package encapsulation.core;

public class Person {

public int luckyNumber;
int luckyNumber2;
protected String t;
private String name;
private int num;
private static int nbr;

public Person(String name) {
this.name = name;
num = (nbr++);
t = "person";
luckyNumber = 0;
luckyNumber2 = 0;
}

public void info() {
System.out.println("My name: " + name);
System.out.println("My number: " + num);
Expand All @@ -25,9 +25,9 @@ public void info() {
System.out.println("My lucky number 2 is: " + luckyNumber2);
System.out.println("--------------------------");
}

public void copy(Person other) {
name = other.name;
num = other.num;
t = other.t;
}

Expand Down
2 changes: 1 addition & 1 deletion codes/java/src/encapsulation/core/Student.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public Student(String name) {
t = "student";
luckyNumber = 1;
luckyNumber2 = 2;
//this.name = "other name";//cannot be accessed: private
//this.num = 80;//cannot be accessed: private
}

}
41 changes: 0 additions & 41 deletions codes/lua/encapsulation/encap.lua

This file was deleted.

49 changes: 49 additions & 0 deletions codes/perl/encapsulation/Person.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package Person;

sub new {
my $class = shift;
my $self = {
name => shift,
t => "person"
};

my $closure = sub {
die "cannot access fields outside the class" unless caller eq __PACKAGE__;
my ($field, $value) = @_;
die "no field called: $field" unless exists $self->{$field};
if ($value) {#setter
$self->{$field} = $value;
}
return $self->{$field};#getter
};

bless $closure, $class;
return $closure;
}

sub t {
die "t is protected!" unless caller->isa(__PACKAGE__);
my($self, $value )= @_;
return $self->("t", $value);
}

sub _info_private {
die "_info_private is private!" unless caller eq __PACKAGE__;
my( $self ) = @_;
print "My name: ",$self->("name"),"\n";
}

sub _info_protected {
die "_info_protected is protected!" unless caller->isa(__PACKAGE__);
my( $self ) = @_;
print "I am a: ",$self->("t"),"\n";
}

sub info {
my( $self ) = @_;
_info_private(@_);
_info_protected(@_);
print "----------------------------\n";
}

1;
21 changes: 21 additions & 0 deletions codes/perl/encapsulation/Student.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package Student;
use Person;
our @ISA = qw(Person);

sub new {
my ($class, @args) = @_;
$self = $class->SUPER::new(@args);
#$self->{t} = "student";#error the object is not a HASH
#$self->("t", "student");#limited the direct access
$self->t("student");
bless $self, $class;
return $self;
}

sub use_protected {
my( $self, @args ) = @_;
# $self->_info_private(@args); #_info_private is private!
$self->_info_protected(@args);
}

1;
Loading

0 comments on commit ee83d3e

Please sign in to comment.