Functional Programming Patterns in Scala and Clojure 1st Edition Michael Bevilacqua-Linn - Quickly download the ebook to never miss any content
Functional Programming Patterns in Scala and Clojure 1st Edition Michael Bevilacqua-Linn - Quickly download the ebook to never miss any content
com
https://ebookgate.com/product/functional-programming-
patterns-in-scala-and-clojure-1st-edition-michael-
bevilacqua-linn/
OR CLICK BUTTON
DOWLOAD EBOOK
https://ebookgate.com/product/programming-scala-2nd-edition-
scalability-functional-programming-objects-second-edition-dean-
wampler/
ebookgate.com
https://ebookgate.com/product/learning-scala-practical-functional-
programming-for-the-jvm-1st-edition-jason-swartz/
ebookgate.com
https://ebookgate.com/product/programming-clojure-1st-edition-stuart-
halloway/
ebookgate.com
https://ebookgate.com/product/clojure-programming-1st-edition-chas-
emerick/
ebookgate.com
Programming in Scala 2nd 2nd Edition Martin Odersky
https://ebookgate.com/product/programming-in-scala-2nd-2nd-edition-
martin-odersky/
ebookgate.com
https://ebookgate.com/product/scala-high-performance-programming-1st-
edition-theron/
ebookgate.com
https://ebookgate.com/product/the-joy-of-clojure-thinking-the-clojure-
way-1st-edition-michael-fogus/
ebookgate.com
https://ebookgate.com/product/science-learning-and-instruction-1st-
edition-linn/
ebookgate.com
This book is an absolute gem and should be required reading for anybody looking
to transition from OO to FP. It is an extremely well-built safety rope for those
crossing the bridge between two very different worlds. Consider this mandatory
reading.
➤ Colin Yates, technical team leader at QFI Consulting, LLP
This book sticks to the meat and potatoes of what functional programming can do
for the object-oriented JVM programmer. The functional patterns are sectioned in
the back of the book separate from the functional replacements of the object-oriented
patterns, making the book handy reference material. As a Scala programmer, I even
picked up some new tricks along the read.
➤ Justin James, developer with Full Stack Apps
This book is good for those who have dabbled a bit in Clojure or Scala but are not
really comfortable with it; the ideal audience is seasoned OO programmers looking
to adopt a functional style, as it gives those programmers a guide for transitioning
away from the patterns they are comfortable with.
➤ Rod Hilton, Java developer and PhD candidate at the University of Colorado
Michael Bevilacqua-Linn
Preface . . . . . . . . . . . . . . ix
Bibliography . . . . . . . . . . . . 231
Index . . . . . . . . . . . . . . 233
This book would have suffered greatly without a great group of technical
reviewers. My thanks to Rod Hilton, Michajlo “Mishu” Matijkiw, Venkat Sub-
ramaniam, Justin James, Dave Cleaver, Ted Neward, Neal Ford, Richard
Minerich, Dustin Campbell, Dave Copeland, Josh Carter, Fred Daoud, and
Chris Smith.
Finally, I’d like to thank Dave Thomas and Andy Hunt. Their book, The
Pragmatic Programmer, is one of the first books I read when I started my
career. It made a tremendous impact, and I’ve still got my original dog-eared,
fingerprint-covered, bruised and battered copy. In the Pragmatic Bookshelf,
they’ve created a publisher that’s truly dedicated to producing high-quality
technical books and supporting the authors who write them.
Used together, these patterns let programmers solve problems faster and in
a more concise, declarative style than with object-oriented programming alone.
If you’re using Java and want to see how functional programming can help
you work more efficiently, or if you’ve started using Scala and Clojure and
can’t quite wrap your head around functional problem-solving, this is the
book for you.
Before we dig in, I’d like to start off with a story. This story is true, though
some names have been changed to protect the not-so-innocent.
A Tale of Functional Programming
by: Michael Bevilacqua-Linn, software firefighter
The site isn’t down, but an awful lot of alarms are going off. We trace the problems to changes
someone made to a third-party API we use. The changes are causing major data problems on
our side; namely, we don’t know what the changes are and we can’t find anyone who can tell
us. It also turns out the system that talks to the API uses legacy code, and the only guy who
knows how to work on it happens to be away on vacation. This a big system: 500,000-lines-of-
Java-and-OSGI big.
Support calls are flooding in, lots of them. Expensive support calls from frustrated customers.
We need to fix the problem quickly. I start up a Clojure REPL and use it to poke around the
problem API.
My boss pokes his head into my office. “How’s it going?” he asks. “Working on it,” I say. Ten
minutes later, my grandboss pokes his head into my office. “How’s it going?” he asks. “Working
on it,” I say. Another ten minutes pass by when my great-grandboss pokes his head into my
office. “How’s it going?” he asks. “Working on it,” I say. I get a half hour of silence before the CTO
pokes his head into my office. “Working on it,” I say before he opens his mouth.
An hour passes, and I figure out what’s changed. I whip up a way to keep the data clean until
the legacy developer gets back and can put together a proper fix. I hand my little program off
to the operations team, which gets it up and running in a JVM, somewhere safe. The support
calls stop coming in, and everyone relaxes a bit.
A week or so later at an all-hands meeting, the great-grandboss thanks me for the Java program
I wrote that saved the day. I smile and say, “That wasn’t Java.”
Two of the patterns that we’ll see in this book, Pattern 21, Domain-Specific
Language, on page 218, and Pattern 15, Chain of Operations, on page 159,
contributed greatly to this story’s happy ending.
The TinyWeb extended example serves a few purposes. It will let us see how
several of the patterns we cover in this book fit together in a comprehensive
manner. We also use it to introduce the basics of Scala and Clojure. Finally,
since we’ll transform TinyWeb from Java to Scala and Clojure bit by bit, it
gives us a chance to explore how to easily integrate Java code with Scala and
Clojure.
The remainder of the book is organized into two sections. The first, Chapter
3, Replacing Object-Oriented Patterns, on page 39, describes functional
replacements for object-oriented patterns. These take weighty object-oriented
patterns and replace them with concise functional solutions.
Peter Norvig, author of the classic Lisp text Paradigms of Artificial Intelligence
Programming: Case Studies in Common Lisp [Nor92], current director of
research at Google, and all-around very smart guy, pointed out in Design
Patterns in Dynamic Languages that expressive languages like Lisp could turn
classic object-oriented patterns invisible.1
Pattern Template
The patterns are laid out using the following format, with some exceptions.
For example, a pattern that doesn’t have any other common name would not
have the Also Known As subsection, and the Functional Replacement subsec-
tions only apply to the patterns in Chapter 3, Replacing Object-Oriented Pat-
terns, on page 39.
Intent
The Intent subsection provides a quick explanation of the intent of this pattern
and the problem it solves.
Overview
Here is where you’ll find a deeper motivation for the pattern and an explanation
of how it works.
Also Known As
This subsection lists other common names for the pattern.
1. http://norvig.com/design-patterns/
Functional Replacement
Here you’ll find how to replace this pattern with functional programming
techniques—sometimes object-oriented patterns can be replaced with basic
functional language features and sometimes with simpler patterns.
Example Code
This subsection contains samples of the pattern—for object-oriented patterns,
we first show a sketch of the object-oriented solution using either class dia-
grams or a sketch of the Java code before showing how to replace them in
Clojure and Scala. Functional patterns will be shown in Clojure and Scala
only.
Discussion
This area provides a summary and discussion of interesting points about the
pattern.
Related Patterns
This provides a list of other patterns in this book that are related to the current
one.
Both Scala and Clojure run on a Java virtual machine (JVM), so they interop-
erate well with existing Java libraries and have no issues being dropped into
the JVM infrastructure. This makes them ideal to run alongside existing Java
codebases. Finally, while both Scala and Clojure have functional features,
they’re quite different from each other. Learning to use both of them exposes
us to a very broad range of functional programming paradigms.
Clojure is a modern take on Lisp. It has Lisp’s powerful macro system and
dynamic typing, but Clojure has added some new features not seen in older
Lisps. Most important is its unique way of dealing with state change by using
reference types, a software transactional memory system, and efficient
immutable data structures.
As we introduce the patterns, we’ll explore both of these languages and their
features, so this book serves as a good introduction to both Scala and Clojure.
For further detail on either language, my favorite books are Programming
Clojure [Hal09] and The Joy of Clojure [FH11] for Clojure, and Programming
Scala: Tackle Multi-Core Complexity on the Java Virtual Machine [Sub09] and
Scala In Depth [Sue12] for Scala.
From there you can jump around, pattern by pattern, as needed. The patterns
covered earlier in Chapter 3, Replacing Object-Oriented Patterns, on page 39,
and Chapter 4, Functional Patterns, on page 137, tend to be more basic than
later ones, so they’re worth reading first if you have no previous functional
experience.
A quick summary of each pattern can be found in Section 1.2, Pattern Glos-
sary, on page 4, for easy browsing. Once you’re through the introduction,
you can use it to look up a pattern that solves the particular problem you
need to solve.
Online Resources
As you work through the book, you can download all the included code files
from http://pragprog.com/titles/mbfpp/source_code. On the book’s home page at
http://pragprog.com/book/mbfpp, you can find links to the book forum and to report
errata. Also, for ebook buyers, clicking on the box above the code extracts
downloads the code for that extract for you.
Second, the functional world also has its own set of useful patterns. These
patterns focus on writing code that avoids mutability and favors a declarative
style, which helps us write simpler, more maintainable code. The two main
sections of this book cover these two sets of patterns.
You may be surprised to see the first set. Don’t the patterns we know and
love extend across languages? Aren’t they supposed to provide common
solutions to common problems regardless of what language you are using?
The answer to both questions is yes, so long as the language you are using
looks something like Java or its ancestor, C++.
That’s not to say that foreach loops are exactly equivalent to the Iterator. A
foreach won’t replace an Iterator in all cases. The problems they do address
are solved in a simpler way. Developers prefer the built-in foreach loops for the
common-sense reasons that they are less work to implement and are less
error prone.
Adding functional features and techniques adds more tools to our program-
ming toolbox, just as Java 1.5 did with its foreach loop but on a grander scale.
These tools often complement the tools we already know and love from the
object-oriented world.
The second set of patterns we cover in this book, native functional patterns,
describes the patterns that evolved out of the functional style. These functional
patterns differ from the object-oriented patterns you may be familiar with in
a few key ways. The first, and most obvious, is that functions are the primary
unit of composition, just as objects are in the object-oriented world.
Another key difference lies in the patterns’ granularity. The patterns from
Design Patterns: Elements of Reusable Object-Oriented Software [GHJV95] (one
of the original drivers of the software patterns movement) are generally tem-
plates that define a few classes and specify how they fit together. Most of
them are medium size. They often don’t concern themselves either with very
small issues that encompass just a few lines of code or with very large issues
that encompass entire programs.
The functional patterns in this book cover a much broader range, as some of
them can be implemented in a line or two of code. Others tackle very big
problems, such as creating new, miniature programming languages.
The range is in line with the book that started the patterns movement in
general, A Pattern Language [AIS77]. This book on architectural patterns
starts off with the very big “1—Independent Regions” pattern, which outlines
why the planet should be organized into political entities of about 10,000
people, and goes all the way down to “248—Soft Tile and Brick,” which explains
how to make your own bricks.
Before we dig into the various patterns in this book, let’s spend some time
getting familiar with functional programming itself.
Favor pure functions: Pure functions are functions that have no side effects.
A side effect is an action that the function does that modifies state outside
the function.
However, other problems are hard, if not impossible, to solve using strict
functional programming techniques. A compiler is a pure function. If you put
a program in, you expect to get the same machine code out every time. If you
don’t, it’s probably a compiler bug. Google’s search engine, however, is not a
pure function. If we got the same results from a Google search query every
time, we’d be stuck with a late 1990s view of the Web, which would be quite
tragic.
Scala has more support for mutable data, but immutable data is preferred.
For instance, Scala has both mutable and immutable versions of its collections
library, but the immutable data structures are imported and used by default.
This section introduces two basic types of functional features. The first type,
higher-order functions, allows us to pass functions around as first-class data.
The second, anonymous functions, allows us to write quick one-off functions
without giving them a name. These features combine to let us replace most
instances of Functional Interface very concisely.
Let’s focus on a few goals for this example. The first is to see several patterns
working together in one codebase before we go into them in more detail.
The second is to introduce basic Scala and Clojure concepts for those unfa-
miliar with either, or both, of the languages. A full introduction to the lan-
guages is beyond the scope of this book, but this section gives you enough
of the basics to understand the majority of the remaining code.
Finally, we’ll work existing Java code into a Scala or Clojure codebase. We’ll
do this by taking the Java version of TinyWeb and transforming it into Scala
and Clojure piece by piece.
Template Method, on page 83. Views are implemented using the Strategy
pattern, covered in Pattern 7, Replacing Strategy, on page 92.
Our framework is built around core pieces of data objects, HttpRequest and
HttpResponse. We want these to be immutable and easy to work with, so we are
going to build them using the Builder pattern discussed in Pattern 4,
Replacing Builder for Immutable Object, on page 62. Builder is a standard way
of getting immutable objects in Java.
Finally, we’ve got request filters that run before a request is handled and that
do some work on the request, such as modifying it. We will implement these
filters using the Filter class, a simple example of Pattern 1, Replacing Functional
Interface, on page 40. Our filters also show how to handle changing data using
immutable objects.
We’ll start off with a look at our core data types, HttpRequest and HttpResponse.
JavaExamples/src/main/java/com/mblinn/oo/tinyweb/HttpResponse.java
package com.mblinn.oo.tinyweb;
This approach encapsulates all mutability inside of a Builder object, which then
builds an immutable HttpResponse. While this gives us a clean way of working
with immutable data, it’s quite verbose. For example, we could create a simple
test request using this code:
Without using Builder we’d need to pass all of our arguments in the construc-
tor. This is okay for our small example, but this practice grows unwieldy when
working with larger classes. Another option would be to use a Java Bean–style
class with getters and setters, but that would require mutability.
Let’s move on and take a quick look at HttpRequest. Since the class is similar
to HttpResponse (though it lets us set a request body, headers, and a path), we
won’t repeat the code in full. One feature is worth mentioning, though.
return builder;
}
This may seem wasteful, but the JVM is a miracle of modern software engi-
neering. It’s able to garbage-collect short-lived objects very efficiently, so this
style of programming performs admirably well in most domains.
First we’ll need a View interface, which has a single method, render(). render()
takes in a model in the form of a Map<String, List<String>>, which represents the
A large class of software bugs boil down to one section of code modifying data in
another section in an unexpected way. This type of bug becomes even more heinous
in the multicore world we all live in now. By making our data immutable, we can
avoid this class of bugs altogether.
Using immutable data is an oft-repeated bit of advice in the Java world; it’s mentioned
in Effective Java [Blo08]—Item 15: Minimize Mutability, among other places, but it is
rarely followed. This is largely due to the fact that Java wasn’t designed with
immutability in mind, so it takes a lot of programmer effort to get it.
Still, some popular, high-quality libraries, such as Joda-Time and Google’s collections
library, provide excellent support for programming with immutable data. The fact
that both of these popular libraries provide replacements for functionality available
in Java’s standard library speaks to the usefulness of immutable data.
Thankfully, both Scala and Clojure have much more first-class support for immutable
data, to the extent that it’s often harder to use mutable data than immutable.
model attributes and values. We’ll use a List<String> for our values so that a
single attribute can have multiple values. It returns a String representing the
rendered view.
import java.util.List;
import java.util.Map;
Next we need two classes that are designed to work together using the Strat-
egy pattern: StrategyView and RenderingStrategy.
JavaExamples/src/main/java/com/mblinn/oo/tinyweb/RenderingStrategy.java
package com.mblinn.oo.tinyweb;
import java.util.List;
import java.util.Map;
Now let’s examine the class that delegates to RenderingStrategy, StrategyView. This
class is implemented by the framework and takes care of properly handing
exceptions thrown out of the RenderingStrategy. Its code follows:
JavaExamples/src/main/java/com/mblinn/oo/tinyweb/StrategyView.java
package com.mblinn.oo.tinyweb;
import java.util.List;
import java.util.Map;
@Override
public String render(Map<String, List<String>> model) {
try {
return viewRenderer.renderView(model);
} catch (Exception e) {
throw new RenderingException(e);
}
}
}
We’ll use the Template Method pattern so that users can implement their
own controllers. The central class for this implementation is TemplateController,
which has an abstract doRequest(), as shown in the following code:
JavaExamples/src/main/java/com/mblinn/oo/tinyweb/TemplateController.java
package com.mblinn.oo.tinyweb;
import java.util.List;
import java.util.Map;
try {
Map<String, List<String>> model = doRequest(request);
responseBody = view.render(model);
} catch (ControllerException e) {
responseCode = e.getStatusCode();
} catch (RenderingException e) {
responseCode = 500;
responseBody = "Exception while rendering.";
} catch (Exception e) {
responseCode = 500;
}
return HttpResponse.Builder.newBuilder().body(responseBody)
.responseCode(responseCode).build();
}
protected abstract Map<String, List<String>> doRequest(HttpRequest request);
}
Both the Template Method pattern we used for our controllers and the
Strategy pattern we used for our views support similar tasks. They let some
general code, perhaps in a library or framework, delegate out to another bit
of code intended to perform a specific task. The Template Method pattern
does it using inheritance, while the Strategy pattern does it using composition.
In the functional world, we’ll rely heavily on composition, which also happens
be good practice in the object-oriented world. However, it’ll be a composition
of functions rather than a composition of objects.
Now that we’ve seen all of the pieces of TinyWeb, let’s see how they fit
together.
The TinyWeb class has a single public method, handleRequest(), which takes
HttpRequest. The handleRequest() method then runs the request through the filters,
looks up the appropriate controller to handle it, and returns the resulting
HttpResponse. The code is below:
JavaExamples/src/main/java/com/mblinn/oo/tinyweb/TinyWeb.java
package com.mblinn.oo.tinyweb;
import java.util.List;
import java.util.Map;
if (null == controller)
return null;
return controller.handleRequest(currentRequest);
}
}
A full-featured Java web framework wouldn’t expose a class like this directly
as its framework plumbing. Instead it would use some set of configuration
files and annotations to wire things together. However, we’ll stop adding to
TinyWeb here and move on to an example that uses it.
Using TinyWeb
Let’s implement an example program that takes an HttpRequest with a comma-
separated list of names as its value and returns a body that’s full of friendly
greetings for those names. We’ll also add a filter that logs the path that was
requested.
import com.mblinn.oo.tinyweb.HttpRequest;
import com.mblinn.oo.tinyweb.TemplateController;
import com.mblinn.oo.tinyweb.View;
@Override
public Map<String, List<String>> doRequest(HttpRequest httpRequest) {
Map<String, List<String>> helloModel =
new HashMap<String, List<String>>();
helloModel.put("greetings",
generateGreetings(httpRequest.getBody()));
return helloModel;
}
Next up, let’s take a look at GreetingRenderingStrategy. This class iterates through
the list of friendly greetings generated by the controller and places each into
an <h2> tag. Then it prepends the greetings with an <h1> containing "Friendly
Greetings:", as the following code shows:
JavaExamples/src/main/java/com/mblinn/oo/tinyweb/example/GreetingRenderingStrategy.java
package com.mblinn.oo.tinyweb.example;
import java.util.List;
import java.util.Map;
import com.mblinn.oo.tinyweb.RenderingStrategy;
@Override
public String renderView(Map<String, List<String>> model) {
List<String> greetings = model.get("greetings");
StringBuffer responseBody = new StringBuffer();
responseBody.append("<h1>Friendly Greetings:</h1>\n");
for (String greeting : greetings) {
responseBody.append(
String.format("<h2>%s</h2>\n", greeting));
}
return responseBody.toString();
}
Finally, let’s look at an example filter. The LoggingFilter class just logs out the
path of the request it’s being run on. Its code follows:
JavaExamples/src/main/java/com/mblinn/oo/tinyweb/example/LoggingFilter.java
package com.mblinn.oo.tinyweb.example;
import com.mblinn.oo.tinyweb.Filter;
import com.mblinn.oo.tinyweb.HttpRequest;
@Override
public HttpRequest doFilter(HttpRequest request) {
System.out.println("In Logging Filter - request for path: "
+ request.getPath());
return request;
}
Now that we’ve seen the TinyWeb framework in Java, let’s take a look at how
we’ll use some of the functional replacements for the object-oriented patterns
we’ll explore in this book. This will give us a TinyWeb that’s functionally
equivalent but written with fewer lines of code and in a more declarative,
easier-to-read style.
The biggest change we’ll make is to the view-rendering code. Instead of using
Functional Interface in the form of RenderingStrategy, we’ll use a higher-order
function. We go over this replacement in great detail in Pattern 1, Replacing
Functional Interface, on page 40.
trait View {
def render(model: Map[String, List[String]]): String
}
We start off with our View trait. It defines a single method, render(), which takes
a map representing the data in our model and returns a rendered String.
trait View {
def render(model: Map[String, String]): String
}
Next up, let’s take a look at the body of FunctionView. The code below declares
a class that has a constructor with a single argument, viewRenderer, which sets
an immutable field of the same name.
class FunctionView(viewRenderer: (Map[String, String]) => String) extends View {
«classBody»
}
Next, let’s take a look at the render() method itself. As we can see from the code
below, it takes in a model and runs it through the viewRender() function.
def render(model: Map[String, String]) =
try
viewRenderer(model)
catch {
case e: Exception => throw new RenderingException(e)
}
Notice how there’s no return keyword anywhere in this code snippet? This
illustrates another important aspect of functional programming. In the func-
tional world, we program primarily with expressions. The value of a function
is just the value of the last expression in it.
If we wanted to supply a default value rather than wrap the exception up into
a RenderException, we can do so just by having the appropriate case branch take
on our default, as illustrated in the following code:
try
viewRenderer(model)
catch {
case e: Exception => ""
}
Now when an exception is caught, the try block takes on the value of the
empty string.
In Scala, we rely on function composition just like we did with our views by
passing in a doRequest() function when we create a Controller:
ScalaExamples/src/main/scala/com/mblinn/mbfpp/oo/tinyweb/steptwo/Controller.scala
package com.mblinn.mbfpp.oo.tinyweb.steptwo
import com.mblinn.oo.tinyweb.HttpRequest
import com.mblinn.oo.tinyweb.HttpResponse
import com.mblinn.oo.tinyweb.ControllerException
import com.mblinn.oo.tinyweb.RenderingException
trait Controller {
def handleRequest(httpRequest: HttpRequest): HttpResponse
}
try {
val model = doRequest(request)
responseBody = view.render(model)
} catch {
case e: ControllerException =>
responseCode = e.getStatusCode()
case e: RenderingException =>
responseCode = 500
responseBody = "Exception while rendering."
HttpResponse.Builder.newBuilder()
.body(responseBody).responseCode(responseCode).build()
}
}
This code should look fairly similar to our view code. This is a fairly literal trans-
lation of Java into Scala, but it’s not terribly functional because we’re using the
try-catch as a statement to set the values of responseCode and responseBody.
We’re also reusing our Java HttpRequest and HttpResponse. Scala provides a more
concise way to create these data-carrying classes, called case classes.
Switching over to use the try-catch as a statement, as well as using case
classes, can help cut down on our code significantly.
We can create new HttpRequest and HttpResponse objects easily, as the following
REPL output shows:
scala> val request = HttpRequest(Map("X-Test" -> "Value"), "requestBody", "/test")
request: com.mblinn.mbfpp.oo.tinyweb.stepfour.HttpRequest =
HttpRequest(Map(X-Test -> Value),requestBody,/test)
At first glance, this might seem similar to using a Java class with constructor
arguments, except that we don’t need to use the new keyword. However, in
Pattern 4, Replacing Builder for Immutable Object, on page 62, we dig deeper
and see how Scala’s ability to provide default arguments in a constructor,
the natural immutability of case classes, and the ability to easily create a new
instance of a case class from an existing instance lets them satisfy the intent
of the Builder pattern.
Let’s take a look at our second change. Since a try-catch block in Scala has a
value, we can use it as an expression rather than as a statement. This might
seem a bit odd at first, but the upshot is that we can use the fact that Scala’s
try-catch is an expression to simply have the try-catch block take on the value of
the HttpResponse we’re returning. The code to do so is below:
ScalaExamples/src/main/scala/com/mblinn/mbfpp/oo/tinyweb/stepthree/Controller.scala
package com.mblinn.mbfpp.oo.tinyweb.stepthree
import com.mblinn.oo.tinyweb.ControllerException
import com.mblinn.oo.tinyweb.RenderingException
trait Controller {
def handleRequest(httpRequest: HttpRequest): HttpResponse
}
class FunctionController(view: View, doRequest: (HttpRequest) =>
Map[String, List[String]] ) extends Controller {
def handleRequest(request: HttpRequest): HttpResponse =
try {
val model = doRequest(request)
val responseBody = view.render(model)
HttpResponse(responseBody, 200)
} catch {
case e: ControllerException =>
HttpResponse("", e.getStatusCode)
case e: RenderingException =>
HttpResponse("Exception while rendering.", 500)
case e: Exception =>
HttpResponse("", 500)
}
}
Rather than tracing the values of responseCode and responseBody from the top of
the method through the try block and finally into the HttpResponse, we only
need to look at the appropriate piece of the try block to understand the final
value of the HttpResponse. These changes combine to give us code that’s more
readable and concise.
Tying It Together
Now let’s add in the class that ties it all together, TinyWeb. Like its Java coun-
terpart, TinyWeb is instantiated with a map of Controllers and a map of filters.
Unlike Java, we don’t define a class for filter; we simply use a list of higher-
order functions!
Also like the Java version, the Scala TinyWeb has a single method, handleRequest(),
which takes in an HttpRequest. Instead of returning an HttpResponse directly, we
return an Option[HttpResponse], which gives us a clean way of handling the case
when we can’t find a controller for a particular request. The code for the Scala
TinyWeb is below:
ScalaExamples/src/main/scala/com/mblinn/mbfpp/oo/tinyweb/stepfour/Tinyweb.scala
package com.mblinn.mbfpp.oo.tinyweb.stepfour
class TinyWeb(controllers: Map[String, Controller],
filters: List[(HttpRequest) => HttpRequest]) {
Let’s take a look at it in greater detail starting with the class definition.
class TinyWeb(controllers: Map[String, Controller],
filters: List[(HttpRequest) => HttpRequest]) {
«classBody»
}
Here we’re defining a class that takes two constructor arguments, a map of
controllers and a list of filters. Note the type of the filters argument,
List[(HttpRequest) => HttpRequest]. This says that filters is a list of functions from
HttpRequest to HttpRequest.
Now that we’ve seen the TinyWeb framework, let’s take a look at it in action.
We’ll use the same example from the Java section, returning a list of friendly
greetings. However, since it’s Scala, we can poke at our example in the REPL
as we go. Let’s get started with our view code.
We’ll start by creating a FunctionView and the rendering function we’ll compose
into it. The following code creates this function, which we’ll name greetingViewRen-
derer(), and the FunctionView that goes along with it:
ScalaExamples/src/main/scala/com/mblinn/mbfpp/oo/tinyweb/example/Example.scala
def greetingViewRenderer(model: Map[String, List[String]]) =
"<h1>Friendly Greetings:%s".format(
model
getOrElse("greetings", List[String]())
map(renderGreeting)
mkString ", ")
We’re using a couple of new bits of Scala here. First, we introduce the map()
method, which lets us map a function over all the elements in a sequence
and returns a new sequence. Second, we’re using a bit of syntactic sugar that
Scala provides that allows us to treat any method with a single argument as
an infix operator. The object on the left side of the operator is treated as the
receiver of the method call, and the object on the right is the argument.
This bit of syntax means that we can omit the familiar dot syntax when
working in Scala. For instance, the two usages of map() below are equivalent:
scala> val greetings = List("Hi!", "Hola", "Aloha")
greetings: List[java.lang.String]
scala> greetings.map(renderGreeting)
res0: List[String] = List(<h2>Hi!</h2>, <h2>Hola</h2>, <h2>Aloha</h2>)
Now let’s take a look at our controller code. Here we create the handleGreetingRe-
quest() function to pass into our Controller. As a helper, we use makeGreeting(),
which takes in a name and generates a random friendly greeting.
We can create a function and name it by using Scala’s anonymous function syntax,
assigning the resulting function to a val, like we do in this code snippet:
We can almost always use methods as higher-order functions. For instance, here we
pass both the method and the function version of addOne() into map().
Since method definitions have a cleaner syntax, we use them when we need to define
a function, rather than using the function syntax. When we need to manually convert
a method into a function, we can do so with the underscore operator, as we do in the
following REPL session:
scala> addOneMethod _
res3: Int => Int = <function1>
The need to do this is very rare, though; for the most part Scala is smart enough to
do the conversion automatically.
ScalaExamples/src/main/scala/com/mblinn/mbfpp/oo/tinyweb/example/Example.scala
def handleGreetingRequest(request: HttpRequest) =
Map("greetings" -> request.body.split(",").toList.map(makeGreeting))
Finally, let’s take a look at our logging filter. This function simply writes the
path that it finds in the passed-in HttpRequest to the console and then returns
the path unmodified:
ScalaExamples/src/main/scala/com/mblinn/mbfpp/oo/tinyweb/example/Example.scala
private def loggingFilter(request: HttpRequest) = {
println("In Logging Filter - request for path: %s".format(request.path))
request
}
We can now run the test request through TinyWeb’s handleRequest() method in
the REPL and view the corresponding HttpResponse:
scala> tinyweb.handleRequest(testHttpRequest)
In Logging Filter - request for path: /greeting
res0: Option[com.mblinn.mbfpp.oo.tinyweb.stepfour.HttpResponse] =
Some(HttpResponse(<h1>Friendly Greetings:<h2>Mike</h2>, <h2>Nam</h2>, <h2>John</h2>,
200))
That wraps up our Scala version of TinyWeb. We’ve made a few changes to
the style that we used in our Java version. First, we replaced most of our
iterative code with code that’s more declarative. Second, we’ve replaced our
bulky builders with Scala’s case classes, which give us a built-in way to
handle immutable data. Finally, we’ve replaced our use of Functional Interface
with plain old functions.
Taken together, these small changes save us quite a bit of code and give us
a solution that’s shorter and easier to read. Next up, we’ll take a look at
TinyWeb in Clojure.
The most obvious difference between Clojure and Java is the syntax. It’s very
different than the C-inspired syntax found in most modern programming
languages. This isn’t incidental: the syntax enables one of Clojure’s most
powerful features, macros, which we’ll cover in Pattern 21, Domain-Specific
Language, on page 218.
Like Scala, Clojure has excellent interoperability with existing Java code.
Calling a method on a Java class looks almost exactly like calling a Clojure
function; you just need to prepend the method name with a period and put
it before the class instance rather than after. For instance, this is how we call
the length() method on an instance of a Java String:
=> (.length "Clojure")
7
Instead of organizing Clojure code into objects and methods in Java or into
objects, methods, and functions in Scala, Clojure code is organized into
functions and namespaces. Our Clojure version of TinyWeb is based on
models, views, controllers, and filters, just like the Java and Scala versions;
however, these components will take quite a different form.
Our views, controllers, and filter codes are simply functions, and our models
are maps. To tie everything together, we use a function named TinyWeb,
which takes in all our components and returns a function that takes in an
HTTP request, runs it through the filters, and then routes it to the proper
controller and view.
Controllers in Clojure
Let’s start our look at the Clojure code with the controllers. Below, we implement
a simple controller that takes the body of an incoming HTTP request and uses it
to set a name in a model. For this first iteration, we’ll use the same HttpRequest as
our Java code. We’ll change it to be more idiomatic Clojure later on:
ClojureExamples/src/mbfpp/oo/tinyweb/stepone.clj
(ns mbfpp.oo.tinyweb.stepone
(:import (com.mblinn.oo.tinyweb HttpRequest HttpRequest$Builder)))
(defn test-controller [http-request]
{:name (.getBody http-request)})
(def test-builder (HttpRequest$Builder/newBuilder))
(def test-http-request (.. test-builder (body "Mike") (path "/say-hello") build))
(defn test-controller-with-map [http-request]
{:name (http-request :body)})
Let’s take a look at this code piece by piece, starting with the namespace
declaration.
ClojureExamples/src/mbfpp/oo/tinyweb/stepone.clj
(ns mbfpp.oo.tinyweb.stepone
(:import (com.mblinn.oo.tinyweb HttpRequest HttpRequest$Builder)))
Now let’s take a look at our controller, which takes an HttpRequest from the
original Java solution and produces a Clojure map as a model:
ClojureExamples/src/mbfpp/oo/tinyweb/stepone.clj
(defn test-controller [http-request]
{:name (.getBody http-request)})
Here we call the getBody() method on the HttpRequest to get the body of the
request, and we use it to create a map with a single key-value pair. The key
is the keyword :name, and the value is the String body of the HttpRequest.
Before we move on, let’s look at Clojure maps in greater detail. In Clojure, it’s
common to use maps to pass around data. The syntax for creating a map in
Clojure is to enclose key-value pairs inside curly braces. For instance, here
we’re creating a map with two key-value pairs. The first key is the keyword
:name, and the value is the String "Mike". The second is the keyword :sex, and the
value is another keyword, :male>:
=> {:name "Mike" :sex :male}
{:name "Mike" :sex :male}
Maps in Clojure are functions of their keys. This means that we can call a map
as a function, passing a key we expect to be in the map, and the map will return
the value. If the key isn’t in the map, nil is returned, as the code below shows:
Keywords in Clojure are also functions. When they are passed a map, they
will look themselves up in it, as in the following snippet, which shows the
most common way to look up a value from a map:
=> (def test-map {:name "Mike"})
#'mbfpp.oo.tinyweb.stepone/test-map
=> (:name test-map)
"Mike"
=> (:orange test-map)
nil
Now let’s create some test data. Below, we create an HttpRequest$Builder and use
it to create a new HttpRequest:
ClojureExamples/src/mbfpp/oo/tinyweb/stepone.clj
(def test-builder (HttpRequest$Builder/newBuilder))
(def test-http-request (.. test-builder (body "Mike") (path "/say-hello") build))
This code features two more Clojure/Java interop features. First, the forward
slash lets us call a static method or reference a static variable on a class. So
the snippet (HttpRequest$Builder/newBuilder) is calling the newBuilder() method on the
HttpRequest$Builder class. As another example, we can use this syntax to parse
an integer from a String using the parseInt() method on the Integer class:
=> (Integer/parseInt "42")
42
Next up is the .. macro, a handy interop feature that makes calling a series
of methods on a Java object easy. It works by taking the first argument to ..
and threading it through calls to the rest of the arguments.
The snippet (.. test-builder (body "Mike") (path "/say-hello") build) first calls the body()
method on test-builder with the argument "Mike". Then it takes that result and
calls the path() method on it with the argument "say-hello" and finally calls build()
on that result to return an instance of HttpResult.
Here’s another example of using the .. macro to uppercase the string "mike"
and then take the first character of it:
=> (.. "mike" toUpperCase (substring 0 1))
"M"
Robinsons Tabakspfeife.
Obgleich ich nicht weniger als zwei Jahre mit meinen
Schiffszimmerarbeiten zugebracht hatte, so entsprach doch die
Größe der Barke nicht dem Zwecke, welchen ich bei Erbauung der
ersteren verfolgte, nämlich dem, mit derselben das
gegenüberliegende Festland zu erreichen, welches nach meiner
Schätzung wohl vierzig englische Meilen entfernt lag. Dennoch
empfand ich eine nicht zu beschreibende Freude, als ich mein
selbsterbautes Fahrzeug so sicher und leicht auf den Wellen
dahingleiten sah, und wenn ich auch auf den Wunsch verzichten
mußte, jenes ferne Küstenland zu erreichen, so schien mir mein Boot
doch hinlänglich fest, um in demselben eine Rundreise um mein
Eiland unternehmen zu können. Zu diesem Zwecke pflanzte ich
einen kleinen Mast auf meinen Ruderkahn und brachte ein Segel
zustande, das ich aus mehreren Stück Leinwand
zusammenschneiderte. Ebenso sorgte ich an beiden Seiten für
Kästchen und sonstige Behältnisse, um darin Lebensmittel, Pulver
und Blei aufzubewahren und so gegen den Regen und den Gischt
des Meeres gesichert zu sein. Im Innern des Bootes machte ich der
ganzen Länge nach eine Höhlung, legte meine Flinte hinein und
nagelte zum Schutze gegen die Nässe Leinwand darüber. Außerdem
befestigte ich noch meinen Schirm am Hinterteile der Barke, zum
Schutze gegen die brennenden Sonnenstrahlen, setzte ein
Steuerruder sowie einen Anker in Bereitschaft und versuchte mich
zunächst in kleinen Lustfahrten in der Nähe meiner Besitzung.
Nachdem ich die Tauglichkeit meines Bootes durch solche Ausflüge
auf dem Wasser erprobt hatte, konnte ich doch der Begierde, den
ganzen Umfang meines kleinen Königreichs kennen zu lernen, nicht
länger widerstehen. Ich brachte in mein Kanoe eine hinlängliche
Menge Proviant, nämlich zwei Dutzend Brote oder vielmehr
Gerstenkuchen, einen Topf mit Reis, eine Ziegenhälfte und ein
Fläschchen Rum; auch nahm ich Pulver und Blei mit, sowie zwei
Überröcke, die mir in kühlen Nächten teils als Matratzen, teils als
Decke dienen sollten.
So ausgerüstet begab ich mich am 6. November des sechsten
Jahres meines Insellebens an Bord und stach in See. Indessen sollte
diese Seefahrt eine andre Wendung nehmen, als ich gedacht hatte.
Nachdem ich eine Strecke hinausgefahren und an die östliche Küste
gelangt war, bemerkte ich eine Kette von Felsen, die meilenweit ins
Meer hinausragten und von denen einige Klippen über, andre unter
der Wasserfläche vorschoben. Am Ende des Riffs breitete sich noch
eine Sandbank von einer halben Stunde in derselben Richtung aus,
so daß ich einen großen Umweg zu machen hatte, wenn ich die
Spitze umsegeln wollte.
Diese Entdeckung kam mir sehr ungelegen, und da mir die Fahrt
denn doch etwas gefährlich schien, steuerte ich in meine Bucht
zurück und legte meine Barke vor Anker. Hierauf griff ich zur Flinte,
stieg ans Land und erklomm einen Hügel, von wo ich das ganze
Felsenriff überschauen konnte.
Ich bemerkte eine heftige Strömung, die in der Richtung nach
Osten ganz nahe an der äußersten Spitze der Sandbank hinlief.
Dieser Umstand konnte für mich sehr gefährlich werden; denn wenn
mich der Strom packte und mit sich fortriß, so mußte ich der Insel
vielleicht auf immer lebewohl sagen. Von der Südseite ließ sich ein
ähnlicher Strom in der Richtung nach Ost-Nordost wahrnehmen,
jedoch in einer größeren Entfernung vom Ufer. Dann sah ich eine
ziemlich genau angedeutete Sandbank, die gegen die Küste verlief.
Diesen Beobachtungen zufolge mußte ich meinen Kurs so nahe an
der ersten Sandbank halten, als es ohne Gefahr, zu stranden, irgend
anging.
Ein steifer Wind aus Ost-Südost sauste gerade dem
nordöstlichsten Strom entgegen und drängte das Wasser in heftiger
Brandung an das Riff und die Spitze der Landzunge. Deshalb konnte
ich mich nicht auf das Meer wagen. Wegen der Brandung war es
doch zu gefährlich, mich nahe am Lande zu halten, und die
Strömung legte mir anderseits die Notwendigkeit auf, mich nicht weit
vom Lande zu entfernen. Aus diesem Grunde blieb ich ruhig in
meiner Bucht zwei Tage vor Anker liegen.
Robinsons Nachtruhe.
Achtes Kapitel.
Robinsons unglückliche
Bootfahrt.
Gefährliche Seereise. – In die See hinausgetrieben. – Sehnsuchtsvolle
Betrachtungen. – Die beiden Strömungen und glückliche Landung. – Des Papageis
Ruf. – Robinsons »Familie«. – Ziegenfang und Ziegenpark. – Schneiderkünste. –
Neue Beobachtungen. – Rückblicke.
Am Morgen des dritten Tages legte sich der Wind, das Meer wurde
ruhig, und nun erst begann ich meine Seefahrt. Mein Schicksal möge
unerfahrenen und wagehalsigen Schiffern zur Warnung dienen!
Kaum hatte ich die Spitze der Sandbank erreicht, von dem Ufer nur
um die Länge meiner Barke entfernt, als ein Strom gleich einer
Mühlschleuse mich mit überwältigender Heftigkeit packte. Alle Mühe,
dagegen anzukämpfen, erwies sich als umsonst; immer weiter trieb
mich die Strömung von der Sandbank, die mir zur Linken lag. Weder
Segel noch Ruder konnte ich mit Erfolg gebrauchen. Wurde ich von
der Strömung etwa in die See hinausgeworfen, so schien mein
Untergang unvermeidlich, insbesondere wegen des Mangels an
Lebensmitteln. Denn die am ersten Tage in die Barke geschafften
Vorräte nebst einer noch am Meeresufer von mir gefangenen
Schildkröte konnten nicht ausreichen, wenn ich weit hinaus auf den
unermeßlichen Ozean getrieben wurde, vielleicht viele Meilen von
der Küste entfernt.
Jetzt gedachte ich meiner einsamen und verlassenen Insel, die mir
nun wie ein behaglicher und reizender Ort erschien. »Glückliche
Einöde!« klagte ich, »werde ich dich jemals wiedersehen? Nie wollte
ich dich wieder verlassen!« So erkannte ich, als mir meine Besitzung
schon verloren schien, erst ihren vollen Wert. Ich ruderte aus allen
Kräften und blieb möglichst in derselben Richtung, in welcher die
Strömung die Sandbank treffen konnte. Plötzlich erhob sich ein
Welcome to Our Bookstore - The Ultimate Destination for Book Lovers
Are you passionate about books and eager to explore new worlds of
knowledge? At our website, we offer a vast collection of books that
cater to every interest and age group. From classic literature to
specialized publications, self-help books, and children’s stories, we
have it all! Each book is a gateway to new adventures, helping you
expand your knowledge and nourish your soul
Experience Convenient and Enjoyable Book Shopping Our website is more
than just an online bookstore—it’s a bridge connecting readers to the
timeless values of culture and wisdom. With a sleek and user-friendly
interface and a smart search system, you can find your favorite books
quickly and easily. Enjoy special promotions, fast home delivery, and
a seamless shopping experience that saves you time and enhances your
love for reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
ebookgate.com