![]() UJML Language Reference |
A state machine consolidates related variables, functions, state transitions, and templates into a single source code unit.
A UJML application consists of variables, state transitions, and functions co-operating to produce a desired outcome. However, these varied parts may be disjointed and unrelated from each other except by the fact they are all part of the same application. See Anatomy of a UJML Application. For large programs, this can lead to complex and difficult-to-follow code (also known as 'spaghetti code').
To solve this problem, UJML provides'state machines' and 'components'; which you can think of as a package of related variables, functions, and state transitions. See Components. Both state machines and components increase modularity and simplify code. Both, used properly, allow you to create reusable function libraries which you can apply to different applications without modification. However state machines are included into UJML source when it is compiled and components are compiled into separate byte code files. At run time each state machine is a single unit of code loaded along with its containing application, partition, or state machine. Components, on the other hand, may be loaded as separate 'instances' as many times as needed.
State machines are declared with a state-machines element which contains one to many state-machine elements. See state-machines, state-machine. Each state-machine element declares a separate, named, state machine and contains child state machines, variables, functions, templates, and state transitions.
State machines may be declared within applications, components, or other state machines. They may also be declared in separate files and included into applications components, or other state machines when those UJML files are compiled.
Identifier elements contained by a state machine, such as variables, functions, and templates, are called 'members'. See Identifiers. State machine members may be 'public' or 'private'. See Scope, Sharing. Code in the element containing the state machine may only access public members of the state machine using what is called 'dot notation'. This is in the form 'StateMachineName.MemberName'. For example, 'foo.bar'.
Code in the scope of an element containing a state machine may get or change the value of public state machine variables, call public state machine functions, and expand public state machine templates. State machines themselves may be shared with linked partitions. See State Machine Scoping and Sharing.
State machines may contain visual element template declarations and may display visual elements from state transitions. See Visual Elements, State Transitions. This means that you have two options for designing state machines which contain visual elements. Your state machine may expose public state variables or functions which change state variables, along with related state transitions containing the visual elements. Or, your state machine may provide public visual element templates which code outside the state machine can expand. See Visual Element Templates.
In the latter case, scripting elements in the templates may only refer to variables and functions within the scope of the state machine where the template is declared. For example, if your application contains a variable named 'foo' and also contains a state machine with a variable named 'foo', templates declared inside the state machine will use the 'foo' from the state machine scope even if they are expanded by UJML code in the application scope. See State Machine Scoping and Sharing.
The z-order of visual elements contained by a state machine is determined by the order they occur in the state machine. See Visual Elements, Z-Order. The z-order of the state machine itself is determined by the order it occurs in the containing element.
The z-order of a state machine is determined by its position in the containing element. Because elements which contain state machines may contain them both at the beginning and the end of the element, state machines have a z-order which comes either before all other contained elements or after all other contained elements.
Templates are the only way a state machine can provide visual elements with controllable z-order. You can expand a public template of a state machine anywhere in UJML code with that state machine in its scope and the template visual elements will have the z-order of the expand element. See Visual Element Templates.
State machines may contain other state machines in exactly the same way that an application or partition may contain one or more state machines. Nested state machines follow the same rules as applications and partitions, including the rules for z-order and scope. See State Machine Scoping and Sharing.
Note: Nested state machines establish their z-order in relation to the containing state machine's z-order.
Nesting state machines in this way allows you to build powerful compound state machines by combining and extending simpler state machines.
The include element copies state machine code from an external partition file into the current file. See Partition Files, Including Files, include. This works like cutting and pasting UJML state machine code from one file into another and, if the state machine is included more than once, results in the including file containing multiple copies of that state machine.
Note: A state machine may be included only once in a particular scope, but may be included more than once in different scopes of the same file. See Scope.
It is possible for an included state machine to include other state machines, resulting in a chain of state machine file dependencies. Attempting to include a state machine that includes itself or includes another state machine which includes itself results in a circular dependency and will cause a compiler error.
You can create state machines which only contain functions. These are a convenient way to keep related functions together and, when the state machines are included from external files, make the functions reusable among UJML applications.
You can create state machines which package together all the code needed to perform some task, hold some data, or display some visual element. Included into UJML applications, these components then provide a standard set of building blocks for creating rich applications quickly. For some examples of simple UJML state machines. See State Machine Samples.
Simply creating a state machine does not automatically bestow reusability upon it. Generally, reusability is maximized by reducing coupling and increasing coherence. This means that a reusable state machine should have minimal dependence on outside code (coupling) and should do only one thing as well as possible (coherence).
For UJML state machines, you achieve the first goal (reduced coupling) by making the state machine depend only on contained state machines (if anything). A state machine that requires a variable or function in its containing element is coupled to that containing element and is difficult to use in another context. You should also reduce the coupling of containing code into your state machine by minimizing the public members of the state machine. If your state machine needs to inform the containing code that something has changed, use a public state variable (that is not used internally by the state machine) and set the value of that state variable to a certain set of known values. The containing code may then implement state transitions appropriately.
Increasing coherence is a function of how well, and tightly, your state machine is designed. Although it might be tempting to build a 'Swiss Army Knife' component that does everything you need, your needs are best served by creating many small state machines which focus narrowly on providing one particular service. Try to make the public members of your state machine as clear as possible; think of public functions as verbs and public variables as nouns.
|
Topic |
Description |
|
State machines are scoped identifiers and may be shared. |
The following example is a simple state machine component which displays a colored box filling the device screen. The state machine exposes two public members: A state variable called 'sShow' which, if true, shows the colored box. And a function called _init() that sets the color for the box and allows you to show the box right away or not. It is part of the background.ujms sample.
<ujml>
<partition>
<state-machines>
<state-machine name="Background">
<state-variables>
<state-var name="sShow" type="boolean" visibility="public"/>
</state-variables>
<variables>
<var name="mColor" type="int" visibility="public"/>
</variables>
<functions>
<!--
Sets the color property and turns on the background if requested.
-->
<function name="init" type="void" visibility="public">
<parameters>
<var name="color" type="int"/>
<var name="showNow" type="boolean"/>background.ujms
</parameters>
<script>
mColor = color;
sShow = showNow;
</script>
</function>
</functions>
<states>
<state var="sShow">
<transition value="true">
<display>
<box>
<!-- Fill the screen with the specified color. -->
<width>
<eval>_getIntProperty(&_PROPERTY_INT_SCREEN_WIDTH;)</eval>
</width>
<height>
<eval>_getIntProperty(&_PROPERTY_INT_SCREEN_HEIGHT;)</eval>
</height>
<fg><eval>mColor</eval></fg>
<bg><eval>mColor</eval></bg>
</box>
</display>
</transition>
</state>
</states>
</state-machine>
</state-machines>
</partition>
</ujml>
The following example includes two state machines from different partition files. It is part of the visualelements.ujml sample.
<state-machines>
<include file="/../components/background.ujms" state-machine="Background" />
<include file="/../components/scrollmenu.ujms" state-machine="ScrollingMenu" />
</state-machines>
The following example shows how to call the _init() function of the 'Background' state machine. It is part of the visualelements.ujml sample.
Background.init(&_COLOR_BLACK;, true);
|
Copyright (c) 2000-2007 UIEvolution, Inc. All rights reserved.
|
|
What do you think about this topic? Send feedback!
|