Calling Scala code from Frege...?

77 views
Skip to first unread message

harv...@cse.ohio-state.edu

unread,
Nov 14, 2015, 10:24:29 AM11/14/15
to Frege Programming Language
Hi Everyone,

(NOTE:  I'm a complete beginner with Frege...as in I just started working with it a few hours ago.)

I was wondering if it is possible to call Scala code from Frege.  So, I gave it a try, but I am having some trouble.  Interestingly, I can call Frege code from Scala, but not vice-versa.

For example, here is a Scala class.

  package example
 
  object Blah {
    val wiffy = "42"
  }

And here is a Frege module where I attempt to call "Blah.wiffy":

  module example.Hello where

  data Meow = native example.Blah where
      pure native wiffy example.Blah.wiffy :: String

  greeting = "Hello, " ++ Meow.wiffy

  main args = do
      println ("Hello, " ++ Meow.wiffy)

I get a compiler error "`example.Blah` is not a known java class".  I suspected that this would happen due to Scala's name mangling (cf. http://stackoverflow.com/questions/12284028/how-can-i-use-a-scala-singleton-object-in-java).  However, if I try to use the mangled name "example.Blah$" to refer to the scala object, I get a parser error "unexpected '::' while trying to parse a method type with optional throws clause".

Is Scala's name mangling incompatible with Frege, or am I doing things wrong?

Thanks so much!

William Harvey

Ingo W.

unread,
Nov 14, 2015, 12:18:58 PM11/14/15
to Frege Programming Language
William, 

I'm afraid it could be both. :)

The $ sign at the end disturbs me, as it is normally used by the JVM to encode nested classes.
However, if the JVM binary name of the Blah class is actually "example.Blah$" then it should work.
But in this case you need to give the name as string, hence

data Meow = pure native "example.Blah$" where

(Remove the pure before the native when it's not an immutable class.)

Then, in the next line. If "wiffy" is a static member, you don't need the data at all. A top level

    pure native wiffy "example.Blah$.wiffy" :: String

would do it.
OTOH if wiffy is not static, it could be a member:

    pure native memberwiffy ".wiffy" :: Meow -> String

or even a method

        pure native wiffy  :: Meow -> String

But in this case you'd also need something that gives you a Meow (i.e. example.Blah$) to access wiffy.

Regards, Ingo

Marimuthu Madasamy

unread,
Nov 14, 2015, 12:20:51 PM11/14/15
to Frege Programming Language
Hi,

Welcome to Frege! This would have been a good StackOverflow question. 

It is perfectly possible to call Scala code from Frege as when it comes to Frege, it cares only about the class file not from where it is compiled from.
When we want to call some "native" code (whether it is Scala or Java or any other JVM language) from Frege, we just need to understand how the code looks from the compiled class file perspective.
We can use javap for that to understand the method signatures that it was compiled to and then write the corresponding native binding in Frege.

scratch$ cat Blah.scala 

package example

object Blah {
val wiffy = "42"
}
scratch$ scalac -d bin Blah.scala 

scratch$ ls bin/example
Blah.class Blah$.class

When that Scala code is compiled, we can see 2 class files: one for the singleton with static methods (Blah.class) and a class with instance methods (Blah$.class).
We want to use `wiffy` from the singleton. Let's use javap on that:

scratch$ javap -cp bin example.Blah
Compiled from "Blah.scala"
public final class example.Blah {
public static java.lang.String wiffy();
}

As we can see, `wiffy` is not a field. It is a method with no parameters so the corresponding native binding in Frege would be:


pure native wiffy example.Blah.wiffy :: () -> String


With this, we can compile the Frege code:

scratch$ java -cp ~/bin/frege/fregec.jar:./bin -Xss2m frege.compiler.Main -d ./bin Hello.fr
calling: javac -cp /home/marimuthu/bin/frege/fregec.jar:./bin:./bin -d ./bin -sourcepath . -encoding UTF-8 ./bin/example/Hello.java
runtime 4.285 wallclock seconds.

It works! Your error "`example.Blah` is not a known java class" could be because of class path issues. Did you add the folder with the compiled Scala class files to the class path when you run the Frege compiler?

Now we can also use the Scala class with instance methods to call `wiffy` by passing the singleton as the instance:

scratch$ javap -cp bin "example.Blah$"
Compiled from "Blah.scala"
public final class example.Blah$ {
public static final example.Blah$ MODULE$;
public static {};
public java.lang.String wiffy();
}

Here the `MODULE$` variable stores the Scala singleton. We can use this class in Frege like this:

data Foo = pure native "example.Blah$" where
pure native companion "example.Blah$.MODULE$" :: Foo
pure native wiffy :: Foo -> String

The complete Frege code with both of those changes:

module example.Hello where

data Meow = native example.Blah where
  pure native wiffy example.Blah.wiffy :: () -> String

greeting = "Hello, " ++ Meow.wiffy ()

data Foo = pure native "example.Blah$" where
pure native companion "example.Blah$.MODULE$" :: Foo
pure native wiffy :: Foo -> String

main args = do
println ("Hello, " ++ Meow.wiffy ())
println $ "Hi, " ++ Foo.companion.wiffy

We can run it with:

scratch$ java -cp ~/bin/frege/fregec.jar:./bin -Xss2m example.Hello
Hello, 42
Hi, 42
runtime 0.064 wallclock seconds.

harv...@cse.ohio-state.edu

unread,
Nov 14, 2015, 1:11:32 PM11/14/15
to Frege Programming Language
Thank you very much, Ingo and Marimuthu, for helping me out.  Your detailed explanations are great!

Cheers,

William
Reply all
Reply to author
Forward
0 new messages