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

Should Java Interfaces be Matchable? #16247

Closed
bblfish opened this issue Oct 25, 2022 · 9 comments
Closed

Should Java Interfaces be Matchable? #16247

bblfish opened this issue Oct 25, 2022 · 9 comments
Labels
stat:needs triage Every issue needs to have an "area" and "itype" label

Comments

@bblfish
Copy link

bblfish commented Oct 25, 2022

Compiler version

3.2.0

Minimized example

It is a bit difficult to get a minimized example on this.
An example of a specific commit fff0be9beb2c1edfabb9e385b72f12c21000f93f of banana-rdf, diesel branch. This was a commit to solve the answer to the problem @bishabosha
came up with in issue 13416 and discussed on scala-users thread lib unification with match types. The answer worked for 2 out of 3 cases (wee below).

(btw. the pattern discussed in the thread seems so useful it seems to me, it should have a name. Perhaps it does?)

Output

Update: For a simplified version of the problem see the comment below

Having made the changes proposed by @bishabosha on that commit, two implementations worked well (Jena RDF and Tim Berners-Lee's rdflib.js) but we had a problem with the Eclipse RDF4J implementation. My best explanation for the otherwise
minor difference in code, is that Eclipse is built around interfaces whereas Jena is built on classes. And I guess Interfaces don't implement Matchable by default.

Here is the type of error I was getting:

[error] -- [E038] Declaration Error: /Volumes/Dev/hjs/Programming/Scala3/CoSy/banana-rdf/scala3/rdf4j/src/main/scala/org/w3/banana/rdf4j/Rdf4j.scala:410:32
[error] 410 |         override protected def stringVal(uri: RDF.URI[R]): String =
[error]     |                                ^
[error]     |method stringVal has a different signature than the overridden declaration
[error]     |---------------------------------------------------------------------------
[error]     | Explanation (enabled by `-explain`)
[error]     |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]     | There must be a non-final field or method with the name stringVal and the
[error]     | same parameter list in a super class of object URI to override it.
[error]     |
[error]     |   protected override def stringVal
[error]     |   (uri: org.eclipse.rdf4j.model.IRI & (org.eclipse.rdf4j.model.Value & (
[error]     |     org.eclipse.rdf4j.model.Value
[error]     |    & Matchable)) & (org.eclipse.rdf4j.model.IRI & (org.eclipse.rdf4j.model.Value
[error]     |
[error]     |   & Matchable))): String
[error]     |
[error]     | The super classes of object URI contain the following members
[error]     | named stringVal:
[error]     |   protected def stringVal
[error]     |   (uri: org.w3.banana.RDF.URI[org.w3.banana.rdf4j.Rdf4j.R]): String
[error]      ---------------------------------------------------------------------------
[error] Explanation
[error] ===========
[error] There must be a non-final field or method with the name stringVal and the
[error] same parameter list in a super class of object URI to override it.
[error]
[error]   protected override def stringVal
[error]   (uri: org.eclipse.rdf4j.model.IRI & (org.eclipse.rdf4j.model.Value & (
[error]     org.eclipse.rdf4j.model.Value
[error]    & Matchable)) & (org.eclipse.rdf4j.model.IRI & (org.eclipse.rdf4j.model.Value
[error]
[error]   & Matchable))): String
[error]
[error] The super classes of object URI contain the following members
[error] named stringVal:
[error]   protected def stringVal
[error]   (uri: org.w3.banana.RDF.URI[org.w3.banana.rdf4j.Rdf4j.R]): String

Expectation

It's difficult to have an expectation here.
Should Java interfaces be Matchable automatically?

If not then I'll need to find a workaround. That is not so easy because all of rdf4j is built around interfaces, and they use factories to create objects that just return the interface. So one would need to change a lot there...

Is there a java interface for Matchable that I could add to the top of the hierarchy of rdf4j Node hierarchy to check if this is the problem?

I'll try to see if I can find a minimal example code to duplicate the problem... But if you have any thoughts on the main question that would help.

@bblfish bblfish added the stat:needs triage Every issue needs to have an "area" and "itype" label label Oct 25, 2022
@bishabosha
Copy link
Member

java interfaces are matchable, e.g. for java.util.List

scala> summon[java.util.List[String] <:< Matchable]
val res0: java.util.List[String] =:= java.util.List[String] = generalized constraint

@bishabosha
Copy link
Member

the exceptions are java.io.Serializable and java.lang.Cloneable

@bblfish
Copy link
Author

bblfish commented Oct 25, 2022

thanks for that trick... So we also have

➤  scala-cli repl --amm

Welcome to Scala 3.2.0 (19, Java Java HotSpot(TM) 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

@ import $ivy.`org.eclipse.rdf4j:rdf4j-sail-memory:4.1.3`
@  import org.eclipse.rdf4j.model
@ summon[model.IRI <:< Matchable]
res2: =:=[IRI, IRI] = generalized constraint

@ summon[model.BNode <:< Matchable]
res3: =:=[BNode, BNode] = generalized constraint

@ summon[model.Literal <:< Matchable]
res4: =:=[Literal, Literal] = generalized constraint

which means the problem I was having was not with Interfaces...

@bblfish
Copy link
Author

bblfish commented Oct 25, 2022

Perhaps more important is to test it with the raw scala compiler with the -source future flag set.
(note the -source future flag does not work with scala-cli)

➤  scala  -source future -classpath ~/.ivy2/cache/org.eclipse.rdf4j/rdf4j-model/jars/rdf4j-model-2.2.2.jar
Welcome to Scala 3.2.0 (18.0.2.1, Java Java HotSpot(TM) 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

scala> import org.eclipse.rdf4j.model

scala> summon[model.IRI <:< Matchable]
val res0: org.eclipse.rdf4j.model.IRI =:= org.eclipse.rdf4j.model.IRI = generalized constraint

We get the same thing... So I need to duplicate the problem...

@SethTisue
Copy link
Member

SethTisue commented Oct 25, 2022

note the -source future flag does not work with scala-cli

it does if you add -O, e.g. scala-cli compile -O -source:future . (or scala-cli compile -O -source -O future .), as per https://scala-cli.virtuslab.org/docs/commands/compile#scala-compiler-options

@bblfish
Copy link
Author

bblfish commented Oct 25, 2022

Ok, now I have put together a simplified version of the problem that holds in one file.

If I run the attached code RDF.scala.zip from the console I get an error that looks very similar to the one in the banana-rdf repo I was having trouble with.

➤  scala -version                                                                                            1Scala code runner version 3.2.0 -- Copyright 2002-2022, LAMP/EPFL
➤  scala -explain  RDF.scala
-- Error: /Volumes/Dev/Imec/ImecGH/CityFlowsSW/scala/RDF.scala:115:8 -----------
115 |  given rops: ROps[R] with
    |        ^
    |object creation impossible, since protected def nodeVal(node: RDF.Node[R]): String in trait ROps is not defined
    |(Note that
    | parameter RDF.Node[R] in protected def nodeVal(node: RDF.Node[R]): String in trait ROps does not match
    | parameter InterfaceRDF.Node & Matchable in protected override def nodeVal(node: InterfaceRDF.Node & Matchable): String in object rops in object IRDF
    | )
-- [E038] Declaration Error: /Volumes/Dev/Imec/ImecGH/CityFlowsSW/scala/RDF.scala:121:27
121 |    override protected def nodeVal(node: RDF.Node[R]): String = node.value
    |                           ^
    |method nodeVal has a different signature than the overridden declaration
    |---------------------------------------------------------------------------
    | Explanation (enabled by `-explain`)
    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    | There must be a non-final field or method with the name nodeVal and the
    | same parameter list in a super class of object rops to override it.
    |
    |   protected override def nodeVal(node: InterfaceRDF.Node & Matchable): String
    |
    | The super classes of object rops contain the following members
    | named nodeVal:
    |   protected def nodeVal(node: RDF.Node[IRDF.R]): String
     ---------------------------------------------------------------------------
2 errors found
Error: Errors encountered during compilation

If I then replace the trait definitions in InterfaceRDF with abstract classes the code runs.

The same code seems to compile ok on scastie...
https://scastie.scala-lang.org/bblfish/ZDVXbP6lRJiRCHaZf6msfQ

It also seems to run when I use scala-cli using the flags @SethTisue mentioned above

➤  scala-cli  -O -source:future RDF.scala
[warn]  JVM that is hosting bloop is older than the requested runtime. Please run `scala-cli bloop exit`, and then use `--jvm` flag to restart Bloop
[warn] OsLibc.defaultJvm
[warn] [current bloop jvm] /Users/hjs/Library/Caches/Coursier/arc/https/github.com/adoptium/temurin17-binaries/releases/download/jdk-17%252B35/OpenJDK17-jdk_x64_mac_hotspot_17_35.tar.gz/jdk-17+35/Contents/Home
[warn]                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Success(https://bblfish.net/#i)
folded=<https://bblfish.net/#i>
matched should be uriisURI InterfaceRDF$AFactory$$anon$2@4eec7777

@SethTisue
Copy link
Member

We're pursuing this on Discord, but regardless, I'm going to close this for now because

• I originally suggested opening the ticket here in the first place because of a hypothesis which has now proved incorrect
• We haven't yet been able to reproduce the problem on any computer except @bblfish's

We can reopen the ticket (or make a new one, if it turns out the nature of the problem is entirely different than originally suspected) if or when new information comes to light.

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Oct 26, 2022
@bblfish
Copy link
Author

bblfish commented Oct 27, 2022

yes, I thought I had code to reproduce the problem, but it turned out to be related to a scala version I was using. The bigger problem is still there in the banana-rdf branch, but it is not easy to reproduce the problem in a simpler setting.

@bblfish
Copy link
Author

bblfish commented Oct 27, 2022

I worked all day to try to reproduce this issue, comiting every attempt that did not fail, and working in a minimal setup, using only a very specific scalac and java compiler, using no build tools and limiting myself to nvim as an editor.

That actually led me to create code that reproduced the problem I am having with banana-rdf.

I published the whole process of discovery in this git repository, with instructions on how to duplicate.
https://github.com/bblfish/DottyIssue16247

I am sure more work could be done. But I thought I need a break.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stat:needs triage Every issue needs to have an "area" and "itype" label
Projects
None yet
Development

No branches or pull requests

3 participants