-
Notifications
You must be signed in to change notification settings - Fork 145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Java Interface with Frege Record #360
Comments
This looks extremely cool! Can't wait to try it out on the weekend. Will prove very useful when we need to pass functions to java, where they will be expected as instances of some functional interface. |
So, it looks like your branch has not made it past the merge. Anyway. This looks extremely promising, though the details need, of course, some more love. For example, the following did not work:
|
By the way, I discovered that the code generation emits a bunch of useless code for records. Why, for example, does it generate an add3() method anyway? Can't remember the reason for this. But even if it's useful somewhere, why this
It's simply unused. I must have been drunk back then. Anyway. I think we've got a bit of work to do here:
with
Finally, we'll have a nice encoding for extending classes and interfaces. But, truth be told, it's a bit clumsy for ad hoc extensions. We can reduce the boilerplate by accepting the following expression (taking Runnable as an example):
This is the same syntax that creates a record value, but instead of the constructor, we have the type name of a native type. In order to remain backwards compatible, the rule would be that when we see
it will be the construction of a record value if
and a native function
and rewrite the above expression as:
This looks innocent enough to survive until typechecking.
and we translate
to
or, if there are no arguments
(disregarding the possibility that such an expression may appear curried, hence the following would not work:
though
would be ok. Here, we have it especially easy in code generation: we can just generate the second argument, and change it into a JNewClass, appending the generated class body. We still need to check whether ß matches the type of (one of the overloads of) the extended method. I guiess all this was a bit of a brain dump. I hope we can clear things up in further discussion. |
Do you mean I should push Frege/frege instead of my fork? You can fetch branches in other repository like:
|
You choose what is most convenient for you regarding the branches. Just let me know if you need something. |
All right, then I'll push to my fork, as I have always done.
Actually, this is what I had in mind when I came up with the idea. However, it doesn't always work with abstract classes. Class constructors themselves may have side-effects, as well as taking other arguments. I thought we should avoid a record-like construct having
We have to be careful here, because the correct constructor must be called just once at the time when an object is instantiated. I think we know that already, but the type signature |
In case you missed, I already proposed a case where a Java class constructor takes arguments:
would pass The reason why |
The point is, in a POC it is ok to have the Impl record types, but in practice it would mean even more boilerplate. Here we do need some kind of anonymous record types. But, unfortunately, we don't have anonymous records in Frege (and I'm not going to even think about trying to implement them ... see the desperate attempts of the Haskell community to solve their record problem). Hence, the proposed syntax is just a special case (and the only posssible one without introducing new data types in the compiler, as far as I can see) where we can pretend to have anonymous records, but behind the scenes we derive a one-time-use named record type and let the type checker fill in the types. If we do it right, there need not be any traces of this type in the generated code. (Since we know that in You are right that we cannot simply give a |
I think understand your point. Surely we don't want to write similar method signatures twice! What I'm concerned right now is if the shorthand notation gets too magical. I'm continuing my approach to support mutable interfaces/methods to have a more concrete view. |
There seems to be a problem with type applications:
|
The code currently doesn't check from which data constructor |
Just pushed it. Please see the latest branch if you are interested: https://github.com/matil019/frege/tree/implement-interface |
I'm going to add the "receiver" parameter (a.k.a. public abstract class JClass {
public void concrete(int param) { /* do something ... */ }
public abstract void abstr(int param);
} data JClass = native JClass where
native concrete :: JClass -> Int -> IO ()
native abstr :: JClass -> Int -> IO ()
JClass { abstr = \this i -> println ("calling concrete(%d);".format i) >> this.concrete i } |
Still, my
IMHO, this is because you simply assume that the return type is just some simple type, like Here are some comments on the code in MethodCall.fr, please take them as constructive criticism. Line 114This is probably where the Line 107I'd advise against using the Also later, when it comes to the methods, why not take the types directly from the symbols? Line 121Why not
We do support constructors with arguments, do we not? Line 350-357This looks to me like a re-invention of Line 315-338 wrapIRMethodIn I also suggest to use
|
No worries :) I gladly take your advices. |
@Ingo60 Thank you for your comments. Exactly the kind of comments I needed since I have had difficulty finding existing functions which do what I want. I'll open a WIP PR later so that we can follow code more efficiently. |
I had that additional idea the other day: it would be generally very useful to have a functionality to "export" a frege function as a method (instance or static) conforming to a given signature. |
another hint: there is a |
This is a proposal which introduces a new syntax that allows Frege programmers to implement Java Interfaces with Frege Record declarations.
Proof of Concept
Supports the "Pure" case only: #361
Short description and Examples
native new
functions take Frege records as their arguments and uses their fields to implement the methods of Java interface.Pure
Mutable
Abstract class
Long description
Motivation
Java libraries and frameworks tend to provide Java
interface
s, which client code must implement to work with them. Currently, in order to implement Java interfaces in Frege, Frege programmers must either (a) use thenative module
declarations, or (b) write Java source files separately. In either case, Frege programmers must work out the laziness of Frege arguments/return values and write boilerplates such as.call()
,TST.performUnsafe(...)
,Thunk.lazy(...)
, etc. Since implementing interfaces and extending classes are the essential part of Java programming, having the compiler automate these tasks should greatly help writing Frege against existing huge Java codebase.Concept
Implementing a Java interface is essentially providing a set of functions that implements its methods. "A set of (named) functions" can be represented with the record syntax in Frege, so currently one can write something like this:
For concrete, working, real examples, please see modules such as this.
The
native module
part in the above example is a boilerplate and is to be automatically generated in the proposal. With the new syntax, it can be rewritten to:Syntax
The new syntax introduced in this proposal is the Java-name
"extends"
innative
function declarations:Specifying
"extends"
instead of"new"
generates an anonymous class declaration instead of a plainnew
expression.Field/Method correspondence and Overload resolution
Since Java has method overloading, the syntax must support overload resolution. For this, it relies on the other native member declarations.
Methods for an anonymous class are generated in the following algorithm:
Impl
),JavaI
) are looked up by Frege name(
add2
,add3
, etc., but notadd
).Impl.add2
matchesJavaI.add2
, andJavaI.add2
has Java-nameadd
,Impl.ignored
) are ignored.Impl.garbage
), it's a javac-time error.The text was updated successfully, but these errors were encountered: