VERSION 1 ACTIONS, METHODS, REFACTORING – 61 – CHAPTER 6 ACTIONS, METHODS, REFACTORING In this chapter we cover ACTIONS in more depth and show how to easily create additional actions in a script by using a technique known as REFACTORING. The chapter covers two forms of refac- toring supported in TouchDevelop. One form provides an easy way to create new actions, while the other form provides an easy way to add declarations for new variables to a script. We also show an extension to the second form of refactoring which promotes a local variable to become a new global data item. 6.1 ACTIONS 6.2 PARAMETER PASSING MECHANISMS 6.3 METHODS IN THE API 6.4 REFACTORING 6.1 ACTIONS An ACTION in TouchDevelop is very similar to a function in C or Python, or to a static method in Ja- va or C#. It is an independent sequence of statements which has a name, it optionally has input pa- rameters, and it optionally has result parameters. Let us take a look at the short example in Figure 6.1. This is similar to how the code would appear on the phone’s screen. Figure 6.1: The send invite Action action send invite( recips, msg ) returns n n := 0 for each s in recips where true do social → send email(s, “party invitation”, msg) n := n + 1 This send invite action has some properties which can be viewed by tapping the first line of the ac- tion, tapping the edit button, and swiping left-to-right. The PARAMS property will show the names
12
Embed
CHAPTER 6 ACTIONS, METHODS, REFACTORINGcdn.touchdevelop.com/c03/smqv-bookchapter6.pdf · 2012-02-28 · CHAPTER 6 ACTIONS, METHODS, REFACTORING In this chapter we cover ACTIONS in
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
VERSION 1 ACTIONS, METHODS, REFACTORING
– 61 –
CHAPTER 6
ACTIONS, METHODS, REFACTORING
In this chapter we cover ACTIONS in more depth and show how to easily create additional actions
in a script by using a technique known as REFACTORING. The chapter covers two forms of refac-
toring supported in TouchDevelop. One form provides an easy way to create new actions, while the
other form provides an easy way to add declarations for new variables to a script. We also show an
extension to the second form of refactoring which promotes a local variable to become a new global
data item.
6.1 ACTIONS
6.2 PARAMETER PASSING MECHANISMS
6.3 METHODS IN THE API
6.4 REFACTORING
6.1 ACTIONS
An ACTION in TouchDevelop is very similar to a function in C or Python, or to a static method in Ja-
va or C#. It is an independent sequence of statements which has a name, it optionally has input pa-
rameters, and it optionally has result parameters.
Let us take a look at the short example in Figure 6.1. This is similar to how the code would appear
on the phone’s screen.
Figure 6.1: The send invite Action
action send invite( recips, msg ) returns n
n := 0
for each s in recips where true do
social → send email(s, “party invitation”, msg)
n := n + 1
This send invite action has some properties which can be viewed by tapping the first line of the ac-
tion, tapping the edit button, and swiping left-to-right. The PARAMS property will show the names
ACTIONS, METHODS, REFACTORING VERSION 1
– 62 –
and the datatypes of all the input parameters. For the send invite action, the listing of the parame-
ters is as shown in Figure 6.2.
Figure 6.2: The send invite PARAMS Property
Similarly, the RETURNS property provides more information about the result returned by the ac-
tion. It is shown in Figure 6.3.
Figure 6.3: The send invite RETURNS Property
The input parameters work in a similar manner to parameters of methods in Java or C#. In other
words, the parameters are considered to be local variables of the action and, each time the action is
invoked, the parameters are initialized by copying values supplied by the caller.
Suppose, for example, that one of the other actions in our script is bulk mailer as shown in Figure
6.4. This action creates a String Collection value as the value of variable addr list and initializes the
variable msg to hold a String value. When send invite is invoked, its first parameter recips is ini-
tialized so that it refers to the same String Collection as addr list. Similarly, the second parameter
msg is initialized to hold the same string as the caller’s local variable named msg. Now that the pa-
rameters of send invite have been initialized, the body of the send invite action is executed. We will
not go into any detail about what this action does (suffice to say it will likely annoy everyone whose
name begins with ‘j’ in the contacts collection held on your phone if you actually run it). However,
while the action is running, it is computing a value held in the variable n. This variable is declared
as an output parameter, but while the action is executing, it should be considered to be just like any
local variable. When the action’s body has finished executing, the value of this local variable is re-
turned as the result. Its value will be assigned to variable cnt in the caller.
VERSION 1 ACTIONS, METHODS, REFACTORING
– 63 –
Figure 6.4: A Caller of the send invite Action
action bulk mailer( )
var my j friends := social → search contacts("j")
var addr list := collections → create string collection
for each c in my j friends where true do
var addr := c → email → address
addr list → add(addr)
// a more realistic example would assign several lines
// of text to the msg variable
var msg := "Will you come to my party on Friday? "
var cnt := ▷send invite(addr list, msg)
(cnt || " friends have been invited") → post to wall
Unlike many programming languages, there is no return statement in TouchDevelop. Execution
must reach the end of the action before control returns to the caller and any results are returned.
Now for some details which serious script developers need to know.
6.2 PARAMETER PASSING MECHANISMS
This is a topic which has been partially covered in Chapter 3 already. To recap, there are two kinds
of datatypes in the TouchDevelop scripting language. There are VALUE TYPES, where the variable
holds the value directly. For example, a variable of type Number corresponds to a word in the
memory of the phone which holds the number directly (as a bit pattern). And there are REFERENCE
TYPES. Every collection type in TouchDevelop is an example of a reference type. Suppose, for ex-
ample, a variable has the Link Collection type. The link collection value is a data structure located
somewhere in memory and the starting point for that data structure has a memory address (or a
location number). A variable in the script which has the type Link Collection would correspond to a
word in memory which holds the memory address of the data structure. When a variable which has
a reference type is assigned to another variable or is passed as a parameter to an action, we have
two references to the same data structure in memory.
This situation is diagrammed in Figure 6.5 where the variable num1 has the Number type, while
both links1 and links2 are variables with the Link Collection type. After creating a link collection as
a list of three e-mail addresses and assigning it to links1, another assignment
var links2 := links1
has been executed. Now any changes to the links1 link collection will change the links2 collection
and vice versa, because they are both references to the same collection.
ACTIONS, METHODS, REFACTORING VERSION 1
– 64 –
Figure 6.5: Value Types and Reference Types
Exactly the same behavior is observed for passing parameters to actions. If the parameter has one
of the value types then the action has a completely independent copy. If the parameter has one of
the reference types, then the caller and the action share references to the same value held in the
phone’s memory.
Which are the value types exactly? They are Number, Boolean, DateTime and Vector3. Every other
type is a reference type.
RETURNING RESULTS
The TouchDevelop editor allows an action to have any number of return parameters. What does
this mean? It simply means that the action can return several results at once and they can have dif-
ferent types. As a highly contrived example, consider the action shown in Figure 6.6.
Figure 6.6: An Action with Two Results
action random stuff( ) returns song, pic
var all songs := media → songs
var all pics := media → pictures
song := all songs → random
pic := all pics → random
VERSION 1 ACTIONS, METHODS, REFACTORING
– 65 –
All that matters for our example is that it has two result parameters, one of type Song and the other
of type Picture. When it is invoked, the caller can assign the result to two variables simultaneously.
Here is an example of how to write the calling code:
var s, p := ▷random stuff( )
s→play
p→post to wall
It declares s and p as local variables with type Song and Picture respectively, and then those varia-
bles are assigned the result of invoking the random stuff action.
Not many programming languages support functions or methods which return multiple results.
(Programmers in such languages must use various workarounds or less readable programming
constructs.) This feature of TouchDevelop can be used to make scripts shorter and more readable.
TouchDevelop treats a result parameter as a local variable with an invalid initial value. The action
must assign a value to the result parameter before the action returns to the caller. To enforce that
requirement, TouchDevelop analyzes the code of the action and checks that at least one assignment
happens on every possible execution path through the action.
6.3 METHODS IN THE API
The API provides various globals which have methods that can be invoked by a TouchDevelop
script. For example, one such global is languages and one of its methods is ‘detect language’. (A
Java or C# programmer might think of languages as being a class type and ‘detect language’ as be-
ing a static method of the class.)
The API also provides a number of datatypes, and values possessing those datatypes have associat-
ed methods. For example, chapter 2 used the Picture datatype in an example and it created a local
variable named pic with that type. One of the examples used the ‘set pixel’ method on that pic var-
iable. (A Java or C# programmer might consider pic to be a reference to a class instance and ‘set
pixel’ to be an instance method.)
When we write code to invoke these methods, parameter values may be passed into the methods
and results may be returned from them. Although the API’s methods are all implemented in the C#
language (as is the whole TouchDevelop application), the methods all behave similarly to Touch-
Develop actions. Value types are passed in to the methods using the call-by-value mechanism and
reference type values are passed in using call-by-reference.
Although methods provided by the API have the potential to return multiple results, none does.
Every method provided in the API so far either returns a single value or it returns Nothing.
ACTIONS, METHODS, REFACTORING VERSION 1
– 66 –
6.4 REFACTORING
The word REFACTORING is used in software engineering to mean a reorganization of a program
which does not change its behavior. Such a reorganization is normally performed to improve the
quality of the software in some way, such as to make the code more efficient or to be more readable
by humans. Most modern environments for software development, such as Visual Studio and
Eclipse, provide a variety of tools to support different forms of refactoring.
The TouchDevelop editor provides two forms of refactoring. One form extracts a group of state-
ments from an action and creates a new action, with appropriate parameters, from those state-
ments. We might want to perform such refactoring if we have an action which has become too long
to comfortably display on the screen and we simply want to split the action up into smaller pieces.
Or, perhaps we have recognized that there is a particular group of statements which we will need to
execute several times with different parameterization. These are both excellent reasons to extract
and create a new action. Finally, a TouchDevelop user is likely to find this form of refactoring to be a
time saver because fewer taps and few swipes are needed to create a script composed of multiple
actions.
The second form of refactoring is to extract an expression or a subexpression, replace it with a
newly created variable, and insert an initialization of that new variable with the extracted expres-
sion.
A further step beyond extracting an expression and creating a new local variable is to convert that
local variable into a new globally visible data item. This would make the value of the variable acces-
sible to all the actions in the script (as well as preserving the value of the data item from one invo-
cation of the script to the next invocation – a feature known as persistence.)
REFACTORING: EXTRACTION OF STATEMENTS TO A NEW ACTION
Let’s go through an example of refactoring in TouchDevelop. Chapter 2 contained an example, the
‘Random circles’ script, which was constructed and entered as two separate actions. Suppose that
we had entered the script as just one action. It would look like the script shown in Figure 6.7.
There is nothing wrong with this version of the script, it is not too long and it runs perfectly well.
However, we might decide that the group of statements which draws the circle is so useful that we
want to extract that code and make a new action from it.
VERSION 1 ACTIONS, METHODS, REFACTORING
– 67 –
Figure 6.7: A Monolithic ‘Random circles’ Script
action Random circles( )
pic := media→create picture(400, 400)
for 0 ≤ i < 20 do
var radius := 5 + math→random(95)
var x := math→random(400) // x coordinate of center
var y := math→random(400) // y coordinate of center
var color := colors→random
for 0 ≤ i1 < 2 * math→ * radius do
var xofs := x + radius * math→cos(i1 / radius)
var yofs := y + radius * math→sin(i1 / radius)
pic→set pixel(x + xofs, y + yofs, color)
pic→post to wall
Here are the steps we might perform extract the circle drawing code (which corresponds to the in-
ner for loop).
1. Touch anywhere in the first line of the group of statements we wish to extract. For our exam-
ple, that is the inner for loop (the one which uses i1 as the index variable). The screen should
now look like this:
ACTIONS, METHODS, REFACTORING VERSION 1
– 68 –
2. Now touch the button labeled ‘select more’ and the screen changes to look like this:
3. It so happens that everything we want has been selected because it is a single statement (the
entire for loop) identified by the red bar on the left and show between the upper and lower
rows of buttons. If we wanted to selected additional statements, we could drag the group of
statements upward to increase the range of statements to be extracted. In our example, we do
not need to do that, so we can proceed to tap the extract button. At this point, we are asked to
provide a name for the extracted code (the new action). We enter the desired name, ‘draw cir-
cle’, and tap another extract button.
4. The screen should change to show the revised ‘Random circles’ action after the refactoring has
been performed. Here is a screenshot:
VERSION 1 ACTIONS, METHODS, REFACTORING
– 69 –
5. The editor has created an invocation of the new action, with the name we gave it and with
whatever parameters were needed to transmit values of variables from the caller (the Random
circles action) to the callee (the new draw circle action).
At this point, the refactoring has been completed. The modified script should work just as before.
Finally, here is a quick way to see the code of the new action (or of any action being invoked in a
script). We touch the line of code containing the call to the action. This brings up the edit statement
menu, which looks like the following for our example:
The go to button will take us to the code for the action invoked in the selected statement. After
touching it, the screen will show our refactored action:
The code is remarkably similar to the code originally shown in Chapter 2. The only differences are
the order in which the parameters appear and the name used for the index variable of the for loop.
These would usually be considered to be trivial and unimportant differences.
REFACTORING: EXTRACTION OF AN EXPRESSION TO A VARIABLE
If you discover that you have constructed an expression whose value you would like to reuse, or if
you have a complicated expression which you would like to break up into smaller pieces, this form
of refactoring is just what you need.
Let’s take a small example. Suppose that you have just entered the following script which calculates
the length of the diagonal side of a right-angled triangle whose sides are x1 and y2:
ACTIONS, METHODS, REFACTORING VERSION 1
– 70 –
Perhaps we are now going to extend this script to perform more calculations and we will need to
reuse the values of x1*x1 and x2*x2 in some statements we will add to the bottom. Here are the
steps to follow.
1. Tap the line containing the expression you wish to extract. In our sample script, that is the
line beginning “var x := …”
2. Tap the first element of the expression, which is the first x1 appearing in that line.
3. Swipe from left to right, to highlight all the elements of the selected expression. For our exam-
ple, the screen should now look like this, with a menu of available editing actions at the bottom:
4. Tap the extract to local button. The statement shown on the screen changes to the following,
indicating that a new local variable named x3 has been created.
5. Let’s repeat steps 2 to 4 in the same way to extract the expression x2*x2 into a new local varia-
ble named x4.
6. We can tap the phone back button to see how the code for our script has been transformed.
VERSION 1 ACTIONS, METHODS, REFACTORING
– 71 –
7. If we do not like the default names provided for the new local variables, they are easy to re-
name. One just has to tap any line where the name appears, choose the option to edit the line,
select an occurrence of the variable, and there will be a rename button provided on the screen.
REFACTORING: PROMOTING A LOCAL VARIABLE TO A GLOBAL DATA ITEM
Perhaps we are going to expand the example script by adding many new actions to it and lots of
these actions will need access to the values of the new variables x3 and x4. One possibility is to
pass x3 and x4 as parameters to the various actions. Another possibility is to convert x3 and x4
into global data items. TouchDevelop provides an easy way to make that transformation.
The steps for converting the local variable x3 in the preceding example into a new data item are as
follows.
1. Tap the line which declares and initializes the local variable.
2. Tap the edit button.
3. Tap the variable on the left-hand side. An edit menu like that shown below appears.
4. Tap the promote to ◳ button. The code displayed on the screen changes to that shown below,
indicating that x3 is now being accessed as a global data item. A return to the main screen for
the script would show that the script now includes x3 as a data item.