

Show HN: Motif – Scala-like pattern matching with Java 8 - johnlcox
https://github.com/johnlcox/motif

======
qqueue
The Cambrian explosion of java 8 functional libraries like this is fun to
watch. Others I've come across:

\- [http://javaslang.com/](http://javaslang.com/)

\- [https://github.com/aol/cyclops](https://github.com/aol/cyclops)

\- [http://totallylazy.com/](http://totallylazy.com/)

\- [https://github.com/poetix/octarine](https://github.com/poetix/octarine)

\- (good ol') [http://www.functionaljava.org/](http://www.functionaljava.org/)

The syntax for these libraries is always a little wonky though. If only these
libraries also had some sort of syntax preprocessor to make it more palatable.
You could call it, I don't know, Scala, or something.

~~~
bwanab
Exactly. I want to like these things, but they're just way to painful on the
eyes.

~~~
dangerlibrary
whoosh?

[http://www.scala-lang.org/](http://www.scala-lang.org/)

~~~
incepted
He said he wanted something that's not painful on the eyes.

~~~
emergentcypher
I hardly see how Scala is more painful on the eyes than good old Java.

~~~
incepted
Random example from a popular project:

    
    
         def bimap[C, X[_, _], D](g: Bijection[C, D])(implicit F: Bifunctor[X], evF: F[B] =:= Id[B], evG: G[A] =:= Id[A]): Bijection[X[A, C], X[B, D]] =
            bijection(
              F.bimap(_)(to(_), g.to(_)): Id[X[B, D]]
            , F.bimap(_)(from(_), g.from(_)): Id[X[A, C]]
            )

~~~
emergentcypher
And I could cherry pick something just as hideous out of Java. Congrats.

~~~
incepted
Nobody disputed that but that's off topic. We're discussing the fact that
Scala can be pretty ugly too.

------
stormcrowsx
Hard to read in comparison to Scala. It's impressive that it was accomplished
but some things just aren't meant to happen in Java 8.

~~~
leothekim
If you've ever endured the compilation time of a Scala codebase that has more
than, say, 2000+ classes, then you might think that some things just aren't
meant to happen in Scala either.

I used Scala for 4+ years at a company that spent a non-trivial amount of time
and resources speeding up its Scala builds (way more than 2000+ classes),
sometimes doing sadly controversial things[1] to achieve that speedup. It was
a real quality-of-life issue, and one of the reasons that compelled me to
leave.

I'm using Java 8 now, and yes it has its warts and is nowhere near Scala wrt
functional goodness, but I'm glad to be compiling and iterating a lot more
quickly with the ability to use even a subset of the Scala stuff I missed.

[1] [https://groups.google.com/d/msg/pants-
devel/mcdllXQsYNg/96ZG...](https://groups.google.com/d/msg/pants-
devel/mcdllXQsYNg/96ZGYu2fT0MJ)

~~~
leothekim
As a point of reference, compiling ~200 Scala classes at a time would take
~2.5 minutes on average. At my last job, compiling >2000 Java classes took
about 10-15 seconds with an ant script doing a top-down build. Unfortunately I
don't remember LOC, but I don't remember the average Scala file being overly
large at my Scala job, or the average Java file being unusually short at my
Java job.

~~~
AdieuToLogic
> As a point of reference, compiling ~200 Scala classes at a time would take
> ~2.5 minutes on average.

Odd... I just did a full compile of a Scala project I work on which has:

\- 259 source files

\- Contains dozens of macros[1]

\- Results in 2097 classes (includes companion objects and anonymous types)

And it took 75 seconds on my laptop. As I mentioned in another reply, doing a
full recompile is rarely needed but was done now to provide quantified
metrics.

1 - [http://docs.scala-
lang.org/overviews/macros/overview.html](http://docs.scala-
lang.org/overviews/macros/overview.html)

~~~
leothekim
In Java, I compile around 250 classes in about 6 seconds on my laptop. It
results in around 250 class files being generated because no filea for
anonymous inner classes are created from the lambdas in the code. I don't need
a full recompile either. An incremental compile in Java is measured in
milliseconds. IntelliJ is usable to its fullest instead of being a fancy
editor that just autocompletes and jumps to symbol definitions.

You may not be using all of scala's language features. I'm using java's
features to the fullest. I compile in 6 seconds. You compile in 75 seconds.
You may still prefer that trade off. After working with thousands of scala
files (you have 259 source files? That's cute! I wish I could pinch your
cheeks!) where a 75 second compile sounds like a fail-fast error, I think I
will live happier with what Java 8 has, limited and warted though it may be.

~~~
AdieuToLogic
You have no idea my background, how I use Scala, and assume that the small
project I reference is the only project I _could_ reference. It was chosen due
to being near the size of the situation you describe as "compiling ~200 Scala
classes at a time would take ~2.5 minutes."

Being a condescending asshole doesn't help you communicate with others.
Frankly, it strengthens my opinion that you don't know how to organize a
medium-sized project, since being able to do so obviates requiring to compile
2000+ files for each build _in any language_.

------
subtenante
Funny, I happened to code something just today very similar, but a lot lighter
(just two classes, Match for consuming only, and MatchMap for mapping the
optional. No when/get, just a when taking two parameters : the predicate and
the mapping function.

    
    
      public class MatchMap<T, U> {
    
        private final Optional<T> opt;
        private final U defaultValue;
        private final AtomicReference<U> result = new AtomicReference<U>();
    
        private MatchMap(Optional<T> pOpt, U pDefault) {
            super();
            opt = pOpt;
            defaultValue = pDefault;
        }
    
        public MatchMap<T, U> whenMatch(Predicate<T> pPred, Function<T, U> pMapFn) {
            if (result.get() != null) {
                return this;
            }
            Optional<T> lFiltered = opt.filter(pPred);
            if (lFiltered.isPresent()) {
                result.set(pMapFn.apply(lFiltered.get()));
            }
            return this;
        }
    
        public MatchMap<T, U> whenEquals(T pExact, Function<T, U> pMapFn) {
            return whenMatch(t -> pExact.equals(t), pMapFn);
        }
    
        public U resolve() {
            return Optional.ofNullable(result.get())
              .orElse(defaultValue);
        }
    
        public static <T, U> MatchMap<T, U> of (Optional<T> pOpt, U pDefault) {
            return new MatchMap<T, U>(pOpt, pDefault);
        }
    
      }
    

The class Match is very similar, but takes consumer instead of Function and
has some logic to allow several matches to be executed (if several predicates
are ok), or only allow the first match to be executed.

~~~
nittpicker
You can simplify your code a little bit and add some wildcards :)

[https://gist.github.com/anonymous/7d45e0f746b46684ec45](https://gist.github.com/anonymous/7d45e0f746b46684ec45)

~~~
subtenante
Indeed, thanks!

------
jlebrech
[https://en.wikipedia.org/wiki/Motif_(software)](https://en.wikipedia.org/wiki/Motif_\(software\))

------
ch_123
The javaslang library has a similar construct:

[http://javaslang.com/javadoc/1.2.0/javaslang/control/Match.h...](http://javaslang.com/javadoc/1.2.0/javaslang/control/Match.html)

