Break OO privacy

From Rosetta Code
Revision as of 21:26, 26 October 2011 by 192.139.122.42 (talk) (→‎{{header|Common Lisp}}: Less text, more code.)
Break OO privacy is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Show how to access private or protected members of a class in an object oriented language from outside an instance of the class, without calling non-private or non-protected members of the class as a proxy.

Note that this is almost universally regarded as unidiomatic at best, and poor programming practice at worst.

Please read and contribute to the talk page before adding examples as I wouldn't be surprised if the task has a short life.

C#

<lang csharp>using System; using System.Reflection;

public class MyClass {

   private int answer = 42;

}

public class Program {

   public static void Main()
   {
       var myInstance = new MyClass();
       var fieldInfo = typeof(MyClass).GetField("answer", BindingFlags.NonPublic | BindingFlags.Instance);
       var answer = fieldInfo.GetValue(myInstance);
       Console.WriteLine(answer);
   }

}</lang> Output: <lang>42</lang>

C++

C++ has the 'friend' keyword to indicate that one class should have access to the private data of another. Here's a simple use case. (Please note that this code is not thread-safe.)

<lang cpp>#include <iostream>

class CWidget; // Forward-declare that we have a class named CWidget.

class CFactory {

 friend class CWidget;

private:

 unsigned int m_uiCount;

public:

 CFactory();
 ~CFactory();
 CWidget* GetWidget();

};

class CWidget { private:

 CFactory& m_parent;

private:

 CWidget(); // Disallow the default constructor.
 CWidget(const CWidget&); // Disallow the copy constructor
 CWidget& operator=(const CWidget&); // Disallow the assignment operator.

public:

 CWidget(CFactory& parent);
 ~CWidget();

};

// CFactory constructors and destructors. Very simple things. CFactory::CFactory() : m_uiCount(0) {} CFactory::~CFactory() {}

// CFactory method which creates CWidgets. CWidget* CFactory::GetWidget() {

 // Create a new CWidget, tell it we're its parent.
 return new CWidget(*this);

}

// CWidget constructor CWidget::CWidget(CFactory& parent) : m_parent(parent) {

 ++m_parent.m_uiCount;
 std::cout << "Widget spawning. There are now " << m_parent.m_uiCount << " Widgets instanciated." << std::endl;

}

CWidget::~CWidget() {

 --m_parent.m_uiCount;
 std::cout << "Widget dieing. There are now " << m_parent.m_uiCount << " Widgets instanciated." << std::endl;

}

int main() {

 CFactory factory;
 CWidget* pWidget1 = factory.GetWidget();
 CWidget* pWidget2 = factory.GetWidget();
 delete pWidget1;
 CWidget* pWidget3 = factory.GetWidget();
 delete pWidget3;
 delete pWidget2;

}</lang>

Output: <lang text>Widget spawning. There are now 1 Widgets instanciated. Widget spawning. There are now 2 Widgets instanciated. Widget dieing. There are now 1 Widgets instanciated. Widget spawning. There are now 2 Widgets instanciated. Widget dieing. There are now 1 Widgets instanciated. Widget dieing. There are now 0 Widgets instanciated.</lang>

Without the "friend" mechanism, it's still possible to meaningfully modify any member in another class, as long as you know that member's address in memory, and its type. Here's the same program as above, but using a pointer to m_uicount, rather a reference to the factory:

<lang cpp>#include <iostream>

class CWidget; // Forward-declare that we have a class named CWidget.

class CFactory { private:

 unsigned int m_uiCount;

public:

 CFactory();
 ~CFactory();
 CWidget* GetWidget();

};

class CWidget { private:

 unsigned int* m_pCounter;

private:

 CWidget(); // Disallow the default constructor.
 CWidget(const CWidget&); // Disallow the copy constructor
 CWidget& operator=(const CWidget&); // Disallow the assignment operator.

public:

 CWidget(unsigned int* pCounter);
 ~CWidget();

};

// CFactory constructors and destructors. Very simple things. CFactory::CFactory() : m_uiCount(0) {} CFactory::~CFactory() {}

// CFactory method which creates CWidgets. CWidget* CFactory::GetWidget() {

 // Create a new CWidget, tell it we're its parent.
 return new CWidget(&m_uiCount);

}

// CWidget constructor CWidget::CWidget(unsigned int* pCounter) : m_pCounter(pCounter) {

 ++*m_pCounter;
 std::cout << "Widget spawning. There are now " << *m_pCounter<< " Widgets instanciated." << std::endl;

}

CWidget::~CWidget() {

 --*m_pCounter;
 std::cout << "Widget dieing. There are now " << *m_pCounter<< " Widgets instanciated." << std::endl;

}

int main() {

 CFactory factory;
 CWidget* pWidget1 = factory.GetWidget();
 CWidget* pWidget2 = factory.GetWidget();
 delete pWidget1;
 CWidget* pWidget3 = factory.GetWidget();
 delete pWidget3;
 delete pWidget2;

}</lang>

Common Lisp

Common Lisp doesn't have concepts like class scopes, name lookup rules, or access. Essentially, the way things are referenced in the source code (the static view of the program) is not involved in the class hierarchy. For instance, when a class is derived from another one, it is purely an object-oriented inheritance. There is no parallel symbol-table inheritance going on whereby one namespace becomes a tributary of another (the identifier scope of a derived class inheriting symbols from, or a visibility window into the base class).

Classes, generic functions and methods are objects. Their naming by symbols is secondary, in a way. For instance, when we instantiate an object of class C in Lisp using (make-instance 'c), we are actually invoking the specialization of the make-instance method to the symbol type. This method is a wrapper which invokes (make-instance (find-class 'c)), where find-class returns a class based on the symbol which names it. Ultimately, the instantiation method is being run on the class object, not the class name. The name is thus only loosely connected to the class. By contrast in other languages, the class name is a big deal. It establishes the name of a scope, and perhaps of special functions such as constructors, and such.

In Lisp, if a superclass and a derived class define a slot of the same name, there is simply no clash. The result is that the derived class just has one slot of that name, with the derived class having control over certain attributes of the slot, such as redefining a shared (class-wide) slot to be local (per instance) or vice versa. [1]

The concept of privacy in Lisp is located in the package system. An external symbol S in package P can be accessed using P:S. If S is internal then P:S results in error at read time. This is completely independent of context and orthogonal to the use of symbols to denote class slots (instance variables), methods, functions, class names themselves, global variables, et cetera. Even if the private symbol appears in a literal piece of data like a quoted list, it is an error to refer to it: (1 2 3 P:S). The internal symbol S in package P can be accessed using P::S. This is easy to do because programmers are assumed to be responsible grownups who can be trusted to know what they are donig. Also, note that this privacy is a property of the relationship between a symbol and a package. A symbol can be present in more than one package, such that it can be internal in some of them, and external in others.

<lang lisp>(defpackage :funky

 ;; only these symbols are public
 (:export :widget :get-wobbliness)
 ;; for convenience, bring common lisp symbols into funky
 (:use :cl))
switch reader to funky package
all symbols that are
not from the CL package are interned in FUNKY.

(in-package :funky)

(defclass widget ()

 ;; :initarg -> slot "wobbliness" is initialized using :wobbliness keyword
 ;; :initform -> if initarg is missing, slot defaults to 42
 ;; :reader -> a "getter" method called get-wobbliness is generated
 ((wobbliness :initarg :wobbliness :initform 42 :reader get-wobbliness)))
simulate being in another source file with its own package
cool package gets external symbols from funky, and cl

(defpackage :cool

 (:use :funky :cl))

(in-package :cool)

we can use the symbol funky
widget without any package prefix

(defvar *w* (make-instance 'widget :wobbliness 36))

ditto with funky
get-wobbliness

(format t "wobbliness: ~a~%" (get-wobbliness *w*))

direct access to the slot requires fully qualified private symbol
and double colon

(format t "wobbliness: ~a~%" (slot-value *w* 'funky::wobbliness))

if we use unqualified wobbliness, it's a different symbol
it is cool
:wobbliness interned in our local package.
we do not have funky
wobbliness because it's not exported by funky.

(unless (ignore-errors

         (format t "wobbliness: ~a~%" (slot-value *w* 'wobbliness)))
 (write-line "didn't work"))
single colon results in error at read time! The expression is not
even read and evaluated. The symbol is internal and so cannot be used.

(format t "wobbliness: ~a~%" (slot-value *w* 'funky:wobbliness)) </lang>

Output using CLISP:

wobbliness: 36
wobbliness: 36
didn't work
*** - READ from #<INPUT BUFFERED FILE-STREAM CHARACTER #P"funky.lisp" @44>:
      #<PACKAGE FUNKY> has no external symbol with name "WOBBLINESS"

E

In its goal of supporting programs including mutually suspicious robust components and potentially executing untrusted code, E specifically does not provide any means within the language to break the encapsulation of an object. The official answer to how you access private state is: evaluate the code with a special evaluator which permits such access to the objects the code creates, or, entirely equivalently, transform the code so that each object definition has hooks for private access.


This example is in need of improvement:

Show an example of such an evaluator once it is available.

Factor

From the documentation for private words: "Privacy is not enforced by the system; private words can be called from other vocabularies, and from the listener. However, this should be avoided where possible."

This example uses the private word sequence/tester from the vocabulary sets.private. It tries to count the elements in an intersection of two sets.

<lang factor>( scratchpad ) USING: sets sets.private ; ( scratchpad ) { 1 2 3 } { 1 2 4 } sequence/tester count . 2</lang>

There is better way to do the same, without any private words.

<lang factor>( scratchpad ) USE: sets ( scratchpad ) { 1 2 3 } { 1 2 4 } intersect length . 2</lang>

Java

Private fields (and in general all members) of a Java class can be accessed via reflection, but must pass a security check in order to do so. There are two such security checks, one for discovering the field at all, and another for granting access to it in order to be able to read and write it. (This in turn means that trusted applications can do this — it is in fact a mechanism used by important frameworks like Spring — but untrusted applets cannot.) <lang java>import java.lang.reflect.*;

class Example {

   private String _name;
   public Example(String name) { _name = name; }
   public String toString() { return "Hello, I am " + _name; }

}

public class BreakPrivacy {

   public static final void main(String[] args) throws Exception {
       Example foo = new Example("Eric");
       for (Field f : Example.class.getDeclaredFields()) { 

if (f.getName().equals("_name")) {

               // make it accessible
               f.setAccessible(true);
               // get private field
               System.out.println(f.get(foo));
               // set private field
               f.set(foo, "Edith");

System.out.println(foo);

               break;
           }
       }
   }

}</lang>

Output:

Eric
Hello, I am Edith

Objective-C

In Objective-C, you can simply access a private field. The compiler will give a warning, but you can ignore it and it will still compile. <lang objc>#import <Foundation/Foundation.h>

@interface Example : NSObject { @private

 NSString *_name;

} - (id)initWithName:(NSString *)name; @end

@implementation Example - (NSString *)description {

 return [NSString stringWithFormat:@"Hello, I am %@", _name];

} - (id)initWithName:(NSString *)name {

 if ((self = [super init])) {
   _name = [name copy];
 }
 return self;

} - (void)dealloc {

 [_name release];
 [super dealloc];

} @end

int main (int argc, const char * argv[]) {

 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
 Example *foo = [[Example alloc] initWithName:@"Eric"];
 
 // get private field
 NSLog(@"%@", foo->_name);
 
 // set private field
 [foo->_name release];
 foo->_name = [@"Edith" copy];
 NSLog(@"%@", foo);
 [foo release];
 
 [pool release];
 return 0;

} </lang>

Output:

Eric
Hello, I am Edith

PicoLisp

PicoLisp uses "transient symbols" for variables, functions, methods etc. inaccessible from other parts of the program. Lexically, a transient symbol is enclosed by double quotes. The only way to access a transient symbol outside its namespace is to search for its name in other (public) structures. This is done by the 'loc' function. <lang PicoLisp>(class +Example)

  1. "_name"

(dm T (Name)

  (=: "_name" Name) )

(dm string> ()

  (pack "Hello, I am " (: "_name")) )

(====) # Close transient scope

(setq Foo (new '(+Example) "Eric"))</lang> Test: <lang PicoLisp>: (string> Foo) # Access via method call -> "Hello, I am Eric"

(get Foo '"_name") # Direct access doesn't work

-> NIL

(get Foo (loc "_name" +Example)) # Locating the transient symbol works

-> "Eric"

(put Foo (loc "_name" +Example) "Edith")

-> "Edith"

(string> Foo) # Ditto

-> "Hello, I am Edith"

(get Foo '"_name")

-> NIL

(get Foo (loc "_name" +Example))

-> "Edith"</lang>

PHP

While normally accessing private variables causes fatal errors, it's possible to catch output of some debugging functions and use it. Known functions which can get private variables include: var_dump(), print_r(), var_export() and serialize(). The easiest to use is var_export() because it's both valid PHP code and doesn't recognize private and public variables.

Works with: PHP version 5.1

<lang php><?php class SimpleClass {

   private $answer = "hello\"world\nforever :)";

}

$class = new SimpleClass; ob_start();

// var_export() expects class to contain __set_state() method which would import // data from array. But let's ignore this and remove from result the method which // sets state and just leave data which can be used everywhere... var_export($class); $class_content = ob_get_clean();

$class_content = preg_replace('"^SimpleClass::__set_state\("', 'return ', $class_content); $class_content = preg_replace('"\)$"', ';', $class_content);

$new_class = eval($class_content); echo $new_class['answer'];</lang>

Another way commonly used to access private and protected variables in PHP is to cast the object to an array. It's probably unintentional though looking on how casted array contains null bytes (probably "private" mark). This works unless a magic method for the cast operation is implemented:

Works with: PHP version 4.x
Works with: PHP version 5.x

<lang php><?php class SimpleClass {

   private $answer = 42;

}

$class = new SimpleClass; $classvars = (array)$class; echo $classvars["\0SimpleClass\0answer"];</lang>

Ruby

In Ruby, you can use .send to send any message to any object, even private ones: <lang ruby>>> class Example >> private >> def name >> "secret" >> end >> end => nil >> example = Example.new => #<Example:0x101308408> >> example.name NoMethodError: private method `name' called for #<Example:0x101308408> from (irb):10 from :0 >> example.send(:name) => "secret"</lang>

Tcl

Tcl's object properties are just variables in the a per-instance namespace; all that's required to get hold of them is to discover the name of the namespace concerned: <lang tcl>package require Tcl 8.6

oo::class create Example {

   variable name
   constructor n {set name $n}
   method print {} {puts "Hello, I am $name"}

} set e [Example new "Eric"] $e print set [info object namespace $e]::name "Edith" $e print</lang> Produces this output:

Hello, I am Eric
Hello, I am Edith