Using do-syntax

When working with anonymous functions, we may end up having a code block that is in the middle of a function call, making the code more difficult to read. The do-syntax is a great way to address this problem and produce clear, easy-to-read code.

To illustrate the concept, let's build up a new use case for our battle fleet. In particular, we will enhance our spaceships with the ability to launch missiles. We also want to support the requirement that launching a weapon requires that the spaceship is in a healthy state. 

We can define a fire function that takes a launch function and a spaceship. The launch function is executed only when the spaceship is healthy. Why do we want to take a function as an argument? Because we want to make it flexible so that, later on, we can use the same fire function to launch laser beams and other possible weapons:

# Random healthiness function for testing
healthy(spaceship) = rand(Bool)

# make sure that the spaceship is healthy before any operation
function fire(f::Function, spaceship::Widget)
if healthy(spaceship)
f(spaceship)
else
println("Operation aborted as spaceship is not healthy")
end
return nothing
end

Let's try this out using an anonymous function to fire the missile:

So far so good. But what happens if we need a more complex procedure to fire missiles? For example, say that we would like to move the spaceship up before firing and move it back down afterward:

fire(s -> begin
move_up!(s, 100)
println(s, " launched missile!")
move_down!(s, 100)
end, spaceship)

The syntax now looks quite ugly. Fortunately, we can rewrite the code using the do-syntax and make it more readable:

fire(spaceship) do s
move_up!(s, 100)
println(s, " launched missile!")
move_down!(s, 100)
end

How does it work? Well, the syntax is translated so that the do-block is turned into an anonymous function and it is then just inserted as the first argument of the function.

An interesting usage of the do-syntax can be found in Julia's open function. Because reading a file involves opening and closing a file handler, the open function is designed to accept an anonymous function that takes an IOStream and do something with it, while the opening/closing housekeeping tasks are handled by the open function itself. 

The idea is quite simple, so let's just replicate it here with our own process_file function:

function process_file(func::Function, filename::AbstractString)
ios = nothing
try
ios = open(filename)
func(ios)
finally
close(ios)
end
end

Using the do-syntax, we can focus on developing the logic of file processing without having to worry about the housekeeping chores, such as opening and closing files. Consider the following code:

As you can see, the do-syntax can be useful in two ways:

  • It makes the code more readable by rearranging the anonymous function argument in a block format.
  • It allows the anonymous functions to be wrapped in a context for which additional logic can be executed before or after the function.

Next, we will take a look at multiple dispatch, which is a unique feature that is not commonly found in object-oriented languages.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.186.6