Live data from Hacker News

Pattern Matching for Java

cr.openjdk.java.net

131–140 of 152 posts

Re: Pattern Matching for Java

#131
post #94

Earlier quoted context omitted.

> I've found the DLR is just as fast... with a much lower overhead Can you expand on this? I would not have expected that it would be faster than compiled expressions.

The codegen creates a cache of delegates (created using expression trees), but uses a structure more suited to the problem than a simple ConcurrentDictionary. [1]: http://geekswithblogs.net/simonc/archive/2012/07/20/inside-t...

Ah, faster than the `ConcurrentDictionary`. That makes sense!

Re: Pattern Matching for Java

#132
post #29

Would be really great to see this make it's way into the language. Here are some ways I've found to work around its absence: * adding a match() function to a common base type. So if it could have subtypes Foo(x), Bar(y, z), then the signature would look like: T match(Function foo, BiFunction bar); * in the cases where I don't have control over the common base type, I've written a builder pattern that constructs a seq…

Just use another language if you want pattern matching so badly. Twisting Java to look like Scala doesn't do the language justice.

It's not so easy to just choose another language; there might be hundreds of thousands of lines of Java already written. In that case it's better make the best of a bad situation by doing something like this, than not even trying.

Re: Pattern Matching for Java

#133

Earlier quoted context omitted.

would you be able to give me a pseudo code example of things that are easy to do with pattern matching, but not multiple dispatch? I'm intrigued, I always considered them equivalent.

Here's some concrete examples in Rust: http://pzol.github.io/getting_rusty/posts/20140417_destructu... It's not just about finding the right bit of code to run; it's also about pulling some fields out of the polymorphic value so they're available as nice short names, without qualification.

I suppose languages from the ML family, and rust, haskell etc are somewhat oriented around nested structures of algebraic types that you want to destructure to pull out little atoms of data out of from some well-defined node. But that's orthogonal to the OO approach, where once all the little atoms of data are sealed up in their protective casing of an object you don't want to deal with them anymore.

C# is a weird beast though - it's pure OO on some level, but then keeps making getters and setters even easier to write. It's easier to write an "object" where every field has a getter and setter, than it is to write an actual constructor for private variables, so that's what people do.

Re: Pattern Matching for Java

#134

Why the fixation on pattern matching? Don't get me wrong, I enjoy the benefit it provides, but for OO code multiple dispatch is a more elegant and idiomatic way to solve the "I don't want to implement the visitor pattern" problem. FYI, I recently found out that C# can actually do multiple dispatch https://blogs.msdn.microsoft.com/shawnhar/2011/04/05/visitor...

To me it seems pattern matching without possibility to actually enforce that all cases are matched seems to miss the most useful scenario: What I want to do is create proper sum types. For some reason most OO languages were designed around the idea that being "open for extension" was a good thing. Normally if I make a base class, I want a closed and known set of sub classes. E.g. if I make a payment method then I wan…

In the C# example in the code I posted, all cases are matched. If you add a new animal subclass, that's not "explicitly" handled, it will route to the default (Animal, Animal) method.

It's equivalent of

    _ -> default_function
At the end of a pattern matching statement.

Essentially it's impossible for not all the cases to be matched, as far as I can see.

Re: Pattern Matching for Java

#135

Earlier quoted context omitted.

Why does multiple dispatch bring type unsafe dynamism or runtime errors? Or do you just mean C#'s implementation of multiple dispatch?

Yep, there is no way to check the exhaustiveness in the compile time. Say you have an Expression parent class and a list of child classes: say Add, Const, Var, and a corresponding visitor. Add new child class, and the visitor would be non-exhaustive. Multiple dispatch is not very different in that sense. I think that Alan Key spoke about dynamic nature of OOP, that's one of the examples. Even in the statically typed…

I'm lost here. Either people didn't read the article and are just relying on preconceived notions about what stuff can and can't happen with multiple dispatch, or I am missing something blindingly obvious. Anyway, consider this example:

    class Expression {}
    class Add : Expression {}
    class Const : Expression {}
    class Var : Expression {}

    void FSpecialization(Expression e1, Expression e2) { ... }
    void FSpecialization(Const c, Var v) { ... }

    ...

    void F(Expression e1, Expression e2)
    {
        FSpecialization(e1 as dynamic, e2 as dynamic);
    }
How is this not exhausted? Any new sub class of expression will be routed through to the first FSpecialization. Same as it would with a

    _ -> default_f
in algebraic pattern matching.

Re: Pattern Matching for Java

#136
post #88

Earlier quoted context omitted.

A dynamic type is probably just implemented as a tagged bit of data, surely. Which is the exact same way an algebraic datatype would be done. So I dunno why it would be any slower. I think the safety thing is a non issue as well - what arguments could you pass in to the statically typed function that would cause the use of dynamic to bite you in the ass?

> I think the safety thing is a non issue as well - what arguments could you pass in to the statically typed function that would cause the use of dynamic to bite you in the ass? None if the function is written correctly, but by that logic you don't need type safety at all. The point is that the dynamic technique gives you no warning if you forget to implement one of the cases.

My point was that the dynamic technique in the posted code was written in a very small, contained point where it would be impossible due to the signature of the surrounding argument for it to go wrong.

    void React(Animal me, Animal other) 
    { 
        ReactSpecialization(me as dynamic, other as dynamic); 
    }
Unless you pass in a casted value here, it's fool proof.

Re: Pattern Matching for Java

#137

Earlier quoted context omitted.

I am talking about what value you could pass into the multiple dispatch code in the article I linked to. I know you can cause run time type errors using dynamic in general, but in the code I linked it was very well contained and water tight. Dynamically typed languages usually represent objects as something like a struct with an int tag to represent the type, and a void pointer for its value. The actual reflection go…

> I am talking about what value you could pass into the multiple dispatch code in the article I linked to Ah, I misunderstood the question. Yes, in that case it's fairly type-safe. > The actual reflection going on in the code I posted for multiple dispatch would surely be nothing more than an int comparison Is this based on gut reaction or are you talking about optimizations that `dynamic` performs? I ask because my…

Base classes already have to carry their runtime type with them anyway. As do nodes of an algebraic data type. You may well be right that the compiler might not be "sufficiently smart" to see this very limited use of dynamic and realise no special reflection magic is actually required. But considering dynamic is only used to actually pull out the runtime type in the example code, and not to call arbitrary methods on it that may or not be there, I assumed - maybe wrongly - that the runtime hit would be the same as the branching that occurs in Ocaml or Haskell or F# when it comes across a "match" statement.

But to answer your question - yes, entirely based on gut reaction and what a compiler would ideally be able to do given the code posted. So very probably wrong.

Re: Pattern Matching for Java

#138
post #121

Earlier quoted context omitted.

That's not the important/valuable use case for what people normally refer to as "pattern matching".

I've recently found dynamic pattern matching pretty valuable to completely replace REST-like server-side APIs with a data-oriented API that gets pattern matched and dispatched based on the actual values and shapes of the data structure. It helps almost completely avoid the /get/this /get/that /set/those explosion of API getters and setters that ultimately leads to very complex client logic that makes any notion of co…

I really don't think you're talking about pattern matching in the usual sense. So it's probably better to use a different term.

Re: Pattern Matching for Java

#139
post #88

Earlier quoted context omitted.

> I think the safety thing is a non issue as well - what arguments could you pass in to the statically typed function that would cause the use of dynamic to bite you in the ass? None if the function is written correctly, but by that logic you don't need type safety at all. The point is that the dynamic technique gives you no warning if you forget to implement one of the cases.

My point was that the dynamic technique in the posted code was written in a very small, contained point where it would be impossible due to the signature of the surrounding argument for it to go wrong. void React(Animal me, Animal other) { ReactSpecialization(me as dynamic, other as dynamic); } Unless you pass in a casted value here, it's fool proof.

The point is that if you forget to write one of the ReactSpecialization methods nothing detects it. Perhaps more importantly, if you add a new type of Animal there's nothing to tell you you need to write a bunch of new ReactSpecializations.

Re: Pattern Matching for Java

#140
post #139

Earlier quoted context omitted.

My point was that the dynamic technique in the posted code was written in a very small, contained point where it would be impossible due to the signature of the surrounding argument for it to go wrong. void React(Animal me, Animal other) { ReactSpecialization(me as dynamic, other as dynamic); } Unless you pass in a casted value here, it's fool proof.

The point is that if you forget to write one of the ReactSpecialization methods nothing detects it. Perhaps more importantly, if you add a new type of Animal there's nothing to tell you you need to write a bunch of new ReactSpecializations.

Aha! There's the crux of an argument. It's a valid point actually, that ties into the expression problem.

As an OO apologist I do feel compelled to point out that

    type Animal = Cat | Dog | Mouse

    let react = function (a, b)
    | Cat, Dog -> ...

    ...

    | x, y -> $"{x} is not interested in {y}."
Would suffer from the exact same issue though.
Post reply on HN