javascalagenericsscala-java-interoptype-projection

couldn't extend scala class from java class which has abstract function which takes inner class as parameter


I've scala - java polyglot project with scala version 2.13

Below is the standard project structure

    $scala-java-extend-demo on master
    ± tree .
    .
    ├── build.gradle.kts
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle.kts
    └── src
        ├── main
             ├── java
             │   ├── Collector.java
             │   ├── Function.java
             │   ├── JProcessAllWindowFunction.java
             │   └── Window.java
             ├── resources
             └── scala
                 └── ScalaProcessAllWindowFunctionWrapper.scala


    24 directories, 15 files

Below is the Collector.java

public interface Collector<T> {
    void collect(T record);

    void close();
}

Below is the Function.java

public interface Function extends java.io.Serializable {}

Below is the Window.java

public abstract class Window {
    public abstract long maxTimestamp();
}

Below is the JProcessAllWindowFunction.java

public abstract class JProcessAllWindowFunction<IN, OUT, W extends Window> {

    private static final long serialVersionUID = 1L;

    public void process(Context context, Iterable<IN> elements, Collector<OUT> out){}

    public void clear(Context context) {}

    public abstract class Context {
        public abstract W window();
        public abstract <X> void output( X value);
    }
}

Below is the ScalaProcessAllWindowFunctionWrapper.scala which extends JProcessAllWindowFunction

import java.lang

final class ScalaProcessAllWindowFunctionWrapper[IN, OUT, W <: Window] extends JProcessAllWindowFunction[IN, OUT, W] {
  override def process(context: JProcessAllWindowFunction[IN, OUT, W]#Context, elements: lang.Iterable[IN], out: Collector[OUT]): Unit = ???
}

When I compile the project I get below error -

  > scala-java-extend-demo on master $
  ± gradle clean build
  
  > Task :compileScala FAILED
  [Error] /Users/myuser/Coding/misc/scala-java-extend-demo/src/main/scala/ScalaProcessAllWindowFunctionWrapper.scala:4: method process overrides nothing.
  Note: the super classes of class ScalaProcessAllWindowFunctionWrapper contain the following, non final members named process:
  def process: ((context: _1.Context, elements: Iterable[IN], out: Collector[OUT]): Unit) forSome { val _1: ScalaProcessAllWindowFunctionWrapper[IN,OUT,W] }
  one error found
  
  FAILURE: Build failed with an exception.

The project is on github here.

How can I fix this error?


Solution

  • In ScalaProcessAllWindowFunctionWrapper modify the signature of method from

    def process(context: JProcessAllWindowFunction[IN, OUT, W]#Context, elements: lang.Iterable[IN], out: Collector[OUT]): Unit = ???
    

    to

    def process(context: Context, elements: lang.Iterable[IN], out: Collector[OUT]): Unit = ???
    

    i.e. replace type projection JProcessAllWindowFunction[IN, OUT, W]#Context with path-dependent type Context aka this.Context. Type projection is a typical Java type and would work for overriding there but too rough type here in Scala.

    In Java Context means JProcessAllWindowFunction<IN, OUT, W>.Context i.e. JProcessAllWindowFunction[IN, OUT, W]#Context in Scala. But in Scala Context means this.Context.

    this.Context and x.Context (for specific x: JProcessAllWindowFunction[IN, OUT, W]) are subtypes of JProcessAllWindowFunction[IN, OUT, W]#Context.

    Why does one select Scala type members with a hash instead of a dot?

    What are type projections useful for?

    What does the `#` operator mean in Scala?

    What is meant by Scala's path-dependent types?

    What is the difference between path-dependent types and dependent types?

    Are path-dependent types type projections?

    Also add modifier override to process in ScalaProcessAllWindowFunctionWrapper and remove modifier final from process in JProcessAllWindowFunction.