A side effect occurs when scripting code in a function, event, or state transition alters the value of a module-level variable, leading to changes in the behavior of unrelated code which references the same module level variable.
If a scripting statement inside of a function, event, or state transition changes the global application state, that code has what is called a 'side effect'. See Scripting, State Transitions, User Defined Functions, Handling Events. This means that, despite whatever local purpose the code might have, it has also had a global effect. In many cases, this is intended. After all, the state of the application must change in order for the application to actually do something.
In other cases, side effects may be unintended or may have unintended consequences. This occurs most often in cases where evaluating a function in the context of a visual element has a side effect. See Visual Elements. In most cases you will not want a visual element to change the application state when it is displayed, yet if the function has a side effect this will be the case. For example, if two visual elements are displayed at the same time, and both use the same function, then each visual element will evaluate the function according to their z-order; with the first visual element getting a different function result than the second.
Deliberate use of side effects may result in 'spaghetti-code' logic where different, seemingly unrelated, parts of your code affect each other. When things do not work as expected, it may be difficult to track down the problem because the code paths are complex and difficult to understand.
Accidental side effects can result in subtle errors which are difficult to find. Often they occur two or three levels deep; for example, a visual element which evaluates a function which calls another function which changes a state variable, which activates a state transition, which contains an event, which then fires and changes the application state. This kind of non-obvious chain of execution often results in intermittent problems which are extremely difficult to reproduce and debug.
One of the best ways to reduce the consequences of side effects is to avoid evaluating functions in a visual element which changes state. In fact, it is a good idea to only change state in functions which have no return value. It also helps to keep the number of global variables to a minimum, thus reducing the number of factors that can change as a side effect.
Modularizing your code into well-designed state machines also keeps side effects isolated to that state machine, instead of global to the application. See State Machines.
The following example shows how to use nested templates to display a counter value multiple times across the device screen, twice for each state transition. It uses a function with side effects to update variable values during template expansion. It is part of the transition4.ujml sample.
<ujml>
<application>
<state-variables>
<state-var name="sShow" type="boolean" size="6"/>
</state-variables>
<variables>
<var name="mCtr" type="int"/>
<var name="mOffset" type="int"/>
</variables>
<functions>
<!--
Updates variables with side effects.
-->
<function name="sideEffects" type="int">
<script>
// Increment counter.
mCtr++;
// Toggle offset;
if (mOffset == 20)
{
mOffset = 0;
}
else
{
mOffset = 20;
}
</script>
<return><eval>mOffset</eval></return>
</function>
</functions>
<templates>
<template name="tLabel">
<display>
<label>
<text><eval>mCtr</eval></text>
<x><eval>sideEffects() + 2</eval></x>
<y>2</y>
<fg>&_COLOR_YELLOW;</fg>
</label>
</display>
</template>
<template name="tBox">
<display>
<box>
<x><eval>mCtr * 10</eval></x>
<y><eval>mCtr * 12</eval></y>
<width>40</width>
<height>20</height>
<fg>&_COLOR_BLACK;</fg>
<bg>&_COLOR_BLACK;</bg>
<expand template="tLabel"/>
<expand template="tLabel"/>
</box>
</display>
</template>
</templates>
<script>
mOffset = 20;
sShow[0] = true;
</script>
<states>
<!-- Show counts with animation. -->
<state var="sShow" index="*">
<transition value="true">
<display>
<expand template="tBox"/>
</display>
<delay>300</delay>
<script>
if (_state_index(0) &_LT; 5)
{
sShow[_state_index(0) + 1] = true;
}
</script>
</transition>
</state>
</states>
</application>
</ujml>|
Copyright (c) 2000-2007 UIEvolution, Inc. All rights reserved.
|
|
What do you think about this topic? Send feedback!
|