As per my knowledge, every example you made "suffers" the side-effects.
In order to eliminate a side-effect, one must only call a function passing all values as parameters, and get the function results. No global variable should be used.
For example, this is the wrong approach ("counter" introduces the side-effects):
Code: Select all
(setq counter 0)
(define (myFunc)
(dotimes (i 3)
(inc counter)
(println "VALUE [" i "]: " counter) ) )
(myFunc)
This is the correct approach (no side-effect):
Code: Select all
(define (myFunc)
(setq counter 0)
(dotimes (i 3)
(inc counter)
(println "VALUE [" i "]: " counter) ) )
(myFunc)
As you can see, in order to eliminate the side-effects, one must eliminate every reference, inside functions, to external variables (global variables).
This approach is very useful in order to avoid that, another function (XYZ) may change the value of the global variable, by introducing unexpected results (and a big BUG!) inside (myFunc).
In fact, if one function uses global variables (or variables external to the function self), this case may happen:
Code: Select all
(setq counter 0)
(define (anotherFunc)
(dec counter 5) )
(define (myFunc)
(dotimes (i 3)
(inc counter)
(anotherFunc)
(println "VALUE [" i "]: " counter) ) )
(myFunc)
As you can see, (myFunc) makes a job, but there is the function (anotherFunc) that modify the value of counter, so I introduced a bug (difficult to discover in a complex application), and I get unexpected results.
Another correct approach for this problem could be the following code:
Code: Select all
(define (myFunc myI myCounter)
(inc myCounter)
(println "VALUE [" myI "]: " myCounter)
myCounter)
(setq counter 0)
(dotimes (i 3)
(setq counter (myFunc i counter)) )
(myFunc)
As you can see, the function (myFunc) never works on "counter" directly, but over a controlled copy.
The concept is: a function must get some values, can create local (controlled) variables, then it will return the results. A function should never work on variables external to its scoping.