Skip to content

Commit ee83d3e

Browse files
committed
encapsulation chapter: perl => DONE
1 parent 4d1ae31 commit ee83d3e

File tree

12 files changed

+314
-63
lines changed

12 files changed

+314
-63
lines changed

REF.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
* https://perldoc.perl.org/perlootut.html
3535
* http://ods.com.ua/win/eng/program/Perl5Unleashed/ch5.phtml
3636
* https://www.perl.com/pub/2002/11/14/exception.html/
37+
* https://www.perlmonks.org/?node_id=571509
38+
* https://www.perlmonks.org/?node_id=8251
3739

3840
## Php
3941

book/cite.bib

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ @article{1993-kay
1515
acmid = {155364},
1616
publisher = {ACM},
1717
address = {New York, NY, USA},
18-
}
18+
}
19+

book/encapsulation.tex

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
\chapter{Encapsulation}
1010

1111
\begin{introduction}
12-
Encapsulation is one important concept of OOP.
12+
Encapsulation is an important concept of OOP.
1313
It is the mechanism of restricting direct access to some members of a class.
1414
It helps managing complexity when debugging source code.
1515
If a field is accessed everywhere in your source code, this makes it difficult to find errors related to this field.
1616
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).
1717
In this chapter, we will show different visibility modes and how they are implemented in each language.
18-
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".
18+
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".
1919
So, a programming language may fall into one or another.
2020
\end{introduction}
21+
Some languages have just public fields, and it is up to programmers to decide if they want to access it directly.
2122

2223
\section{Public members}
2324

@@ -55,7 +56,7 @@ \subsection{Java}
5556

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

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

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

9798
\subsection{Perl}
9899

99-
%\lstinputlisting[language=Perl, linerange={4-4}, style=codeStyle]{../codes/perl/person.pl}
100+
\begin{kodequote}{Larry Wall}
101+
Perl doesn't have an infatuation with enforced privacy.
102+
It would prefer that you stayed out of its living room because you weren't invited, not because it has a shotgun.
103+
\end{kodequote}
104+
105+
I guess you get the idea: all members are public.
106+
But, in Perl, there is always a hack to limit visibility.
107+
Let's see the normal case where every field and method are public.
108+
109+
\lstinputlisting[language=Perl, linerange={1-18}, style=codeStyle]{../codes/perl/encapsulation/public.pl}
110+
111+
They can be accessed outside the class
112+
113+
\lstinputlisting[language=Perl, linerange={20-22}, style=codeStyle]{../codes/perl/encapsulation/public.pl}
100114

101115
\subsection{PHP}
102116

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

130144
\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}
@@ -137,6 +151,10 @@ \subsection{Ruby}
137151

138152
\section{Protected members}
139153

154+
Protected visibility mode is used to access a member of a class from the class itself and its subclasses.
155+
For fields as for methods, it is used to allow subclasses accessing them directly.
156+
If you define a member as protected, keep in mind that changing it later may break subclasses.
157+
140158
\subsection{C++}
141159

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

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

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

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

181199
There is no protected members in Javascript.
182200
You can find some hacks on the web, but they can be expensive in term of memory and processing power.
183-
To emulate such mechanism, you have to know the caller object
201+
To emulate such mechanism, you have to know the caller object.
184202
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}}.
185203

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

193211
\subsection{Perl}
194212

195-
%\lstinputlisting[language=Perl, linerange={4-4}, style=codeStyle]{../codes/perl/person.pl}
213+
Perl can capture the caller (the location or package where a function was called) using the keyword \keyword{caller}.
214+
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.
215+
Adding to it the keyword \keyword{\_\_PACKAGE\_\_} which captures the current package and exception management \keyword{die}, Bingo! we can limit access.
216+
We cannot limit visibility: the method is still visible, but we raise an exception if the access does not serve our purpose.
217+
218+
\begin{lstlisting}[language=Perl, style=codeStyle]
219+
package Person;
220+
# ...
221+
sub protected_fct {
222+
die "protected_fct is protected!" unless caller->isa(__PACKAGE__);
223+
# ... The rest of the code
224+
}
225+
1;
226+
\end{lstlisting}
227+
228+
As for fields, you can hide them entirely (private) then use getters and setters to access them.
229+
Since these getters/setters are methods, you can limit their access.
230+
231+
%\lstinputlisting[language=Perl, linerange={4-4}, style=codeStyle]{../codes/perl/encapsulation/person.pl}
196232

197233
\subsection{PHP}
198234

@@ -255,6 +291,10 @@ \subsection{Ruby}
255291

256292
\section{Private members}
257293

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

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

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

280320
It cannot be accessed from a subclass
281321

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

284-
And sure cannot be accessed from another class
324+
Also, it cannot be accessed from another class
285325

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

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

294334
There is a convention to use underscore \keyword{\_} as a mean to signal a class member as private.
295335
But the member still accessible as public.
296-
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}.
336+
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}.
297337
But, any method using this variable must be defined inside the constructor.
298-
This means each time you create a new instance (object), a new function will be created for this object.
338+
This means each time you create a new instance (object), a new method will be created for this object.
299339

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

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

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

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

319359
\subsection{Perl}
320360

321-
%\lstinputlisting[language=Perl, linerange={4-4}, style=codeStyle]{../codes/perl/person.pl}
361+
There is a convention to start private members with underscore \keyword{\_}, but they still are accessible.
362+
For methods, you can use \keyword{caller}, \keyword{eq}, \keyword{\_\_PACKAGE\_\_} and \keyword{die} to limit access though they still are visible.
363+
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.
364+
365+
\begin{lstlisting}[language=Perl, style=codeStyle]
366+
package Person;
367+
# ...
368+
sub private_fct {
369+
die "private_fct is private!" unless caller eq __PACKAGE__;
370+
# ... The rest of the code
371+
}
372+
1;
373+
\end{lstlisting}
374+
375+
As for fields, you can hide them entirely (private) using many ways.
376+
377+
\subsubsection{Using scope and object reference}
378+
379+
This is a method I thought of in order to hide internal fields of an object.
380+
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.
381+
The hash must be defined using \keyword{my} and not \keyword{our} so it will not be accessible outside the package.
382+
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.
383+
You can consider this hash as a private static member.
384+
To get an object's reference in memory, you can use \keyword{refaddr} function.
385+
386+
\lstinputlisting[language=Perl, linerange={2-4,6-6,8-16,22-23,56-57}, style=codeStyle]{../codes/perl/encapsulation/private.pl}
387+
388+
Then, you can access any field of an object using the instruction \textbf{\$private\{refaddr \$obj\}->\{name\}}.
389+
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.
390+
391+
\lstinputlisting[language=Perl, linerange={2-5,25-32,43-47,56-57}, style=codeStyle]{../codes/perl/encapsulation/private.pl}
392+
393+
If you want a protected access, just modify the setter/getter to do so.
394+
In addition, if you want to prevent modifying the content of a protected field from a subclass, just delete the setter code block.
395+
396+
\subsubsection{Using closures}
397+
398+
This solution is what you will find on the web. %ref to https://www.perlmonks.org/?node_id=8251
399+
Instead of using hashes as objects, you may implement them as closures.
400+
A closure is a subroutine reference that has access to the lexical variables that were in scope when it was created.
401+
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.
402+
The solution presented here is a simplified one, with some restrictions on closure.
403+
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.
404+
405+
\lstinputlisting[language=Perl, linerange={1-28,49-49}, style=codeStyle]{../codes/perl/encapsulation/Person.pm}
406+
322407

323408
\subsection{PHP}
324409

codes/java/src/encapsulation/core/Person.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
package encapsulation.core;
22

33
public class Person {
4-
4+
55
public int luckyNumber;
66
int luckyNumber2;
77
protected String t;
88
private String name;
99
private int num;
1010
private static int nbr;
11-
11+
1212
public Person(String name) {
1313
this.name = name;
1414
num = (nbr++);
1515
t = "person";
1616
luckyNumber = 0;
1717
luckyNumber2 = 0;
1818
}
19-
19+
2020
public void info() {
2121
System.out.println("My name: " + name);
2222
System.out.println("My number: " + num);
@@ -25,9 +25,9 @@ public void info() {
2525
System.out.println("My lucky number 2 is: " + luckyNumber2);
2626
System.out.println("--------------------------");
2727
}
28-
28+
2929
public void copy(Person other) {
30-
name = other.name;
30+
num = other.num;
3131
t = other.t;
3232
}
3333

codes/java/src/encapsulation/core/Student.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public Student(String name) {
77
t = "student";
88
luckyNumber = 1;
99
luckyNumber2 = 2;
10-
//this.name = "other name";//cannot be accessed: private
10+
//this.num = 80;//cannot be accessed: private
1111
}
1212

1313
}

codes/lua/encapsulation/encap.lua

Lines changed: 0 additions & 41 deletions
This file was deleted.

codes/perl/encapsulation/Person.pm

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package Person;
2+
3+
sub new {
4+
my $class = shift;
5+
my $self = {
6+
name => shift,
7+
t => "person"
8+
};
9+
10+
my $closure = sub {
11+
die "cannot access fields outside the class" unless caller eq __PACKAGE__;
12+
my ($field, $value) = @_;
13+
die "no field called: $field" unless exists $self->{$field};
14+
if ($value) {#setter
15+
$self->{$field} = $value;
16+
}
17+
return $self->{$field};#getter
18+
};
19+
20+
bless $closure, $class;
21+
return $closure;
22+
}
23+
24+
sub t {
25+
die "t is protected!" unless caller->isa(__PACKAGE__);
26+
my($self, $value )= @_;
27+
return $self->("t", $value);
28+
}
29+
30+
sub _info_private {
31+
die "_info_private is private!" unless caller eq __PACKAGE__;
32+
my( $self ) = @_;
33+
print "My name: ",$self->("name"),"\n";
34+
}
35+
36+
sub _info_protected {
37+
die "_info_protected is protected!" unless caller->isa(__PACKAGE__);
38+
my( $self ) = @_;
39+
print "I am a: ",$self->("t"),"\n";
40+
}
41+
42+
sub info {
43+
my( $self ) = @_;
44+
_info_private(@_);
45+
_info_protected(@_);
46+
print "----------------------------\n";
47+
}
48+
49+
1;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package Student;
2+
use Person;
3+
our @ISA = qw(Person);
4+
5+
sub new {
6+
my ($class, @args) = @_;
7+
$self = $class->SUPER::new(@args);
8+
#$self->{t} = "student";#error the object is not a HASH
9+
#$self->("t", "student");#limited the direct access
10+
$self->t("student");
11+
bless $self, $class;
12+
return $self;
13+
}
14+
15+
sub use_protected {
16+
my( $self, @args ) = @_;
17+
# $self->_info_private(@args); #_info_private is private!
18+
$self->_info_protected(@args);
19+
}
20+
21+
1;

0 commit comments

Comments
 (0)