Dynamic object methods are simply defined as closures. They must take the dynamic object object as
their first argument, and we suggest that you call it this
. You can then define as many parameters
as you want.
Here is an example where we define a toString
-style of method:
local function mrbean = -> DynamicObject(): name("Mr Bean"): email("mrbean@gmail.com"): define("toString", |this| -> this: name() + " <" + this: email() + ">") function main = |args| { let bean = mrbean() println(bean: toString()) bean: email("mrbean@outlook.com") println(bean: toString()) }
You cannot overload methods, that is, providing methods with the same name but different signatures.
It is strongly recommended that you use define
to create and update methods.
Consider the following example:
let obj = DynamicObject(): plop(|this| -> "Plop!")
Any call such as obj: plop()
properly calls plop()
. Because the dynamic object is fresh and new,
the first call to plop
creates a property since it is currently missing.
That being said, the following would fail:
obj: plop(|this| -> "Plop it up!")
Indeed, when the value of a dynamic object property is a function, it is understood to be a method,
hence calling plop
like it would be a setter method fails because there already exists a property
that is a function, and it has a different signature. It needs to be updated as in:
obj: define('plop', |this| -> "Plop it up!")
As a rule of thumb, prefer named setters for values and define
for methods. It is acceptable
to have named definitions for methods if and only if a call happens after the object creation and
before any call to mixin
(remember that it injects properties from other objects, including
methods).