How does a dynamic function take a class property as a starting value without changing the property?
← Advanced Type System · Ref: Q2131
Capture a COPY made with the type's copy constructor: '(left: Integer(limit))'. The capture list is evaluated in the method that creates the dynamic function, where the class's private properties are visible, and 'Integer(limit)' makes a new Integer there - the dynamic function owns it, so 'left--' moves only its own working value and 'limit' stays where it was. The copy is made once, when the dynamic function is created; a second call of the method starts a fresh one from the property as it is then. Capturing the property itself, '(left: limit)', would SHARE the object and every 'left--' would move 'limit' too (Q2130). CHOOSE A COPY (this example) when the dynamic construct needs an initial value it then works on - a countdown, a cursor, a retry budget. CHOOSE SHARED when the dynamic construct exists to update the object - a callback recording into the object's tally. A built-in copies at its own level (a List copy is a new container holding the same elements); for your own type, its copy constructor or 'operator :=:' decides how deep the copy goes.
Example
defines module qa.advancedtypes.captureinitialvalue defines function Remaining() as abstract <- rtn as Integer? defines class Retries limit as Integer: 3 //AN INITIAL VALUE: the countdown starts from the limit and owns its own copy. countdown() <- rtn as Remaining: (left: Integer(limit)) is Remaining as function left-- rtn: Integer(left) currentLimit() <- rtn as Integer: Integer(limit) default operator ? defines program CaptureInitialValue() stdout <- Stdout() retries <- Retries() remaining <- retries.countdown() stdout.println(`limit before: ${retries.currentLimit()}`) stdout.println(`remaining: ${remaining()}`) stdout.println(`remaining: ${remaining()}`) stdout.println(`remaining: ${remaining()}`) stdout.println(`limit after: ${retries.currentLimit()}`) fresh <- retries.countdown() stdout.println(`fresh countdown: ${fresh()}`)
Other ways to ask this
- How do I capture a copy of a property into a dynamic function in EK9?
- Why does my closure change the class's field, and how do I stop it?
- What is '(left: Integer(limit))' in a capture list?
- How do I give a closure its own working value from a field?
Coming from another language?
Java: a lambda reads 'this.limit' live, so a snapshot is a local 'int start = limit;' taken before the lambda and copied into an int[] or AtomicInteger to be changed. Kotlin/JavaScript: copy into a local 'var' before the closure. EK9: the copy is written in the capture list itself, so the creation site states which fields are shared and which are starting values.
Keywords: copy constructor, private property, snapshot, initial value, capture, capture list, dynamic function, closure