Strong vs weak encapsulation

David-Sarah Hopwood david-sarah at jacaranda.org
Tue Dec 21 00:27:21 PST 2010


Strong encapsulation means that the code implementing an abstraction can
control the visibility of its fields (i.e. where they can be accessed
from), without any loopholes that can be exploited by code outside the
abstraction's scope. Weak encapsulation allows such loopholes. Note that
I deliberately use the term "fields", in order to avoid the over-
specification that private fields necessarily have to be ECMAScript
properties.

I suggest that we discuss which of these strengths of encapsulation we
want, separately from the choice of how to specify the semantics of
private fields.

In principle there are three possible positions:

a) private fields should always be strongly encapsulated;
b) private fields should be weakly encapsulated;
c) private fields should be strongly encapsulated when a sandbox
   is in effect, and weakly encapsulated if not.

I will be arguing for a) and against both b) and c).

We can analyse this question from the complementary perspectives
of either software engineering or security. The security perspective
is fairly straightforward: weak encapsulation does not provide any
benefit because it can be bypassed by attacking code. c) may be
acceptable, but a) is preferred, so that code not originally written
for use in a sandbox is less likely to fail when run inside one.

From the software engineering perspective, we need any benefits of
encapsulation to be derived even when not running in a sandbox, which
means that b) and c) are roughly equivalent, and the choice is between
those and a):

Weak encapsulation creates a situation where the incentives of the
programmer(s) providing an abstraction are misaligned with the
incentives of the programmer(s) using it. The provider wants to be
able to rely on the encapsulation to prevent clients from depending
on implementation details, so that those details can be changed
compatibly. The client programmers just want their code to work.
The client can (sometimes) get their code to work by breaking the
encapsulation. This is often perceived to be easier than communicating
with the provider in order to get the bug fixed or support the missing
feature.

Some client programmers, faced with such a problem, might refrain from
breaking the encapsulation, even though they could have used it to
work around the problem. In that case, of course, they obtain no
advantage from the encapsulation mechanism being weak. Only clients
who do choose to break the encapsulation obtain any such advantage,
and they do so only at the expense of making their code more fragile
and creating compatibility problems for the provider. The provider
can choose to ignore such problems, but then any client code that
violated encapsulation will be liable to malfunction when it is used
with the new version of the provider's code. (It is possible that any
particular change will not break any particular client, but that would
only be by luck.)

Misaligned incentives do neither party any good.

There are a couple more points that strengthen the above argument:

 - it may be the case that an encapsulation-violating client *appears*
   to work in testing, but actually doesn't in all situations. This is
   quite likely when the client programmers' understanding of the
   provider code is based on reverse-engineering.

 - the ability to break encapsulation as a workaround may create a
   disincentive to reporting the bug or feature request.
   The abstraction is therefore less likely to be changed in a way
   that other users could benefit from.


A possible counterargument goes something like this:

By breaking encapsulation, a client programmer may be able to make
this version of their code work with the *current* version of the
abstraction they are violating. This does have some value (even though
the code is now fragile, and less understandable because the provider
and client code cannot be understood independently).

As you can probably tell, I'm not much impressed by this counterargument.
It's a viewpoint that favours short-termism and code that works by
accident, rather than code that reliably works by design.

Note that in the case where the same programmers are writing the
provided abstraction and its *only* clients, it makes no sense to
use reflection to bypass encapsulation; they might as well make the
field public (or use selective visibility as discussed below).
Doing so would result in clearer code. So weak encapsulation provides
no advantage in this case either.


There's another potential counterargument against the way strong
encapsulation is supported in some (typically class-based) languages,
that may have more merit. It says that a sharp distinction between
"public" and "private", where "private" fields can only be accessed
from within their class definition, can sometimes be insufficiently
expressive. That is, we might want "private" fields to be selectively
accessible from outside the class definition, but not to all code
outside it.

Note, however, that for both the soft fields and the private names
proposals, the scope in which a private field can be accessed can
be controlled lexically. (In the soft fields case, this does not
depend on the use of the 'private id' syntax.)
This can be used to simulate visibility mechanisms found in other
languages, such as export lists and interfaces with different visibility
in Eiffel, package access in Java, etc.

Not all visibility mechanisms from other languages can be sensibly
simulated this way. For example, friend declarations in C++ allow
arbitrary code to give itself private access to arbitrary other code.
("I'm your friend! Deal with it!" :-) That could only be simulated
by putting the 'private' or SoftField declaration at global scope,
which would be pointless. Note that friend declarations are a widely
criticised misfeature of C++ -- e.g. see
<http://www.zechweb.de/Joyners_cpp_critique/index003.htm#s03-26> --
precisely because they are incompatible with strong encapsulation.


The private names and soft field proposals are similar in the
visibility mechanisms they can simulate, but soft fields are slightly
more general. In either proposal, visibility can be restricted to a
particular lexical scope. In the soft fields proposal, because
SoftFields are first-class values, it can also be restricted to any
set of objects that can get access to a given SoftField. I don't
claim this to be a critical benefit, but it is occasionally
useful in object-capability programming. For example, in
<http://www.erights.org/elib/capability/ode/ode-capabilities.html#simple-money>,
a Purse of a given currency is supposed to be able to access a
private field of other Purses of the same currency, but not other
Purses of different currencies. The implementation at
<http://www.eros-os.org/pipermail/cap-talk/2007-June/007885.html>
uses WeakMaps to do this, and could just as well use soft fields if
transliterated to ECMAScript.

-- 
David-Sarah Hopwood  ⚥  http://davidsarah.livejournal.com

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 292 bytes
Desc: OpenPGP digital signature
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20101221/6fb0eafd/attachment-0001.bin>


More information about the es-discuss mailing list