Erlang (programming language)/Tutorials/erlangOOP: Difference between revisions

From Citizendium
Jump to navigation Jump to search
imported>Eric Evers
mNo edit summary
imported>Eric Evers
mNo edit summary
Line 8: Line 8:
Its parent complex, knows how to take the square root of negative numbers.  
Its parent complex, knows how to take the square root of negative numbers.  
Its parent matrix, knows how to take the square root of a diagonal matrix.  
Its parent matrix, knows how to take the square root of a diagonal matrix.  
Logically, the traditional class relationship is held in the class diagram. An integer is a Real. A Real(float) is a (subset of) complex. An a complex number is a (subset of) complex matrices, if we think of a (1 by 1) matrix a single number.


If a process does not know how to do something, it passes it to its parent(process in this situation).
If a process does not know how to do something, it passes it to its parent(process in this situation).
Line 24: Line 26:
     |              |     
     |              |     
     |              |       
     |              |       
  +---------+     +---------+  
  +-----------+   +-----------+  
  | Object  |     | Object |
  | Object   |  | Object    |
  +---------+    +---------+  
+-----------+  +-----------+
  | id        |  | id        |
| classname |  | classname |
  | name      |  | name      |
  +-----------+  +-----------+
| get()    |  | get()     |
+-----------+   +-----------+  
     / \            / \     
     / \            / \     
     |              |     
     |              |     
Line 32: Line 40:
  +---------+    +---------+
  +---------+    +---------+
  | Matrix  |    | Matrix  |
  | Matrix  |    | Matrix  |
+---------+    +---------+
  +---------+    +---------+
  +---------+    +---------+
  | sqrt()  |    | sqrt()  |
  | sqrt()  |    | sqrt()  |
Line 40: Line 49:
  +---------+    +---------+
  +---------+    +---------+
  | Complex |    | Complex |
  | Complex |    | Complex |
+---------+    +---------+
  +---------+    +---------+
  +---------+    +---------+
  | sqrt()  |    | sqrt()  |
  | sqrt()  |    | sqrt()  |
Line 45: Line 55:
     / \            / \     
     / \            / \     
     |              |       
     |              |       
    |              |   
+---------+    +---------+
| Float  |    | Float  |
+---------+    +---------+
+---------+    +---------+
| sqrt()  |    | sqrt()  |
+---------+    +---------+
    / \            / \   
     |              |       
     |              |       
    |              |
  +---------+    +---------+
  +---------+    +---------+
  | Integer |    | Integer |
  | Integer |    | Integer |
+---------+    +---------+
  +---------+    +---------+
  +---------+    +---------+
  | sqrt()  |    | sqrt()  |
  | sqrt()  |    | sqrt()  |
Line 70: Line 90:
   
   
  start()->
  start()->
     Obj_1         = spawn_link(mathobjects, integer, []),   
     Obj_1             = spawn_link(mathobjects, integer, []),   
  Id_1       = rpc(Obj_1, {get, id}),             
  Id_1       = rpc(Obj_1, {get, id}),             
  Name_1        = rpc(Obj_1, {get, name}),           
  Name_1        = rpc(Obj_1, {get, name}),           

Revision as of 06:39, 29 October 2008

Objects with Erlang

Erlang is a functional programming language and a concurrency oriented programming languages (Armstrong, 2005), but Erlang does not have explicit built-in object oriented language features. An object oriented programming style can be achieved by alternative means easily. It is particularly easy to do object programming if we restrict ourselves to single inheritance. One can use processes to represent classes and messages to represent methods. To do so, each object when created can create a chain of processes that represent their ancestors in the inheritance chain. The methods(messages) can be passed up the chain until they reach a process that has a matching method. If the message reaches the top of the chain(the Object class or above that dev_nul) then we can generate an exception for a "bad method name". Each class(process) will maintain its own attributes(variables) in its own recursive argument call list. These attributes can be accessed and updated with messages such as get and set. Attributes are stored in a dictionary called a Bundle, in each class process.

Included is some example code that creates OOP using the described technique. In the program, we create an instance of the class integer. Its parent float, knows how to take the square root of reals. Its parent complex, knows how to take the square root of negative numbers. Its parent matrix, knows how to take the square root of a diagonal matrix.

Logically, the traditional class relationship is held in the class diagram. An integer is a Real. A Real(float) is a (subset of) complex. An a complex number is a (subset of) complex matrices, if we think of a (1 by 1) matrix a single number.

If a process does not know how to do something, it passes it to its parent(process in this situation). If we tried to do something like take the sqrt(non-diag-matrix) it would be passed up to dev_nul and generate an error.

----------------------------------------------------------------
 Original        Each object has its own process for each of its ancestors 
 Classes         (Process chain for object Obj_1)
 
+---------+     +---------+
| dev_nul |     | dev_nul |
+---------+     +---------+
   / \             / \    
    |               |    
    |               |      
+-----------+   +-----------+ 
| Object    |   | Object    |
+-----------+   +-----------+
| id        |   | id        |
| classname |   | classname |
| name      |   | name      |
+-----------+   +-----------+
| get()     |   | get()     |
+-----------+   +-----------+ 
   / \             / \     
    |               |     
    |               |      
+---------+     +---------+
| Matrix  |     | Matrix  |
+---------+     +---------+
+---------+     +---------+
| sqrt()  |     | sqrt()  |
+---------+     +---------+
   / \             / \     
    |               |      
    |               |      
+---------+     +---------+
| Complex |     | Complex |
+---------+     +---------+
+---------+     +---------+
| sqrt()  |     | sqrt()  |
+---------+     +---------+ 
   / \             / \     
    |               |      
    |               |     
+---------+     +---------+
| Float   |     | Float   |
+---------+     +---------+
+---------+     +---------+
| sqrt()  |     | sqrt()  |
+---------+     +---------+ 
   / \             / \     
    |               |      
    |               | 
+---------+     +---------+
| Integer |     | Integer |
+---------+     +---------+
+---------+     +---------+
| sqrt()  |     | sqrt()  |
+---------+     +---------+
---------------------------------------
Program output:
1> mathobjects:start().
[
[{id,#Ref<0.0.0.27>},{class_name,integer},{name,book}],
2.00000, 0.20000,
{2.00000, i},
[[2.00000,0],[0,3.00000]]
]
---------------------------------------
-module(mathobjects).
-compile(export_all).

start()->
   Obj_1             = spawn_link(mathobjects, integer, []),  
	Id_1 	      = rpc(Obj_1, {get, id}),             
	Name_1        = rpc(Obj_1, {get, name}),           
	Class_Name_1  = rpc(Obj_1, {get, class_name}),     
	% -------------------------------
	R0 = [ Id_1, Class_Name_1, Name_1 ],
	R1 = rpc(Obj_1, {sqrt, 4}),
	R2 = rpc(Obj_1, {sqrt, 0.04}),
	R3 = rpc(Obj_1, {sqrt, -4}),
	R4 = rpc(Obj_1, {sqrt, [[4,0],[0,9]]}),
	[R0, R1, R2, R3, R4].
	
rpc(Dest, Msg) ->
	Dest ! {self(), Msg},
	receive
		Answer -> 
			Answer
	after 1000 ->
		ok
	end.

dev_null() ->
	receive
		{From, Any} -> From ! {Any, attribute_unknown}
	end,
	dev_null().

object() ->
	Id 		= erlang:make_ref(),
	Class_Name 	= object,
	Bundle 		= dict:from_list([ {id,Id}, {class_name, Class_Name} ]),
	Parent 		= spawn(objects, dev_null, []),
	object(Parent, Bundle).

object(Parent, Bundle) ->
	receive
		{From, {get, Attribute}} ->
			handle_get_attribute(Attribute, From, Bundle, Parent)
	end,
	object(Parent, Bundle).

% default constructor 

matrix() ->
	Class_Name      = matrix,
	Name            = book,
	Parent 	        = spawn_link(mathobjects, object, []),
	Parent_Class    = object,
	Bundle = dict:from_list( [
		{class_name, Class_Name},
		{parent_class, Parent_Class},
		{name, Name},
		{parent, Parent}]),
	matrix(Parent, Bundle).
	
matrix(Parent, Bundle) ->
	receive
		{From, {get, Attribute}} ->
			handle_get_attribute(Attribute, From, Bundle, Parent);
		{set, Attribute, Value} ->
			NBundle = handle_set_attribute(Attribute, Value, Bundle, Parent),
			matrix(Parent, NBundle);
		{From, {sqrt, [[A,B],[C,D]]}} when B==0, C==0 ->
			Out = [[math:sqrt(A),0],[0,math:sqrt(D)]],
			From ! Out; 
		Any ->
			Parent ! Any
	end,
	matrix(Parent, Bundle).
	
complex() ->
	Class_Name      = complex,
	Name            = book,
	Parent 	        = spawn_link(mathobjects, matrix, []),
	Parent_Class    = object,
	Bundle = dict:from_list( [
		{class_name, Class_Name},
		{parent_class, Parent_Class},
		{name, Name},
		{parent, Parent} ] ),
	complex(Parent, Bundle).
	
complex(Parent, Bundle) ->
  	receive
		{From, {get, Attribute}} ->
			handle_get_attribute(Attribute, From, Bundle, Parent);
		{set, Attribute, Value} ->
			NBundle = handle_set_attribute(Attribute, Value, Bundle, Parent),
			complex(Parent, NBundle);
		{From, {sqrt, Arg}} when is_list(Arg) ->
			Parent ! {From, {sqrt, Arg}};
		{From, {sqrt, Arg}} when Arg < 0 ->
			Out = {math:sqrt(0-Arg), i},
			From ! Out;
		Any ->
			Parent ! Any
	end,
	complex(Parent, Bundle).
	
float() ->
 	Class_Name      = float,
	Name            = book,
	Parent 	        = spawn_link(mathobjects, complex, []),
	Parent_Class    = object,
	Bundle = dict:from_list( [
		{class_name, Class_Name},
		{parent_class, Parent_Class},
		{name, Name},
		{parent, Parent}]),
	float(Parent, Bundle).
	
float(Parent, Bundle) ->
	receive
		{From, {get, Attribute}} ->
			handle_get_attribute(Attribute, From, Bundle, Parent);
		{set, Attribute, Value} ->
			NBundle = handle_set_attribute(Attribute, Value, Bundle, Parent),
			float(Parent, NBundle);
		{From, {sqrt, Arg}} when is_list(Arg) ->
			Out = rpc(Parent, {sqrt, Arg}),
			From ! Out;
		{From, {sqrt, Arg}} when Arg < 0 ->
			Out = rpc(Parent, {sqrt, Arg}),
			From ! Out;  
		{From, {sqrt, Arg}} ->
			Out = math:sqrt(Arg),
			From ! Out; 
		Any ->
			Parent ! Any
	end,
	float(Parent, Bundle).
	
integer() ->
	Class_Name      = integer,
	Name            = book,
	Parent 	        = spawn_link(mathobjects, float, []),
	Parent_Class    = object,
	Bundle = dict:from_list( [
		{class_name, Class_Name},
		{parent_class, Parent_Class},
		{name, Name},
		{parent, Parent}]),
	integer(Parent, Bundle).
	
integer(Parent, Bundle) ->
	receive
		{From, {get, Attribute}} ->
			handle_get_attribute(Attribute, From, Bundle, Parent);
		{set, Attribute, Value} ->
			NBundle = handle_set_attribute(Attribute, Value, Bundle, Parent),
			integer(Parent, NBundle);
		{From, {sqrt, Arg}} when is_float(Arg) ->
			Out = rpc(Parent, {sqrt, Arg}),
			From ! Out;
		{From, {sqrt, Arg}} when is_list(Arg) ->
			Out = rpc(Parent, {sqrt, Arg}),
			From ! Out;
		{From, {sqrt, Arg}} when Arg < 0 ->
			Out = rpc(Parent, {sqrt, Arg}),
			From ! Out;
		{From, {sqrt, Arg}} ->
			Out = 
				try math:sqrt(Arg)  
					catch
						_AnyException ->
							rpc(Parent, {From, sqrt, Arg})
					end,
			From ! Out;
		Any ->
			Parent ! Any
	end,
	integer(Parent, Bundle).
	
% -----------------------------------------------
 	
handle_set_attribute(Attribute, Value, Bundle, Parent) ->	
			Found = dict:find(Attribute, Bundle),
			if 
				is_tuple(Found) ->     % if attribute exists then set it
					{ok, _} = Found,
					NBundle = dict:store(Attribute, Value, Bundle),
					NBundle;
				true ->
					Parent ! {set, Attribute, Value}
			end.
			
handle_get_attribute(Attribute, From, Bundle, Parent) ->	
			Found = dict:find(Attribute, Bundle),
			if 
				is_tuple(Found) ->
					{ok, Value} = Found,
					From ! {Attribute, Value};
				true ->
					Parent ! {From, {get, Attribute}}
			end.