Defining Your Own Methods¶
In the tutorial on variables, we discussed how variables store values that can then be referenced later. But wouldn’t it be nice to be able to store a set of logic code for later re-use? That’s where defining your own methods come in.
Basic Method Definition¶
Here’s the latest iteration of our ongoing example:
<?lasso
local(hour) = date->hour
local(time_info) = map(
`morning` = map('greeting'="Good Morning!", 'bgcolor'='lightyellow'),
`afternoon` = map('greeting'="Good Afternoon!", 'bgcolor'='lightblue'),
`evening` = map('greeting'="Good Evening!", 'bgcolor'='lightgray')
)
local(time_of_day)
if(#hour >= 5 and #hour < 12)
#time_of_day = #time_info->find('morning')
else(#hour >= 12 && #hour < 17)
#time_of_day = #time_info->find('afternoon')
else
#time_of_day = #time_info->find('evening')
/if
?>
<html>
<body style="background-color: [#time_of_day->find('bgcolor')]">
[#time_of_day->find('greeting')] I am an HTML document.
</body>
</html>
Let’s suppose that we had the need to be able to tell the current time of day
(morning, afternoon, evening) on multiple pages. We could repeat our if
statement on those pages, but what if our definition of when evening starts or
ends changes? We would have to find and adjust this logic on all the pages that
have it.
Instead, let’s create a method we can call on each of the pages that returns the current time of day. That way if we need to adjust the time, we only have one place we need to adjust the code:
define time_of_day => {
local(hour) = date->hour
if(#hour >= 5 and #hour < 12) => {
return 'morning'
else(#hour >= 12 && #hour < 17)
return 'afternoon'
else
return 'evening'
}
}
The first line contains the define
keyword followed by the name for the
method followed by the association operator (=>
) and an open brace. All the
code between that open brace and its matching closing brace is associated with
the method and executed when the method is called. The return
statement in a
method tells it to stop executing its code and return the value to the method’s
caller. In this case, we’ll be returning either “morning”, “afternoon”, or
“evening”.
We could put this method definition inside the <?lasso ... ?>
delimiter on
our page, but then it would be redefined each time that page is called, and if
that page hasn’t been called but a different page tried to invoke the method,
Lasso wouldn’t be able to find it. For these reasons, it’s best to put method
definitions like this in a file whose name ends with either “.lasso” or
“.inc” and place that file in “LassoStartup” in your instance’s home
directory. Those files get run when Lasso starts up which means the method will
then be loaded and ready for use on any page.
Our page can then use the method in the following fashion:
<?lasso
local(time_info) = map(
`morning` = map('greeting'="Good Morning!", 'bgcolor'='lightyellow'),
`afternoon` = map('greeting'="Good Afternoon!", 'bgcolor'='lightblue'),
`evening` = map('greeting'="Good Evening!", 'bgcolor'='lightgray')
)
local(time_of_day) = #time_info->find(time_of_day)
?>
<html>
<body style="background-color: [#time_of_day->find('bgcolor')]">
[#time_of_day->find('greeting')] I am an HTML document.
</body>
</html>
Method Definition with Arguments¶
There may be times when it would be useful to pass data into a method for it to
work with. For example, instead of using the current time, we may want to modify
our time_of_day
method to take a date object and return the time of day
based on the specified time:
define time_of_day(datetime) => {
local(hour) = #datetime->hour
if(#hour >= 5 and #hour < 12) => {
return 'morning'
else(#hour >= 12 && #hour < 17)
return 'afternoon'
else
return 'evening'
}
}
Here, in the method signature, we’ve added “(datetime)” after the method name. This specifies that the method will now take one parameter (also called an argument) with the name of “datetime”. This parameter is setup as a local variable in our method which allows us to set the “hour” local variable to the hour of the date object passed to the method. (If you’ve made changes to the startup file, you’ll need to restart Lasso for the new definition to load.)
There is one problem, however; our current code for the HTML page won’t work
because it doesn’t pass any parameters to the time_of_day
method. We could
fix this by changing it to use time_of_day(date)
, but a better solution
might be to make the argument an optional parameter by giving it a default
value:
define time_of_day(datetime=date) => {
// ... rest of method definition ...
By placing an equals sign after “datetime” followed by an expression we have
made it an optional parameter whose default value is determined by the
expression. In this case, if no parameters are passed to time_of_day
, the
“datetime” variable will be set to the current date and time by the date
method.
Method Definition and Multiple Dispatch¶
Lasso also has an amazing feature called multiple dispatch. With multiple dispatch, two methods with the same name but with different signatures that execute different code can exist. Lasso uses the signatures to figure out which method to call.
This can be useful in our example because we may want to have one method named “time_of_day” that returns the time of day based on a date object and another method named “time_of_day” that returns the time of day based on an integer passed to it:
define time_of_day(datetime::date=date) => {
return time_of_day(#datetime->hour)
}
define time_of_day(hour::integer) => {
if(#hour >= 5 and #hour < 12) => {
return 'morning'
else(#hour >= 12 && #hour < 17)
return 'afternoon'
else
return 'evening'
}
}
Here I am defining two methods, both with the name “time_of_day”. The first method has a signature of “time_of_day(datetime::date=date)”. All that has been added from the previous definition is the type constraint ”::date”. This method can be called without a parameter and “datetime” will default to the current date and time, but with the type constraint the method can only be called with a date object. The following method calls will call this method:
time_of_day // Can be called with no parameters
time_of_day(date) // Any date object will do
The second method has the following signature: “time_of_day(hour::integer)”. The
hour
parameter has been constrained to only take integer values. Also, there
is no default value for “hour”, so a parameter must be provided to call this
method. The following method calls will invoke this method:
time_of_day(19) // Any integer will do
Notice that all the first method does is return the value of invoking the second method. Once again, it’s better not to have the same code in multiple places. Now any changes to the logic can again be made in only one place.
See also
For detailed documentation on method definitions and multiple dispatch, see the Methods chapter.