Delegates: Difference between revisions

From Rosetta Code
Content added Content deleted
(Add C)
(→‎{{header|Oz}}: simplified; made more idiomatic)
Line 411: Line 411:
=={{header|Oz}}==
=={{header|Oz}}==
{{trans|Python}}
{{trans|Python}}
<lang oz>functor
<lang oz>declare
class Delegator from BaseObject
import
attr
Open Application Module
delegate:unit
define
Stdout = {New Open.file init(name:stdout)}


meth set(DG)
%% modify from http://osdir.com/ml/lang.mozart.user/2007-04/msg00042.html
{Object.is DG} = true %% assert: DG must be an object
%% not known if this is a right way ...
delegate := DG
fun{IsMethod Klax Meth NArg}
B = {NewCell false}
end
in
if {IsObject Klax} then
[BootObj BootName] = {Module.link ['x-oz://boot/Object' 'x-oz://boot/Name']}
MethList = {BootObj.getClass Klax}.{BootName.newUnique 'ooMeth'}
MethName = {Dictionary.keys MethList}
in
{For 1 {Length MethName} 1
proc{$ Idx}
if {Value.type MethName.Idx} == 'tuple' andthen
MethName.Idx.1 == Meth andthen
{Value.type {Dictionary.get MethList MethName.Idx.1}} == 'procedure' andthen
{ProcedureArity {Dictionary.get MethList MethName.Idx.1}} == NArg
then
B := true
end
end
}
end
@B
end


meth operation($)
%% translate from Python version
if @delegate == unit then
class Delegator
{self default($)}
attr delegate
else
meth operation(?R)
try
if {IsMethod @delegate 'thing' 1} then
{@delegate thing(R)}
{@delegate thing($)}
catch error(object(lookup ...) ...) then
else
%% the delegate did not understand the message
R = 'default implementation'
end
{self default($)}
end
end
end
meth init
end
delegate := {New BaseObject noop}
end
meth set(DG)
delegate := DG
end
end


meth default($)
"default implementation"
end
end
class Delegate from BaseObject
class Delegate from BaseObject
meth thing(?R)
meth thing($)
R = 'Delegate Implementation'
"delegate Implementation"
end
end
end
end
A = {New Delegator noop}
in
{System.showInfo {A operation($)}}


A = {New Delegator init}
{A set({New BaseObject noop})}
{Stdout write(vs:{A operation($)}#'\n')}
{System.showInfo {A operation($)}}
{A set('A delegate may be any object')}
{Stdout write(vs:{A operation($)}#'\n')}
{A set({New Delegate noop})}
{Stdout write(vs:{A operation($)}#'\n')}


{A set({New Delegate noop})}
{Application.exit 0}
{System.showInfo {A operation($)}}</lang>
end</lang>


=={{header|Perl}}==
=={{header|Perl}}==

Revision as of 03:02, 4 January 2010

Task
Delegates
You are encouraged to solve this task according to the task description, using any language you may know.

A delegate is a helper object used by another object. The delegator may send the delegate certain messages, and provide a default implementation when there is no delegate or the delegate does not respond to a message. This pattern is heavily used in Cocoa framework on Mac OS X. See also wp:Delegation pattern.

Objects responsibilities:

Delegator:

  • Keep an optional delegate instance.
  • Implement "operation" method, returning the delegate "thing" if the delegate respond to "thing", or the string "default implementation".

Delegate:

  • Implement "thing" and return the string "delegate implementation"

Show how objects are created and used. First, without a delegate, then with a delegate that does not implement "thing", and last with a delegate that implements "thing".

Ada

All that is needed in order to implement this is a common base type. The delegator holds a pointer to an "untyped" object from the base class. Querying if the target implements the delegate interface is done using run-time type identification. <lang ada>with Ada.Text_IO; use Ada.Text_IO;

procedure Delegation is

  package Things is
     -- We need a common root for our stuff
     type Object is tagged null record;
     type Object_Ptr is access all Object'Class;
     
     -- Objects that have operation thing
     type Substantial is new Object with null record;
     function Thing (X : Substantial) return String;
     
     -- Delegator objects
     type Delegator is new Object with record
        Delegate : Object_Ptr;
     end record;
     function Operation (X : Delegator) return String;
     
     No_Thing  : aliased Object;      -- Does not have thing
     Has_Thing : aliased Substantial; -- Has one
  end Things;
     
  package body Things is
     function Thing (X : Substantial) return String is
     begin
        return "delegate implementation";
     end Thing;
  
     function Operation (X : Delegator) return String is
     begin
        if X.Delegate /= null and then X.Delegate.all in Substantial'Class then
           return Thing (Substantial'Class (X.Delegate.all));
        else
           return "default implementation";
        end if;
     end Operation;
  end Things;
  use Things;
  A : Delegator; -- Without a delegate

begin

  Put_Line (A.Operation);
  A.Delegate := No_Thing'Access; -- Set no thing
  Put_Line (A.Operation);
  A.Delegate := Has_Thing'Access; -- Set a thing
  Put_Line (A.Operation);

end Delegation;</lang> Sample output:

default implementation
default implementation
delegate implementation

C

As best you can do, without support for classes. <lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>

typedef char * (*Responder)( int p1);

typedef struct sDelegate {

   Responder operation;

} *Delegate;

/* Delegate class constructor */ Delegate NewDelegate( Responder rspndr ) {

   Delegate dl = (Delegate)malloc(sizeof(struct sDelegate));
   dl->operation = rspndr;
   return dl;

}

/* Thing method of Delegate */ char *DelegateThing(Delegate dl, int p1) {

   return  (dl->operation)? (*dl->operation)(p1) : NULL;

}

/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ typedef struct sDelegator {

   int     param;
   char    *phrase;
   Delegate delegate;

} *Delegator;

char * defaultResponse( int p1) {

   return "default implementation";

}

static struct sDelegate defaultDel = { &defaultResponse };

/* Delegator class constructor */ Delegator NewDelegator( int p, char *phrase) {

   Delegator d  = (Delegator)malloc(sizeof(struct sDelegator));
   d->param = p;
   d->phrase = phrase;
   d->delegate = &defaultDel;	/* default delegate */
   return d;

}

/* Operation method of Delegator */ char *Delegator_Operation( Delegator theDelegator, int p1, Delegate delroy) {

   char *rtn;
   if (delroy) {
       rtn = DelegateThing(delroy, p1);
       if (!rtn) {			/* delegate didn't handle 'thing' */
           rtn = DelegateThing(theDelegator->delegate, p1);
       }
   }
   else 		/* no delegate */
       rtn = DelegateThing(theDelegator->delegate, p1);
   printf("%s\n", theDelegator->phrase );
   return rtn;

}

/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ char *thing1( int p1) {

   printf("We're in thing1 with value %d\n" , p1);
   return "delegate implementation";

}

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

   Delegate del1 = NewDelegate(&thing1);
   Delegate del2 = NewDelegate(NULL);
   Delegator theDelegator = NewDelegator( 14, "A stellar vista, Baby.");
   printf("Delegator returns %s\n\n", 
           Delegator_Operation( theDelegator, 3, NULL));
   printf("Delegator returns %s\n\n", 
           Delegator_Operation( theDelegator, 3, del1));
   printf("Delegator returns %s\n\n",
           Delegator_Operation( theDelegator, 3, del2));
   return 0;

}</lang>

Common Lisp

Translation of: Python

In CLOS, methods exist apart from classes, and are specialized based on the types of their arguments. This example defines two classes (delegator and delegate), and a thing generic method which is specialized in three ways: (1) for 'any' argument, providing a default method; (2) for delegators, where thing is recursively applied to the delegator's delegate (if there is one); and (3) for delegates.

<lang lisp>(defgeneric thing (object)

 (:documentation "Thing the object."))

(defmethod thing (object)

 "default implementation")

(defclass delegator ()

 ((delegate
   :initarg :delegate
   :reader delegator-delegate)))

(defmethod thing ((delegator delegator))

 "If delegator has a delegate, invoke thing on the delegate,

otherwise return \"no delegate\"."

 (if (slot-boundp delegator 'delegate)
   (thing (delegator-delegate delegator))
   "no delegate"))

(defclass delegate () ())

(defmethod thing ((delegate delegate))

 "delegate implementation")

(let ((d1 (make-instance 'delegator))

     (d2 (make-instance 'delegator :delegate nil))
     (d3 (make-instance 'delegator :delegate (make-instance 'delegate))))
 (assert (string= "no delegate" (thing d1)))
 (assert (string= "default implementation" (thing d2)))
 (assert (string= "delegate implementation" (thing d3))))</lang>

D

D has built-in delegates, so we can skip createing additional Delegate object and pass real delegate directly to Delegator.

This example uses tango for output.

<lang D>import tango.io.Stdout;

class Delegator {

   private char[] delegate() hasDelegate;

public:

   char[] operation() {
       if (hasDelegate is null)
           return "default implementation";
       return hasDelegate();
   }
   typeof(this) setDg(char[] delegate() dg)
   {
       hasDelegate = dg;
       return this;
   }

}

int main(char[][] args) {

   auto dr = new Delegator();
   auto thing = delegate char[]() { return "delegate implementation"; };
   Stdout ( dr.operation ).newline;
   Stdout ( dr.operation ).newline;
   Stdout ( dr.setDg(thing).operation ).newline;
   return 0;

}</lang>

E

<lang e>def makeDelegator {

   /** construct without an explicit delegate */
   to run() {
       return makeDelegator(null)
   }
   /** construct with a delegate */
   to run(delegateO) { # suffix because "delegate" is a reserved keyword
       def delegator {
           to operation() {
               return if (delegateO.__respondsTo("thing", 0)) {
                          delegateO.thing()
                      } else {
                          "default implementation"
                      }
           }
       }
       return delegator
   }

}

? def delegator := makeDelegator() > delegator.operation()

  1. value: "default implementation"

? def delegator := makeDelegator(def doesNotImplement {}) > delegator.operation()

  1. value: "default implementation"

? def delegator := makeDelegator(def doesImplement { > to thing() { return "delegate implementation" } > }) > delegator.operation()

  1. value: "default implementation"</lang>

Java

This implementation uses an interface called Thingable to specify the type of delegates that respond to thing(). The downside is that any delegate you want to use has to explicitly declare to implement the interface. The upside is that the type system guarantees that whent the delegate is non-null, it must implement the "thing" method.

<lang java>interface Thingable {

   String thing();

}

class Delegator {

   public Thingable delegate;
   public String operation() {
       if (delegate == null)
           return "default implementation";
       else
           return delegate.thing();
   }

}

class Delegate implements Thingable {

   public String thing() {
       return "delegate implementation";
   }

}

// Example usage // Memory management ignored for simplification public class DelegateExample {

   public static void main(String[] args) {
       // Without a delegate:
       Delegator a = new Delegator();
       assert a.operation().equals("default implementation");
       // With a delegate:
       Delegate d = new Delegate();
       a.delegate = d;
       assert a.operation().equals("delegate implementation");
       // Same as the above, but with an anonymous class:
       a.delegate = new Thingable() {
               public String thing() {
                   return "anonymous delegate implementation";
               }
           };
       assert a.operation().equals("anonymous delegate implementation");
   }

}</lang>

JavaScript

Translation of: Python

<lang javascript>function Delegator() {

 this.delegate = null ;
 this.operation = function(){
   if(this.delegate && typeof(this.delegate.thing) == 'function')
     return this.delegate.thing() ;
   return 'default implementation' ;
 }

}

function Delegate() {

 this.thing = function(){
   return 'Delegate Implementation' ;
 }

}

function testDelegator(){

 var a = new Delegator() ;
 document.write(a.operation() + "\n") ;
 
 a.delegate = 'A delegate may be any object' ; 
 document.write(a.operation() + "\n") ;
 
 a.delegate = new Delegate() ;
 document.write(a.operation() + "\n") ;

}</lang>

Objective-C

Works with: Cocoa
Works with: GNUstep

<lang objc>#import <Cocoa/Cocoa.h>

@interface Delegator : NSObject {

   id delegate;

} - (id)delegate; - (void)setDelegate:(id)obj; - (NSString *)operation; @end

@implementation Delegator - (id)delegate; {

   return delegate;

} - (void)setDelegate:(id)obj; {

   delegate = obj; // Weak reference

} - (NSString *)operation; {

   if ([delegate respondsToSelector:@selector(thing)])
       return [delegate thing];
   return @"default implementation";

} @end

// Any object may implement these @interface NSObject (DelegatorDelegating) - (NSString *)thing; @end

@interface Delegate : NSObject // Don't need to declare -thing because any NSObject has this method @end

@implementation Delegate - (NSString *)thing; {

   return @"delegate implementation";

} @end

// Example usage // Memory management ignored for simplification int main() {

   // Without a delegate:
   Delegator *a = [[Delegator alloc] init];
   NSLog(@"%d\n", [[a operation] isEqualToString:@"default implementation"]);
   // With a delegate that does not implement thing:
   [a setDelegate:@"A delegate may be any object"];
   NSLog(@"%d\n", [[a operation] isEqualToString:@"delegate implementation"]);
   // With a delegate that implements "thing":
   Delegate *d = [[Delegate alloc] init];
   [a setDelegate:d];
   NSLog(@"%d\n", [[a operation] isEqualToString:@"delegate implementation"]);
   return 0;

}</lang>

Oz

Translation of: Python

<lang oz>declare

 class Delegator from BaseObject
    attr

delegate:unit

    meth set(DG)

{Object.is DG} = true %% assert: DG must be an object delegate := DG

    end
    meth operation($)

if @delegate == unit then {self default($)} else try {@delegate thing($)} catch error(object(lookup ...) ...) then  %% the delegate did not understand the message {self default($)} end end

    end
    meth default($)

"default implementation"

    end
 end

 class Delegate from BaseObject
    meth thing($)

"delegate Implementation"

    end
 end

 A = {New Delegator noop}  

in

 {System.showInfo {A operation($)}}
 {A set({New BaseObject noop})}
 {System.showInfo {A operation($)}}
 {A set({New Delegate noop})}  
 {System.showInfo {A operation($)}}</lang>

Perl

Translation of: Python

<lang perl>use strict;

package Delegator; sub new {

  bless {}

} sub operation {

  my ($self) = @_;
  if (defined $self->{delegate} && $self->{delegate}->can('thing')) {
     $self->{delegate}->thing;
  } else {
     'default implementation';
  }

} 1;

package Delegate; sub new {

  bless {};

} sub thing {

  'delegate implementation'

} 1;

package main;

  1. No delegate

my $a = Delegator->new; $a->operation eq 'default implementation' or die;

  1. With a delegate that does not implement "thing"

$a->{delegate} = 'A delegate may be any object'; $a->operation eq 'default implementation' or die;

  1. With delegate that implements "thing"

$a->{delegate} = Delegate->new; $a->operation eq 'delegate implementation' or die;</lang>

PHP

Translation of: Python

<lang php>class Delegator {

 function __construct() {
   $this->delegate = NULL ;
 }
 function operation() {
   if(method_exists($this->delegate, "thing"))
     return $this->delegate->thing() ;
   return 'default implementation' ;
 }

}

class Delegate {

 function thing() {
   return 'Delegate Implementation' ;
 }

}

$a = new Delegator() ; print "{$a->operation()}\n" ;

$a->delegate = 'A delegate may be any object' ; print "{$a->operation()}\n" ;

$a->delegate = new Delegate() ; print "{$a->operation()}\n" ;</lang>

Pop11

<lang pop11>uses objectclass; define :class Delegator;

   slot delegate = false;

enddefine;

define :class Delegate; enddefine;

define :method thing(x : Delegate);

  'delegate implementation'

enddefine;

define :method operation(x : Delegator); if delegate(x) and fail_safe(delegate(x), thing) then

  ;;; Return value is on the stack

else

  'default implementation'

endif; enddefine;

Default, without a delegate

lvars a = newDelegator(); operation(a) =>

a delegating to itself (works because Delegator does not
implement thing)

a -> delegate(a); operation(a) =>

delegating to a freshly created Delegate

newDelegate() -> delegate(a); operation(a) =></lang>

Python

<lang python>class Delegator:

  def __init__(self):
     self.delegate = None
  def operation(self):
      if hasattr(self.delegate, 'thing') and callable(self.delegate.thing):
         return self.delegate.thing()
      return 'default implementation'

class Delegate:

  def thing(self):
     return 'delegate implementation'

if __name__ == '__main__':

  # No delegate
  a = Delegator()
  assert a.operation() == 'default implementation'
  # With a delegate that does not implement "thing"
  a.delegate = 'A delegate may be any object'
  assert a.operation() == 'default implementation'
  # With delegate that implements "thing"
  a.delegate = Delegate()
  assert a.operation() == 'delegate implementation'</lang>

Ruby

Translation of: Python

<lang ruby>class Delegator

  attr_accessor :delegate
  def operation
     if @delegate.respond_to?(:thing)
        @delegate.thing
     else
        'default implementation'
     end
  end

end

class Delegate

  def thing
     'delegate implementation'
  end

end

if __FILE__ == $PROGRAM_NAME

  # No delegate
  a = Delegator.new
  puts a.operation # prints "default implementation"
  # With a delegate that does not implement "thing"
  a.delegate = 'A delegate may be any object'
  puts a.operation # prints "default implementation"
  # With delegate that implements "thing"
  a.delegate = Delegate.new
  puts a.operation # prints "delegate implementation"

end</lang>

Tcl

Works with: Tcl version 8.6
Works with: Tcl version 8.5

and the TclOO package

Uses Assertions#Tcl <lang tcl>package require Tcl 8.6

oo::class create Delegate {

   method thing {} {
       return "delegate impl."
   }
   export thing

}

oo::class create Delegator {

   variable delegate
   constructor args {
       my delegate {*}$args
   }
   
   method delegate args {
       if {[llength $args] == 0} {
           if {[info exists delegate]} {
               return $delegate
           }
       } elseif {[llength $args] == 1} {
           set delegate [lindex $args 0]
       } else {
           return -code error "wrong # args: should be \"[self] delegate ?target?\""
       }
   }
   
   method operation {} {
       try {
           set result [$delegate thing]
       } on error e {
           set result "default implementation"
       }
       return $result
   }

}

  1. to instantiate a named object, use: class create objname; objname aMethod
  2. to have the class name the object: set obj [class new]; $obj aMethod

Delegator create a set b [Delegator new "not a delegate object"] set c [Delegator new [Delegate new]]

assert {[a operation] eq "default implementation"}  ;# a "named" object, hence "a ..." assert {[$b operation] eq "default implementation"}  ;# an "anonymous" object, hence "$b ..." assert {[$c operation] ne "default implementation"}

  1. now, set a delegate for object a

a delegate [$c delegate] assert {[a operation] ne "default implementation"}

puts "all assertions passed"</lang>

To code the operation method without relying on catching an exception, but strictly by using introspection: <lang tcl>method operation {} {

   if { [info exists delegate] &&
        [info object isa object $delegate] &&
        "thing" in [info object methods $delegate -all]
   } then {
       set result [$delegate thing]
   } else {
       set result "default implementation"
   }

}</lang>

Vorpal

Delegate objects can be an array of delegates or as a single delegate. <lang vorpal>a = new() a.f = method(){

       .x.print()

}

c = new() c.g = method(){

       (.x + 1).print()

}

  1. array of delegates

b = new() b.delegate = new() b.delegate[0] = a b.delegate[1] = c b.x = 3 b.f() b.g()

  1. single delegate

d = new() d.delegate = a d.x = 7 d.f()</lang>

The resulting output:

3
4
7