Go for Java developers (lambda functions to the rescue)

As you might already know from this post, I've recently started programming in Go, so quite often the first question which pops up in my mind is: How would I do it in Java?

I am not sure if it's good or not, but I find somehow beneficial for me to look at the same thing from multiple perspectives. It is not about using Go or Java, using functional or imperative style, it's in mixing different concepts in which I see the real value.

Similarly to the other post, in this one I'll document how looking at the problem from a different angle shaped the solution.

The problem

I am going to simply a bit the task to highlight the interesting bit in this post. Part of the task involved loading in memory a section of a file: a super simple parser.

We are interested in two keys which belong to a section.
The section starts with an header, which begins with an hashtag.
We are given the name of the section and the name of two keys.
i.e. section: "person", keys : ["name", "surname"]
So we want to find the "person "section in the file and load the values for name and surname in memory.

Couples of gotchas about the file:

The Header might not be in the file

name and/or surname might not be present in the file

name always precedes surname in the file

It might contain comments (//) or other markers

One of the possible solution is simply to read the file line by line and:

if the line starts with # then this is the beginning of a section, prepare to read the key pair for this header

Read name and surname

Ignore comments and the rest of the keys

So, let's put on for a second the hat of a Java programmer here.

So reading a file, line by line, filtering some lines…

Alright this looks like a job for java.nio.file.Files, a java.util.stream.Stream and a custom java.util.function.Predicate to filter the stream.
I say custom, meaning that we need to keep some state within our predicate.
The state is simply what string the predicate should match next time it is called, i.e. if it already matched the header then should match name next.

This basically means two things: Stream and Lambda functions.

Let's make it short, there is no such a thing like a stream in Golang.
Let me make a little diversion here, the whole point of this mental exercise is not implementing something which goes against the language itself, but get the best out of it. So no stream. We are going to live without it, for loops to the rescue.

But what about lambdas?
Well, functions in Go are first class citizen. We can assign them to variables, create array of functions, pass them around like any other argument, so I guess we have our lambdas :)

Ok enough talk, let's see the code…
Wait before looking at the code, let's recap what we want to do.
So we expect to have a for loop in which we read the content from a source line by line and for each line we check if it should be written somewhere.
The bit which checks if the line should be written is a filter, which internally keeps a state.

This is the constructor of profileFilter, responsible to detect the header of the section and the keys. It's basically an array of functions or lambdas if you will. Every time the filter matches a line in the file, we pop an element from the array, so in the next iteration the filter is going to match on a different string.
What I really like from this code is the way we construct the lambdas:

matcher(startsWith).apply("name=")

So we are building a matcher which matches a line that startsWith "name="
What's really a matcher?

typematcherfunc(linestring,toMatchstring)bool

It's a type alias for a function. So it's just a function which gets as input a line and the string to match and return a boolean. That's it.
The syntax matcher(startsWith) is just a cast, we are casting the function startsWith to a matcher. Sure enough we can do that, since matcher is a function!

when I wrote that, I was like...well, functions in go are pretty damn cool

It's just a way to curry the function. Long story short, we have a function of two arguments, and we really want a function with one argument in which the other one is already set.

So here, we apply the string we want to match, like "name=" and we get back a function which has as parameter only the line.
We attached the apply method to the matcher, so the end result is that by calling:

matcher(startsWith).apply("name=")

We get back a function which returns a boolean (a Predicate in java land) which is going to be true if the line starts with name.

The two versions are obviously really similar, except for the fact that in the java version I use stream instead of the for loop and I print the lines on the console instead of writing it to a Writer.

A side note here: Stream are really cool, but they do not get along with Exceptions. Writing to a File for example is one of those operations which throws an exception, so in a real use case I think I would either use a for loop instead of a stream or RxJava Observable.

Conclusions

All right, this turned out to be longer than I expected, considering I wanted just to say that probably Golang isn't that bad XD.
Joke aside, hope you liked it.

Great job. However I'm curious about one thing. Why does the match need to modify the internal matchers state? If you call it 2 times with the same reference object and text it will return different results. For example

So yes it modifies the internal state. The idea is to keep a state within the profileFilter so it matches the header, name and surname in the order.
i.e. after matching the header, the filter must transition in a state in which is going to match 'name' next, and so on.
It has side side effects.

We can transform it in a pure function(no side effects) by passing the filter state itself as additional argument.