Skip to content
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

Streamline callbacks to haskell with inline-java #129

Open
facundominguez opened this issue Aug 2, 2019 · 2 comments
Open

Streamline callbacks to haskell with inline-java #129

facundominguez opened this issue Aug 2, 2019 · 2 comments

Comments

@facundominguez
Copy link
Member

facundominguez commented Aug 2, 2019

Many libraries in java call back into user code to perform its functions. One notable example is GUI libraries. We have another example in jvm-streaming. https://github.com/tweag/inline-java/blob/master/jvm-streaming/src/main/haskell/Language/Java/Streaming.hs#L92

    iterator <-
      [java| new Iterator() {
          private boolean end = false;
          private Object lookahead;
          @Override
          public boolean hasNext() { return !end; }

          @Override
          public Object next() {
            if (hasNext()) {
              final Object temp = lookahead;
              lookahead = hsNext();
              return temp;
            } else
              throw new java.util.NoSuchElementException();
          }

          @Override
          public void remove() { throw new UnsupportedOperationException(); }
          private native void hsFinalize(long tblPtr);
          private native Object hsNext();
          @Override
          public void finalize() { hsFinalize($tblPtr); }
        } |]

The iterator is passed to a function that will retrieve values from Haskell via the native methods of our anonymous Iterator class.

Various housekeeping tasks are necessary to link Haskell functions with those native methods. This issue is about designing and implementing a mechanism that would allow to automate the housekeeping. Suppose we implemented somehow a new quasiquoter like:

    iterator <-
      [new| Iterator() {
          private boolean end = false;
          private Object lookahead;
          @Override
          public boolean hasNext() { return !end; }

          @Override
          public Object next() {
            if (hasNext()) {
              final Object temp = lookahead;
              lookahead = hsNext();
              return temp;
            } else
              throw new java.util.NoSuchElementException();
          }

          @Override
          public void remove() { throw new UnsupportedOperationException(); }
          private native Object $$hsNext();
          @Override
          public void finalize() { hsFinalize(); }
        } |]

Which is capable of identifying hsNext, link it with the corresponding Haskell function and automatically synthesize hsFinalize.

A major challenge with this approach is to produce the FFI wrappers of the haskell functions. Template Haskell can produce FFI wrappers with addTopDecls, but the type information necessary to do so would be available only after type-checking.

@facundominguez
Copy link
Member Author

Well, another approach could be to have some template haskell code

generateFunctionalInterface :: [TH.Type] -> TH.Type -> Q [TH.Decl]
generateFunctionalInterface argumentTypes returnType = ...

that produces the necessary FFI declarations and a function like

newFunctionalInterface :: String -> (ArgType1 -> ... -> ArgTypeN -> ReturnType) -> IO (J ty)
newFunctionalInterface methodName haskellCallback = ...

where J ty is a reference to an instance of some functional interface.

Compared to the first proposal, the user is telling the compiler which types to use, and the compiler would produce some error if the types are wrong.

@facundominguez
Copy link
Member Author

There is some code here which is reusable to setup different types of callbacks:
https://github.com/tweag/inline-java/blob/master/benchmarks/wizzardo-http/src/main/haskell/Language/Java/Function.hs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant