Functor
About
Instances of this class (known as functors) have the same interface as 4D.Function
. 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 than4D.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.Function
. 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\")"