This Lasso 9 tip discusses how containers in Lasso 9 provide backward compatibility with code from earlier versions of Lasso, but also provide new capabilities which make writing code easier.
Container tags in Lasso are used for several purposes. They are used to loop execution of a portion of code. They are used to conditionally execute code. They are used for error handling. They are used to format HTML tags.
Containers in Lasso 9 work the same as they do in earlier versions of Lasso. A conditional statement and a loop both look the same in Lasso 9 as they do in earlier versions.
if(true); // True Part else; // False Part /if; loop(10); loop_count; /loop;
However, behind the scenes, containers are implemented very different in Lasso 9 than they were in earlier versions of Lasso. Containers can be called in a new way in Lasso 9 and can be implemented using different low-level code. Entirely new types of tags are possible using these new conventions.
When a container is compiled by Lasso all of the contents of the container is compiled into an auto-collect codeblock. This is similar to what happens when you define a custom tag within Lasso. The codeblock may be executed many times, as in a loop tag. Each time the codeblock executes its return value is determined by concatenating the values of all the statements within the codeblock. The concatenation of all the repetitions of the codeblock then form the final output of the container.
In Lasso 9 you can choose to use the traditional container syntax from earlier versions of Lasso.
loop(10);
loop_count;
/loop;
Or, you can explicitly associate a codeblock with a container using the association operator =>. In order to replicate the behavior of a container you want to use an auto-collect codeblock which is defined using the delimiters {^ ... ^}. I tend to think of the caret representing an "A" for auto-collect.
The code above can be specified in Lasso 9 using the following code. The output is exactly the same as the loop specified above. The [Loop_Count], [Loop_Abort], and [Loop_Continue] tags can be used within the codeblock the same as they can be used within the traditional container.
loop(10) => {^ loop_count ^}
There are several advantages to using this new syntax.
The block which will be executed by the container can actually be stored in a variable. Rather than doing a conditional within the loop we can move the conditional outside of the loop and execute it once rather than many times.
This simple example shows how this works. We can output only even number or only odd numbers by selecting which code block we want to execute.
var(odds) = {^ loop_count % 2 == 1 ? loop_count ^}
var(evens) = {^ loop_count % 2 == 0 ? loop_count ^}
loop(10) => $odds;
loop(10) => $evens;
For simple expressions it reads more simply using the new syntax. The handle container allows us to run code at the end of the current codeblock. For example we often want to explicitly ask to have a file closed rather than relying on Lasso to do it for us. The following code shows how we can do this in Lasso 9 using a single line [Handle] rather than a traditional container.
local(file) = file;
handle => {#file->close}
#file->openappend(sys_supportpath + 'Lasso_Errors.txt', true)
#file->writebytes(bytes('[' + system_datetime + '] Iceburg!\r\n'))
Using traditional container tags Lasso always collects the output of each tag and returns it as the value for the container. However, sometimes we don't need our codeblock to generate any output. We can optimize our code by selecting a normal codeblock rather than an auto-output codeblock. Now the container may not return any output at all.
The following code does not generate any output, but does log ten values to the console.
loop(10) => {
loop_count;
log_always(loop_count);
}
One of the drawbacks of Lasso's traditional container syntax is that it is difficult to conceive of how a container could be implemented as a member tag. How would this look?
Lasso 9 allows a codeblock to be associated with a member tag. This means that the member tag can serve as a container.
For example, the [Duration->ForEachDay] tag is a container which will implement the given codeblock for each day between the start and end of the duration. The following code returns the a [Date] object for each day in January, 2008. Note that the #1 refers to the first parameter passed to the codeblock. The provided parameters may differ from tag to tag.
var(myduration) = duration('1/1/2008 00:00:00', '1/31/2008 00:00:00');
$myduration->foreachday => {^ #1; '\r\n'; ^}
There are a great many tags of this sort in Lasso 9 already. All compound data types support a ->ForEach tag as an alternative to the [Iterate] ... [/Iterate] tags. The following code returns each element of the array in uppercase on a line by itself.
array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')->foreach => {^
string_uppercase(#1); '\r\n';
^}
The implementation of a container in Lasso 9 relies on some of the characteristics of codeblocks and captures. The implementation for the [Duration->ForEachDay] tag is shown below.
The tag maintains a cursor which cycles through each day in the duration using [Date->Add]. If the cursor is past the end date then the tag returns. The [GivenBlock] tag runs the associated codeblock for the tag with the specified parameter. In this case the cursor is passed to the codeblock as its sole parameter.
The code { }() is called a capture. It is analogous to a tag execution. The tag [CurrentCapture->Restart] tells this capture to jump back to the beginning. Note that the local variable cursor maintains its value even as this capture is run again and again.
public foreachday() => {
local(cursor) = date(.'start'); // Use local so we don't modify start
{
#cursor > .'end' ? return;
givenBlock(#cursor)
#cursor->add(-day=1);
currentCapture->restart;
}();
}
The file _init.lasso contains the definition of several containers including the loop tags. Member containers are defined in many of the startup libraries for Lasso 9.
Author: Dominique Guardiola Falco
Created: 21 Mar 2010
Last Modified: 19 Jan 2012
Please note that periodically LassoSoft will go through the notes and may incorporate information from them into the documentation. Any submission here gives LassoSoft a non-exclusive license and will be made available in various formats to the Lasso community.
©LassoSoft Inc 2015 | Web Development by Treefrog Inc | Privacy | Legal terms and Shipping | Contact LassoSoft