function(groovy) #1
If all you have is a hammer, everything looks like a nail.
Abstract: If my Groovy
builder code is described as declarative then why is the remainder of my code
not declarative? If declarative programming means I can put more emphasis on
what I wish to achieve and less emphasis on how it is achieved then I should
follow this principle throughout all my code. But I don't. Why not?
Ken Barclay
kenbarc@googlemail.com
Introduction
In this series of blogs I describe my experience of
fusing a functional programming style with the object oriented features of
Groovy. Incorporating functional programming constructs into Groovy arose from
a disappointing experience I had when developing a range of applications originally
intended to showcase some of Groovy's great features.
The applications had two major features in common.
They all processed information from web services and they all presented that
data in a GUI. For example applications might obtain meteorological data from
Google's weather service, financial data from Yahoo, photographs from Flickr,
videos from Youtube, or music data from iTunes. GUIs allowed the user to
interact with that data.
Groovy's builder
technology was an obvious choice for developing the UIs. Initially SwingBuilder was adopted, but later a
custom FXBuilder was developed so I
could leverage the richer components of JavaFX. Either way, the satisfaction of
adopting a Groovy builder is the declarative
nature of the resulting code. Declarative code places more emphasis on the what rather than the how. Example 1.1 reminds us how this
would appear.
Example
1.1: GUI builder
def
mainStage = builder.stage(title: "Example 01", x: 100, y: 100, width:
400, height: 300) {
scene(stylesheets:
"file:///C:/css/glib.css") {
borderPane() {
top(alignment: CENTER, margin: [10.0,
10.0, 10.0, 10.0]) {
text(text: 'Example 01', id: 'text20')
}
center(margin: [10.0, 10.0, 10.0, 10.0])
{
gridPane(hgap: 4, vgap: 4) {
text(text: 'Please enter your name:',
id: 'text16')
textField(ID: 'locationTF', text: '',
onAction: controller.onName)
// ...
}
}
bottom(alignment: CENTER, margin: [10.0,
10.0, 10.0, 10.0]) {
button(text: 'Close', onAction:
controller.onClose)
}
}
}
}
In Example 1.1 factory
methods, such as button and textField, are used to define the
JavaFX components while nested closures
define the structure and hence the appearance of the UI. The factory method
calls are decorated with named parameters
that set the various properties on the components. The builder aims to do as
much of the heavy lifting, reducing the effort required by the developer. For
example, the builder translates the factory method calls and their parameters
into code that creates and initializes the components. The builder also
arranges for the UI components defined in a closure to be added as child
components of the enclosing container component.
That was the good part. What followed was the
disappointment. The applications were completed by developing the supporting
classes. They were anything but declarative, especially the method bodies that were
assembled from the usual control flow statements. If statements within while
statements and for statements within switch statements. I never thought of
myself as a sloppy programmer but the implementation of these methods seemed to
stand in sharp contrast with the declarative builder code.
Decomposing complex methods and providing private
support methods or other support classes helped a little but still the code had
a smell about it. I seemed to be operating at too low a level of abstraction
when compared with Groovy's builders. Interestingly the implementation for the Groovy
builders were themselves not especially declarative. Hmmm!
Using a search engine for declarative programming
picked out many interesting articles often with attempts at informal
definitions. Usually the what versus the how was cited. Declarative systems
such as Yacc and SQL were compared to imperative programming languages. Maybe
an imperative language like Groovy is not expected to be declarative because
the programmer has to spell out the actions and their order.
When looking for actual illustrations most articles
referred the reader to functional programming. Some characterized functional
programming languages as examples of declarative programming along with logic
programming languages and constraint programming languages.
So what is it that makes these languages
declarative and what lessons might be learnt? The builder code above gives some
pointers. First, state does not seem to play a major part in this code. There
is state in the code. The named parameters on the factory method calls are
initializing the state properties of the UI components. But, significantly, there is
no explicit state transitions.
Second, there are no binding of results to
variables. The builder code is like a single expression which, at the top
level, delivers a Stage object.
Expressions in the sub-levels deliver the various sub-components that form the
UI. The sub-expressions are used to support assembly of the enclosing
expression.
Perhaps then I should aim to make my Groovy coding
much less dependent on state and state transitions. What place then for my use
of control flow such as if statements and for loops? Usually they manipulate
some state. Perhaps finding a solution for this will address my concern that I
was operating at too low a level of abstraction.
All this may seem at odds with an imperative
programming language such as Groovy. However, I can see immediately that if I
have less state transitions I will have less testing to do since a significant
part of testing is to ensure the transitions are correct.
What other aspects of functional programming might
make a contribution to a more declarative style. What contribution might
Groovy's closures make? How will my use of control flow statements such as for
loops change? What can be done to reduce my use of state? Let's see where this
takes us...
No comments:
Post a Comment