Announcing Derive4J, FP-focused annotation processor with special support for FJ

114 views
Skip to first unread message

jbgir...@gmail.com

unread,
Oct 17, 2015, 10:53:11 AM10/17/15
to functio...@googlegroups.com
Hi functional java programmers!

A new projectI have been working on lately, to facilitate functional programming in Java: https://github.com/derive4j/derive4j

Feedback welcomes! (in particular I would be very grateful if someone could cross-check the FP terminology used in the readme).

Cheers.

Jb

Grégoire Neuville

unread,
Oct 22, 2015, 6:45:35 PM10/22/15
to Functional Java
Hi Jean-Baptiste,

Beau boulot ! I've tried it out and I like it very much. As a matter of
fact, I've been thinking about making something like this for quite a
while since I read this very nice article (that you could add to your README by
the way) ; alas, I never found the time and energy to actually do it so
I'm most grateful you did !

I still have a few remarks to make about your work, if you don't mind :

 - the first one is minor, but I didn't understand why the pattern-match
   syntax returns a function. For instance, following up the 'Request'
   example, the 'getPath' method is implemented that way :
  
     public static String getPath(Request request) {
       return Requests.cases()
         .GET(path          -> path)
         .DELETE(path       -> path)
         .PUT((path, body)  -> path)
         .POST((path, body) -> path)
         .apply(request);
     }
  
   However, given the 'match' method is defined on 'request', something
   like the following would have seemed more obvious to me :
  
     public static String getPath(Request request) {
       return reques.match(Requests.cases()
         .GET(path          -> path)
         .DELETE(path       -> path)
         .PUT((path, body)  -> path)
         .POST((path, body) -> path));
     }
  
   But again, this is just a detail.
  
 - the second one is much more important in my opinion : indeed, your
   claim that the pattern-matching machinery generated by derive4j is
   exhaustive is unfortunately untrue : in the 'Request' example, anyone
   anywhere could extend the Request class, addind further cases to the
   original algebra in an unconstrainable way ! Something like the
   'sealed' keyword in Scala is missing. But, as you most certainly
   know, the functionaljava guys discovered a way to emulate this in
   Java : just declare a private default constructor in your abstract
   class. I thus propose the following modifications to be made to
   derive4j :
  
     * require that the 'template' class name is suffixed by '_ADT'
       ex :
       @Data
       class Request_ADT {...}
    
     * if possible, require that this class is declared final (compile
       time error otherwise)
    
     * in the 'Requests' file generated by derive4j, declare the actual
       basis of the ADT
       ex :
       public static abstract class Request {
         private Request() {} // sealed !
        
         private static final class GET extends Request {...}
         private static final class DELETE extends Request {...}
         etc...
       }
    
       The average Java Joe  - that I once was - is then conveniently
       fucked : what can he possibly do with his brand new 'Request'
       type ? Just use the available constructors and pattern match on
       them, but certainly not extend it in some bizarroid and nasty
       way...
  
 - the third one is a little caprice : would it be possible to
   benefit from some curried version of the '*Matcher' SAM
   types alongside the existing ones ?
   So that we can write :
  
     public static String getPath(Request request) {
       return reques.match(Requests.cases()
         .GET(path          -> path)
         .DELETE(path       -> path)
         .PUT(path -> body  -> path) // curried F2
         .POST(path -> body -> path));
     }

Okay, that's it ! Sorry for this much too long post. I hope that most of
it makes sense and look forward for your opinion about my propositions.

Thanks again for that nice piece of work,

Grégoire.

jbgir...@gmail.com

unread,
Oct 22, 2015, 7:39:15 PM10/22/15
to functio...@googlegroups.com
Thanks for your comments! Responses in-lined.


The main reason is that Derive4J support both the visitor style and the 'catamorphism' style (similar to the one in Runar's blog post) for defining and ADT, and I wanted the pattern matching synthax to be uniform accros both style.
The other reason is to facilitate re-usability and composition.
No, it is really sealed from the point of view the Request type: you cannot add cases externally to the Request class because that would require to either modify the match method signature or modify the Cases visitor interface.
Of course you can subclass Request manually but you will have to implement the abstract match and choose one of the existing 'visit' method to do so: and so instances your manually written subclass of Request will be patterned-match in the same manner as instances of generated subclasses.
To recap, derive4j pattern-matching is based on method dispatch and not instanceof switches (like done internally by scalac) that is why the class hierarchy does not need to be sealed for the datatype to be effectively sealed,

Also I don't want to generate the actual ADT base class because I want it to be easily customizable (eg. by adding business instance methods) and also because it complicate its usage in practice (you would need to run the annotation processor before being able to reference it).

But you can always add a package private constructor. (and that should probably be mandatory when using smart constructors).
 
  
 - the third one is a little caprice : would it be possible to
   benefit from some curried version of the '*Matcher' SAM
   types alongside the existing ones ?
   So that we can write :
  
     public static String getPath(Request request) {
       return reques.match(Requests.cases()
         .GET(path          -> path)
         .DELETE(path       -> path)
         .PUT(path -> body  -> path) // curried F2
         .POST(path -> body -> path));
     }

Yeah it looks somewhat nicer with currying. I could theoretically add it but my concerns is that it could degrade performance: a curried F7 would require seven method calls. Also intellij bootstrap a lambda quite nicely (it generate parameters with the correct name: same as defined in the visitor). That will not be possible when using curried F.


 
Okay, that's it ! Sorry for this much too long post. I hope that most of
it makes sense and look forward for your opinion about my propositions.

Thanks again for that nice piece of work,

Grégoire.


Thanks for your feedback. glad you like the project! do not hesitate to raise github issues if you have any feature requests!
 


On Saturday, 17 October 2015 16:53:11 UTC+2, Jean-Baptiste Giraudeau wrote:
Hi functional java programmers!

A new projectI have been working on lately, to facilitate functional programming in Java: https://github.com/derive4j/derive4j

Feedback welcomes! (in particular I would be very grateful if someone could cross-check the FP terminology used in the readme).

Cheers.

Jb

--
You received this message because you are subscribed to the Google Groups "Functional Java" group.
To unsubscribe from this group and stop receiving emails from it, send an email to functionaljav...@googlegroups.com.
To post to this group, send email to functio...@googlegroups.com.
Visit this group at http://groups.google.com/group/functionaljava.
For more options, visit https://groups.google.com/d/optout.

jbgir...@gmail.com

unread,
May 8, 2017, 8:17:25 PM5/8/17
to functio...@googlegroups.com
Hello everyone,

FunctionalJava users, rejoice: you don't have to write Equal/Hash/Ord/Show manually anymore: https://github.com/derive4j/derive4j-fj !

The derivation algorithms for those "type classes" should be the same as Haskell/GHC (otherwise it's a bug). There is a few complex types that are not handled yet (I will let you find out which one) but otherwise it should work quite well.

Cheers,

Jb

Grégoire Neuville

unread,
May 9, 2017, 7:20:52 AM5/9/17
to Functional Java
Is Java on the verge of becoming useful ? Thanks again Jean-Baptiste !
Reply all
Reply to author
Forward
0 new messages