Functor

About

Instances of this class (known as functors) have the same interface as 4D.Functionopen in new window. This allows you to create objects that act like 4D.Function but can have arbitrarily complex functionality and maintain state.

NOTE

Functors can be used interchangeably with code that uses .call() or .apply() on 4D.Function objects. However:

  • Functors cannot be passed to 4D commands or functions that expect a 4D.Function object.

  • Variables and parameters that expect either a functor or formula must be typed as Object rather than 4D.Function.

  • Formulas require that the first parameter passed to .call() or .apply() be an object. Functors allow you to pass any value as the first parameter.

API

constructor()

cs.js.Functor.new(implementation : Object)

Creates a new Functor. The Functor class itself does not perform any work; you must provide it with an implementation object (typically an instance of a class) that does the actual work.

See the Functor implementation API section for an example.


.apply()

.apply({ thisObj : any { ; params : Collection }}) : any

Executes the implementation, passing thisObj and the items in params as separate positional parameters. Within the implementation, This refers to the implementation object itself.


.call()

.call({ thisObj : any { ; …params : any }}) : any

Executes the implementation, passing thisObj and the given positional params. Within the implementation, This refers to the implementation object itself.


.description()

.description() : Text

By default this returns the name of the implementation class and its superclass. Define this in your implementation class if you want to return something more descriptive.

TIP

See the example below for a sample implementation.


.f()

.f({ …params : any }) : any

Executes the implementation function, passing null as thisObj along with the provided positional parameters.

NOTE

Because this function does not exist in 4D.Function, you cannot use it to call a functor in a way that is interchangeable with 4D.Function. If this is a concern, use the .apply() or .call() functions instead.


.source

.source : Text

This read-only property is present to provide compatibility with 4D.Functionopen in new window. It is not used by the Functor class.

Set this property (or define a getter function) in your implementation if you want to provide a description of the implementation’s contents.

TIP

See the example below for a sample implementation.

Implementation API

At a minimum, your functor implementation must implement the .implementation() function. You may optionally implement .description() and/or .source as well.

.implementation()

.implementation(thisObj : any { ; …params : any }) : any

This function provides the functionality for a functor. Within this function:

  • This refers to the implementation object itself.

  • thisObj is the first parameter passed to the functor’s .call() or .apply() function.

  • thisObj is null if the functor’s .f() function is called.

IMPORTANT

You must implement this function in the implementation object passed to the Functor constructor.

Example

Let’s say you want to create a functor that will perform a fixed operation on a passed-in collection. You could do this:

// CollectionOp class
Class constructor($op : Text; $propertyPath : Text)
  This.op:=$op
  This.propertyPath:=$propertyPath

Function implementation($thisObj : Variant) : Variant
  var $collection : Collection
  
  $collection:=Copy parameters(2)
  
  // Allow the user to pass in a collection as $thisObj
  If (Value type($thisObj)=Is collection)
    $collection:=$thisObj
  End if 
  
  If (This.propertyPath="")
    return $collection[This.op]()
  Else 
    return $collection[This.op](This.propertyPath)
  End if 

Function description() : Text
  return _.format(\
    "${1} functor\nOperation: ${2}\nProperty path: ${3}"; \
    OB Class(This).name; \
    This.op; \
    This.propertyPath || "<none>")

Function get source() : Text
  var $path : Text
  
  $path:=(This.propertyPath#"") ? _.format("\"${1}\""; This.propertyPath) : ""
  return _.format("Collection.${1}(${2})"; This.op; $path)
// Some other code
var $op : cs.js.Functor
var $value: Collection

$op:=cs.js.Functor.new(cs.CollectionOp.new("sum"))
// Next 2 lines are equivalent
$result:=$op.call(Null; 1; 2; 3)
$result:=$op.f(1; 2; 3)
// => 6

$op:=cs.js.Functor.new(cs.CollectionOp.new("average"))
$result:=$op.call(Null; 1; 2; 3)
// => 2

$object1:=New object("count"; 7)
$object2:=New object("count"; 13)

$op:=cs.js.Functor.new(cs.CollectionOp.new("average"; "count"))
$result:=$op.f($object1; $object2)
// => 10

// CollectionOp allows $thisObj to be the collection to operate on
$result:=$op.call(New collection($object1; $object2))
// => 10

$description:=$op.description()
// => "CollectionOp functor\nOperation: average\nProperty path: count"

$source:=$op.source
// => "Collection.average(\"count\")"
Last Updated:
Contributors: Aparajita