Pattern Matching, Averaging Run Times, BFG
CodeFX Occasionally #73 — 16th of June 2019
Hi everyone,
and a good Sunday evening! ☀️ Around here it is indeed sunny and I had a great time yesterday evening hanging out by the Rhine, enjoying good company and a nice sunset. Small complication: tons of mosquitoes. My family took to counting the bites today and we ended up at about 135. 😲
Anyways, here’s a little read on how pattern matching will show up in Java, what to do when you need to run a command a few times and average its run time, as well as a new Project of the Week — a segment I’ve renamed since it’s not even close to being weekly anymore.
I send this newsletter out some Fridays. Or other days. Sometimes not for weeks. But as an actual email. So, subscribe!
Uses of pattern matching
At FOSDEM 2019, Brian Goetz gave a talk Java Language Futures, one of his recurring peaks into how Java will change over the next years, and there were a few uses for pattern matching that I found quite interesting. I’ll present them here, but first I want to point out that while this kind of pattern matching will be usable by switch expressions, they are not identical to it and, as you will see next, have a life of their own.
Phase 1: Type patterns in instanceof
(JEP 305)
In the first phase, patterns will combine a condition, an extraction, and an assignment into one operation. Instead of this …
if (obj instanceof Integer) {
int intValue = ((Integer) obj).intValue();
// use `intValue`
}
… we’ll be able to write this …
if (obj instanceof Integer intValue) {
// use `intValue`
}
Brian says that “this simple thing will eliminate almost 100% of the casts in Java code, so that’s pretty nice”. I agree. 😁
Another neat aspect is that a variable that is declared with instanceof
will be available immediately, so you can use it throughout the rest of the expression. Think of a typical equals
implementation:
@Override
public final boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Employee))
return false;
Employee employee = (Employee) o;
return firstName.equals(employee.firstName)
&& lastName.equals(employee.lastName);
}
Although the use of instanceof
is not actually that typical and requires equals
to be final - a detail Brian himself omitted from the slides. Anyway, with a pimped instanceof
that could be much simpler:
@Override
public final boolean equals(Object o) {
return this == o
|| (o instanceof Employee employee)
&& firstName.equals(employee.firstName)
&& lastName.equals(employee.lastName);
}
Requires you to know operator precedence for ||
and &&
, but is otherwise much clearer and shorter.
Phase 2: Type patterns in switch
This one has already been presented several times with regards to switch expressions and their use of patterns in case
labels. It's pretty straightforward: Because case
doesn't understand types, even after phase 1 you would have to write code like this:
Object value = // ...
String formatted = "unknown";
if (value instanceof Integer i)
formatted = String.format("int %d", i);
else if (value instanceof Byte b)
formatted = String.format("byte %d", b);
else if (value instanceof Long l)
formatted = String.format("long %d", l);
else if (value instanceof Double d)
formatted = String.format("double %f", d);
else if (value instanceof String s)
formatted = String.format("string %s", s);
Taking switch expressions and upgrading their case labels to understand types lets you write this instead:
Object value = // ...
String formatted = switch (value) {
case Integer i -> String.format("int %d", i);
case Byte b -> String.format("byte %d", b);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> "unknown " + value.toString();
};
Much clearer!
Phase 3: Deconstruction patterns in switch
In this talk, Brian only alluded to deconstruction, and while he mentioned that it may follow the first two phases, this is no fixed plan. Heck, only phase one even has a JEP, so none of this is set in stone. Anyways, because he explained deconstruction elsewhere, I’m gonna continue with it here.
Imagine the JVM knew how to take a specific kind of object, let’s call it a record, apart into it’s constituting fields. For example it knows that, in a simple expression tree API, the Node
implementation IntNode
has an int
field (it represents a number in an arithmetic expression). NegNode
has another Node
as a field (it negates that node's result) and AddNode
has two Node
fields (it adds their results).
Then you could evaluate such a tree as follows:
public int eval(Node n) {
return switch(n) {
case IntNode(int i) -> i;
case NegNode(Node n) -> -eval(n);
case AddNode(Node left, Node right) ->
eval(left) + eval(right);
};
}
Of course this looks like a case for simply defining an eval
method on Node
and implementing it in IntNode
, NegNode
, and AddNode
, but you get the point: A pattern that can deconstruct instances of certain types can lead to very expressive, i.e. clear and concise, code. I really like it!
Averaging run times
When experimenting with application class-data sharing, which speeds up JVM starts, I wanted to measure the time it takes to launch the application. On Linux, time
is there for you. It's pretty crude to just take the time once and be done with it, though, so I wanted to at least launch it a few times and take the average. But how? Manually?! Flower that! (Family told me I swear too much - guess what "flower" stands for...)
Luckily, StackOverflow was there for me:
#!/bin/bashrm -f /tmp/mtime.$$for x in {1..10}
do
/usr/bin/time -f "real %e user %U sys %S" -a -o /tmp/mtime.$$ $@
tail -1 /tmp/mtime.$$
doneawk '{ et += $2; ut += $4; st += $6; count++ } END {
printf "Average:\nreal %.3f user %.3f sys %.3f\n",
et/count, ut/count, st/count }' /tmp/mtime.$$
Put that into a script, maybe add a parameter for the number of repetitions and there you go: Repeat the same commend 10 (or n
) times and see the average results of time
.
Project showcase: BFG Repo Cleaner
The BFG is a simpler, faster alternative to git-filter-branch for cleansing bad data out of your Git repository history:
* Removing Crazy Big Files
* Removing Passwords, Credentials & other Private dataThe git-filter-branch command is enormously powerful and can do things that the BFG can’t — but the BFG is much better for the tasks above, because:
* Faster : 10–720x faster
* Simpler : The BFG isn’t particularily clever, but is focused on making the above tasks easy
* Beautiful : If you need to, you can use the beautiful Scala language to customise the BFG. Which has got to be better than Bash scripting at least some of the time.
At Disy we moved from Subversion to Git some time ago, and BFG came in really handy to kick a few of those accidentally committed heap dumps out of 15 years of Subversion history. Recommended.
What I’ve been up to
Nothing that’s publicly visible. Yet. I spend most of the week putting together Accento’s proper site. The thing you see now is just a Save the date page that we put up as quickly as possible. The proper site will of course show talk abstracts, training summaries, speaker profiles, and whatnot. You know, why not just show you? Here’s a super-secret nothing-is-final please-don’t-share-because-URL-will-change preview: <redacted for Medium repost>.
(I’ve put this together with Gatsby.js, which was very interesting and a lot of fun. I’ll continue working on it on stream over the next week, but I don’t know the dates yet. Check out Twitch on Monday morning to see the new schedule if you want to hang out.)
The other thing I did, and you’re not gonna believe this, was go through the final PDF for The Java Module System before it goes to print. It should be at the printer as we speak, which means it’ll be another three to five weeks before a box of them arrive at my door step. I assume deliveries will start around the same time, so those of you who MEAP’ed a copy, should get their dead-tree version soonish. Thank you very much for your patience, I do not deserve it. 😔
Long Shots
- 7 absolute truths I unlearned as junior developer
- This Deepfake of Mark Zuckerberg Tests Facebook’s Fake Video Policies
- A thread for those of you who say coders and developers should take no role in politics
so long … Nicolai
PS: Don’t forget to subscribe or recommend! :)
