User Tools

Site Tools


at:tutorial:objects

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
at:tutorial:objects [2007/07/10 22:14] – changed tvcutsemat:tutorial:objects [2007/07/18 18:30] jorge
Line 94: Line 94:
   def z := 0;   def z := 0;
   def sumOfSquares() {   def sumOfSquares() {
-    super^sumOfSquares() + z*z+    super^sumOfSquares() + z*z;
   };   };
 } }
Line 159: Line 159:
 def Enumerable := object: { def Enumerable := object: {
   def collect: closure {   def collect: closure {
-    def c := clone: self;+    def c := self.new([]);
     self.each: { |v|     self.each: { |v|
-      c.add(closure(v))+      c.add(closure(v));
     };     };
 +    c;
   };   };
 }; };
 def Array := object: { def Array := object: {
   def elements := [];   def elements := [];
-  def init() { ... };+  def init(a) { elements := a; }; 
 +  def add(v) { elements := elements + [v]; self };
   def collect: closure {   def collect: closure {
     Enumerable^collect: closure;     Enumerable^collect: closure;
   };   };
   def each: clo {   def each: clo {
-    1.to: elements.length do: { |i| +    1.to: elements.length + 1 do: { |i| 
-      clo(elements[i])+      clo(elements[i]);
     };     };
   };   };
Line 181: Line 183:
 A message sent to an object using the ''^'' symbol (e.g. to the ''Enumerable'' object in the example above) will start the method lookup in this object and execute the method body with the ''self'' pseudovariable **left unchanged** to the message sender. In the code example above, when ''collect:'' is invoked on an ''Array'' object, the array object //delegates// the message to the ''Enumerable'' object. As such, method lookup starts in ''Enumerable'', finds the method there, and then invokes it with ''self'' left bound to the ''Array'' object. Hence, the ''self.each:'' send in the ''Enumerable'' object uses ''Array'''s definition of ''each:'' to generate the elements in the collection. A message sent to an object using the ''^'' symbol (e.g. to the ''Enumerable'' object in the example above) will start the method lookup in this object and execute the method body with the ''self'' pseudovariable **left unchanged** to the message sender. In the code example above, when ''collect:'' is invoked on an ''Array'' object, the array object //delegates// the message to the ''Enumerable'' object. As such, method lookup starts in ''Enumerable'', finds the method there, and then invokes it with ''self'' left bound to the ''Array'' object. Hence, the ''self.each:'' send in the ''Enumerable'' object uses ''Array'''s definition of ''each:'' to generate the elements in the collection.
  
-Of course, the example above is a bit contrived: we could have just assigned ''Enumerable'' as the parent of ''Array'' such that we would not even have to write the "delegating" ''collect:'' method in ''Array''. However, what the explicit ''^'' delegation operator allows is the expression of patterns resembling //multiple inheritance// where some requests are delegated to one object, while other methods can be delegated to other objects. Explicit delegation enables the expression of delegation patterns which would be awkward or difficult to express using only single (delegation-based) inheritance.+<code> 
 +> Array.add(1).add(2).add(3) 
 +>> <object:11698353> 
 +> def c := Array.collect: { |v| v+1 } 
 +>> <object:14179973> 
 +> c.each: { |v| system.print(v)} 
 +
 +
 +
 +>>nil 
 +</code> 
 + 
 +Of course, the example above is a bit contrived: we could have just assigned ''Enumerable'' as the parent of ''Array'' such that we would not even have to write the "delegating" ''collect:'' method in ''Array''. However, what the explicit ''^'' delegation operator allows is the expression of patterns resembling //multiple inheritance// where some requests are delegated to one object, while other methods can be delegated to other objects. Explicit delegation enables the expression of delegation patterns which would be awkward or difficult to express using only single (delegation-based) inheritance. In [[:at:tutorial:modular#objects_as_traits|a later chapter]], we will show how ''^'' forms the basis for advanced //trait composition//
 + 
 +Having described the semantics of ''^'', we can now turn our attention to "super-sends". In AmbientTalk, a traditional "super-send" (ala Java or Smalltalk) is expressed as explicit delegation to the ''super'' object. For example, here is how to properly initialize parent objects from child objects:
  
 <code> <code>
Line 192: Line 208:
 }; };
 </code> </code>
- 
  
 <note warning> <note warning>
-The delegation operator does not have the same semantics as the dot notationA message sent to ''super'' using the dot notation will not only start the method lookup in the object bound the ''super'' field but also bind the ''self'' pseudo variable to this object.+AmbientTalk, unlike many other OO languages (including Java and Smalltalk) does not treat ''super.m(foo)'' as a special constructBecause AmbientTalk regards ''super'' as a regular field name, and because it distinguishes invocation from delegation by means of ''.'' vs ''^'', super-sends can be expressed without any special additions as ''super^m(foo)''
 + 
 +Keep in mind, however, that ''super.m(foo)'' is //not// a "super-send" in the traditional sense of the word. Rather, it is a method invocation on ''super'', changing the value of ''self'' in ''m'' to refer to ''super''.
 </note> </note>
  
 ===== Encapsulation ===== ===== Encapsulation =====
-In AmbientTalk, all fields and methods are "public" via selectionStill, a field or method can be made "private" by means of lexical scoping. The following code shows the definition of an object inside the definition of a function. The fields and methods of this object cannot be accessed directly from outside the funuction.+ 
 +AmbientTalk has no notion of "visibility modifiers" for fields or methods. All fields and methods of an object are considered "public"Nevertheless, a field or method can be made "private" to a scope by means of lexical scoping (a technique sometimes referred to as [[http://www.erights.org/elib/capability/ode/ode-objects.html|lambda abstraction]]). The following code shows the definition of an object inside the definition of a function. Although all of the object'fields and methods are public, the object can make use of lexically visible fields and methods of outer objects or functions which are not simply accessible "from the outside":
  
 <code> <code>
-def makeObject(hidden) { +def makeBankAccount(balance) { 
-    object: { +  object: { 
-      def foo() { /* use hidden */ } +    def deposit(amnt) { 
-    }+      balance := balance + amnt; 
 +      "ok" 
 +    };
   }   }
 +}
 </code> </code>
  
-Due to the encapsulation of this object the following instruction fails:+Because the bank account object encapsulates its ''balance'' in its private, lexical scope, the following code fails:
  
 <code> <code>
-makeObject(5).hidden+makeBankAccount(100).balance
->>Lookup failure : selector hidden could not be found in +>>Lookup failure : selector balance could not be found in 
   <object:5068254>   <object:5068254>
 </code> </code>
at/tutorial/objects.txt · Last modified: 2013/05/17 20:23 by tvcutsem