Accessing nested objects from java #17873
Replies: 0 comments 14 replies
-
Making a new instance of an object is a bad idea since everything assumes that it's a singleton. It also shouldn't be needed: one can access the singleton through the
Scala 2 never did that and we just copied that behavior, since this is such a long-established behavior, changing it would require a very careful analysis of the impact of that change (and digging up past discussions on this topic in Scala 2). |
Beta Was this translation helpful? Give feedback.
-
Indeed
how can one invoke
which is somehow understandable as there is no such generated JVM class as
The existing class file is Is this a bug then? I'm getting the same errors for scala 2. |
Beta Was this translation helpful? Give feedback.
-
This goes beyond my knowledge of inner classes, maybe @lrytz can help? At least in Scala 2 the InnerClasses table of InnerClasses:
public static lampepfl/dotty#8= lampepfl/dotty#2 of lampepfl/dotty#7; //Bar$=class Foo$Bar$ of class Foo
public static lampepfl/dotty#11= lampepfl/dotty#10 of lampepfl/dotty#2; //Baz$=class Foo$Bar$Baz$ of class Foo$Bar$ But maybe javac doesn't rely on this information? I have no idea. |
Beta Was this translation helpful? Give feedback.
-
As a workaround, one can write |
Beta Was this translation helpful? Give feedback.
-
The problem seems to be explained here https://stackoverflow.com/questions/30809070/accessing-scala-nested-classes-from-java |
Beta Was this translation helpful? Give feedback.
-
Some background here... Basically the recommendation is to make nested objects accessible to Java by adding explicit getters for them in the Scala source. It's hard enough to generate the (mandatory) |
Beta Was this translation helpful? Give feedback.
-
That's interesting, comparing the bytecode generated by 2.13.5 and dotc:
what are those fields for? |
Beta Was this translation helpful? Give feedback.
-
Thanks, so if I understand this correctly, to be able to reference |
Beta Was this translation helpful? Give feedback.
-
No, I don't know... My guess is it's about the tradeoff between complexity of the implementation and the value it would provide. |
Beta Was this translation helpful? Give feedback.
-
A workaround is to use // Foo.scala
object Foo {
def foo = println("foo")
class Bar
object Bar {
@scala.annotation.static
def bar = println("bar")
}
} // Test.java
class Test {
void foo() { Foo.Bar.bar(); }
} |
Beta Was this translation helpful? Give feedback.
-
@liufengyun this doesn't seem to scale with more levels of nesting // Foo.scala
object Foo {
def foo = println("foo")
object Bar {
def bar = println("bar")
class Baz
object Baz {
@scala.annotation.static
def baz = println("baz")
}
}
} public class Test {
public static void main(String[] args) {
Foo.Bar.Baz.baz();
}
}
|
Beta Was this translation helpful? Give feedback.
-
@prolativ Indeed, For any non-top level static object |
Beta Was this translation helpful? Give feedback.
-
@liufengyun yeah, it was my initial intuition that synthesizing proxies should solve the problem. |
Beta Was this translation helpful? Give feedback.
-
By "static object" I mean objects that are not nested inside any class (thus no need for outer).
Yes, static objects could be nested deeply.
They are not static, thus can be ignored for the moment. There might be issues with initialization ordering. But it's worth trying and see how it works. |
Beta Was this translation helpful? Give feedback.
-
Not sure if this is simply a bug or for some reason it was designed that way but accessing nested objects from java code is very tricky.
Having such scala code
one can call
foo
from java simply asFoo.foo()
. So one could expect thatbar
can be similarly called asFoo.Bar.bar()
. Unfortunately this doesn't work. The workaround that I've found is not very intuitive:(new Foo.Bar$()).bar()
.In case of
foo
this works because we synthesize static forwarders for methods defined in top level objects. The behaviour is common with scala 2 and I've seen this discussion scala/scala-dev#573 regarding whether generating static forwarders is the best solution but it didn't address accessing nested objects. Doing it like thisnew Foo.Bar$()
is not only slightly verbose and unintuitive (a java programmer using an API defined in scala needs to know how scala objects are represented in JVM) but even misleading (normallynew
should return a new instance of a class but here the same reference is returned all the time - which can be seen if you introduce some mutability into the object).Should we then generate static forwarders for accessing inner objects so that they can be accessed from java like
Foo.Bar
or at least
Foo.Bar()
? I guess generating static forwarders directly for methods of a nested object is not an option, at least if the object is defined inside a class, which can have multiple instances.@smarter @odersky any ideas?
Beta Was this translation helpful? Give feedback.
All reactions