Results 1 to 4 of 4

Thread: What's a Functor, and where can I get one?

  1. #1

    What's a Functor, and where can I get one?

    Someone mind explaining what a Functor is to me. And when and where I would want to use one?
    My DGDev forum pascal syntax highlight settings:
    <br />[background=#FFFFFF][comment=#8080FF][normal=#000080]
    <br />[number=#C00000][reserved=#000000][string=#00C000]

  2. #2
    Legendary Member cairnswm's Avatar
    Join Date
    Nov 2002
    Location
    Randburg, South Africa
    Posts
    1,537

    What's a Functor, and where can I get one?

    I searched the net and found:

    A functor is a function that can be manipulated as an object.

    In Java, functors are typically implemented as interfaces defined by a single, generic member function, and that is the approach taken here.

    Functors support and encourage a number of powerful programming techniques including:

    programming in a functional style
    higher order functions
    internal iterators
    reuse and specialization through composition rather than inheritance and overloading
    generic "callback" or "extension point" APIs
    generic "filters" or predicate APIs
    many "behavioral" design patterns, such as Visitor, Strategy, Chain of Responsibility, etc.
    So effectivly its an Object that takes parameters.....

    I suppose in Delphi this would be supported by


    Code:
    Function MyFunctor&#40;Parm1 &#58; Type1&#41; &#58; TMyFunctorObject;
    Begin
       MyObj &#58;= TMyFunctorObject.Create;
      Result &#58;= MyObj;
    End;
    
    ....
    With MyFunctor&#40;Var1&#41; do
      Begin
        DoStuff;
      End;
    William Cairns
    My Games: http://www.cairnsgames.co.za (Currently very inactive)
    MyOnline Games: http://TheGameDeveloper.co.za (Currently very inactive)

  3. #3

    What's a Functor, and where can I get one?

    I believe that a functor is a concept to create a class that can behave primarily as a "function" - usually, in C++, that would be overloading the () operator to provide function-like semantics for a class (possibly as a base class). C++ does feel a little dirty in this respect, though, because it doesn't provide proper interfaces.

    As far as I can tell (and I may be wrong here since I've not really bothered looking into functors yet), functors are best used to pass in as parameters to functions, to provide different behaviours. Here's a Delphi example, although I may have missed the point (not sure):

    Code:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, ExtCtrls;
    
    type
      IBinaryFunc = interface
      &#91;'&#123;11231180-585E-11D7-B787-00D0B7BBC908&#125;'&#93;
        function DoIt&#40;X,Y&#58; Integer&#41;&#58; Integer;
      end;
    
      TBinaryAdd = class&#40;TInterfacedObject, IBinaryFunc&#41;
      public
        function DoIt&#40;X, Y&#58; Integer&#41;&#58; Integer;
      end;
    
      TBinarySub = class&#40;TInterfacedObject, IBinaryFunc&#41;
      public
        function DoIt&#40;X, Y&#58; Integer&#41;&#58; Integer;
      end;
    
      TBinaryMultiply = class&#40;TInterfacedObject, IBinaryFunc&#41;
      public
        function DoIt&#40;X, Y&#58; Integer&#41;&#58; Integer;
      end;
    
      TBinaryDivide = class&#40;TInterfacedObject, IBinaryFunc&#41;
      public
        function DoIt&#40;X, Y&#58; Integer&#41;&#58; Integer;
      end;
    
      TForm1 = class&#40;TForm&#41;
        Button1&#58; TButton;
        rgpWhatever&#58; TRadioGroup;
        procedure Button1Click&#40;Sender&#58; TObject&#41;;
      private
        &#123; Private declarations &#125;
      public
        &#123; Public declarations &#125;
      end;
    
    var
      Form1&#58; TForm1;
    
    implementation
    
    &#123;$R *.DFM&#125;
    
    function TBinaryAdd.DoIt&#40;X, Y&#58; Integer&#41;&#58; Integer;
    begin
      Result &#58;= X + Y;
    end;
    
    function TBinarySub.DoIt&#40;X, Y&#58; Integer&#41;&#58; Integer;
    begin
      Result &#58;= X - Y;
    end;
    
    function TBinaryMultiply.DoIt&#40;X, Y&#58; Integer&#41;&#58; Integer;
    begin
      Result &#58;= X * Y;
    end;
    
    function TBinaryDivide.DoIt&#40;X, Y&#58; Integer&#41;&#58; Integer;
    begin
      Result &#58;= X div Y;
    end;
    
    function DoStuff&#40;Num1, Num2&#58; Integer; Operation&#58; IBinaryFunc&#41;&#58; Integer;
    begin
      Result &#58;= Operation.DoIt&#40;Num1, Num2&#41;;
    end;
    
    procedure TForm1.Button1Click&#40;Sender&#58; TObject&#41;;
    begin
      case rgpWhatever.ItemIndex of
        -1&#58; ;
         0&#58; ShowMessage&#40;IntToStr&#40;DoStuff&#40;3, 6, TBinaryAdd.Create&#41;&#41;&#41;;
         1&#58; ShowMessage&#40;IntToStr&#40;DoStuff&#40;13, 4, TBinarySub.Create&#41;&#41;&#41;;
         2&#58; ShowMessage&#40;IntToStr&#40;DoStuff&#40;3, 5, TBinaryMultiply.Create&#41;&#41;&#41;;
         3&#58; ShowMessage&#40;IntToStr&#40;DoStuff&#40;12, 4, TBinaryDivide.Create&#41;&#41;&#41;;
      end;
    end;
    
    end.
    Notice how the behaviour of the function "DoStuff" depends entirely on what function is passed in - you're changing its behaviour in any way you see fit . Also, the functors are derived from TInterfacedObject so they'll be squished automatically when they go out of scope.

    The advantage of using classes as "functions" is that they can retain state if required, which gives them more capabilities than just function pointers.

    You could probably take this further - one rocking feature of Delphi is class references ("class of") - for example, TClass. There should be a way to use them (passing in the type of the functor instead of using a case statement on it), though it escapes me at the moment.

    Class references are lovely. :cyclops:

    [P.S. BlueCat, the pascal forum tag seems to screw up with the above code - it seems to be the interface guid line that's the cause]
    "All paid jobs absorb and degrade the mind."
    <br />-- Aristotle

  4. #4

    What's a Functor, and where can I get one?

    Quote Originally Posted by Alimonster
    You could probably take this further - one rocking feature of Delphi is class references ("class of") - for example, TClass. There should be a way to use them (passing in the type of the functor instead of using a case statement on it), though it escapes me at the moment.
    Code:
    type
      TBinaryFunc = interface&#40;TInterfacedObject, IBinaryFunc&#41; 
        Constructor create; virtual;   
        function DoIt&#40;X,Y&#58; Integer&#41;&#58; Integer; virtual; abstract;
      end; 
      TBinaryFuncClass = class of TBinaryFunc;
    .... 
    function DoStuff&#40;Num1, Num2&#58; Integer; OperationClass&#58; IBinaryFuncClass&#41;&#58; Integer; 
    begin 
      Result &#58;= IBinaryFunc&#40;OperationClass.Create&#41;.DoIt&#40;Num1, Num2&#41;; 
    end; 
    
    procedure TForm1.Button1Click&#40;Sender&#58; TObject&#41;; 
    begin 
      case rgpWhatever.ItemIndex of 
        -1&#58; ; 
         0&#58; ShowMessage&#40;IntToStr&#40;DoStuff&#40;3, 6, TBinaryAdd&#41;&#41;&#41;; 
         1&#58; ShowMessage&#40;IntToStr&#40;DoStuff&#40;13, 4, TBinarySub&#41;&#41;&#41;; 
         2&#58; ShowMessage&#40;IntToStr&#40;DoStuff&#40;3, 5, TBinaryMultiply&#41;&#41;&#41;; 
         3&#58; ShowMessage&#40;IntToStr&#40;DoStuff&#40;12, 4, TBinaryDivide&#41;&#41;&#41;; 
      end; 
    end;
    You need the costructor to be virtual, so when you use a class reference it will resolve to the correct constructor.

    You can get away with "IBinaryFunc(OperationClass.Create).DoIt" because of 2 reasons:
    1) if an exception occurs, the constructor fails and the detsructor is called. Thus the Constructor always returns a valid value, or it raises an exception.
    2) IBinaryFunc(OperationClass.Create) makes sure the returned class is treaded as an interface. This will cause the referance count to equal one while DoIt is executing, but as soon as the statement finishes, the reference count is decreased, and the interface freed. You might be able to remove the cast, but I havent compiled that to check to see if that would work.

    Also you can have virtual class functions too.
    Code:
    type
      TBinaryFunc = interface&#40;TInterfacedObject, IBinaryFunc&#41; 
        Constructor create; virtual;
        class function DoIt&#40;X,Y&#58; Integer&#41;&#58; Integer; virtual; abstract;
      end;
    Then something like "OperationClass.Doit" is valid and will call the correct function.

    This is useful in a system when you have a list of class types which you create a new instance of each time you use the class type, but need extra information from each class type but dont want to have to create a new class to contain this information (which is static).

    Tobject.ClassName is an example of this.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •