Scala visibility when accessed by Java classes - java

I have a module written in Scala that I need to integrate into a Java web application. Everything works great, except the fact that methods and fields that are
private[somepackage]
in the Scala classes appear to be accessible from the Java code from outside that package. Is there any way to hide those?
EDIT: example illustrating what is happening
package my.scala.module
class SomeClass {
private[scala] val myValue = "this should be hidden"
}
package com.something.service;
import my.scala.module.SomeClass;
public class MyService {
private static SomeClass someInstance = new SomeClass();
public static void main(String[] args){
System.out.println(someInstance.myValue());
}
}
Running main will cause "this should be hidden" to print

There is no way to encode this constraint in JVM bytecode. It is enforced by the Scala compiler, but neither the JVM nor Java know anything about it.
There are some Scala features which can be encoded in JVM bytecode, and some which can't.
In particular, there are some constraints which cannot be encoded in JVM bytecode, e.g. sealed or private[foo], or val. Which means that if you get your hands on the compiled JVM bytecode of a Scala source file, then you can do stuff that you can't do from Scala by interacting with the code through a language that is not Scala.
This is not specific to the JVM backend, you have similar, and even more pronounced problems with Scala.js, since the compilation target here (ECMAScript) offers even less ways of expressing constraints than JVM bytecode does.
But really, this is just a general problem: I can take a language as safe and pure as Haskell, compile it to native code, and if I get my hands on the compiled binary, all safety will be lost. In fact, most Haskell compilers perform (almost) complete type erasure, so there are literally no types, and no type constraints left after compilation.

Related

Why is the run-time class of a Kotlin-collection a Java-class?

In the "Kotlin for Java-Developers"-course by JetBrains (at Coursera) it is told, that Kotlin-code is compiled to byte-code directly. And that byte-code is then executed on the JVM.
But when I do:
var list = listOf<String>("A", "B", "C")
println(list::class) // => Prints "class java.util.Arrays$ArrayList"
Obviously the normal Java ArrayList is used underneath. So I confused ...
Is Kotlin just some "more modern" syntax thing, which uses Java underneath?
Practically some syntactic sugar, which is put on-top, so that one can write code in a nicier way. But underneath it's still the same old Java-thing.
Is Kotlin just some "more modern" syntax thing, which uses Java underneath?
No. You Kotlin source code >>is<< compiling to bytecodes.
But your code is using the listof Kotlin library function, and the implementation of that function is returning a value that is an instance of a Java class.
Why?
It was probably easier / quicker to implement it that way. (Based on the type of the list object, we can infer that listof is simply calling java.util.Arrays.asList(...).)
There is possibly no advantage in reimplementing it; e.g. no performance benefit.
There are possibly disadvantages; e.g. it is likely to cause problems for people who need their Kotlin code to be interoperable with Java which uses standard Java collection classes.

What's the intended use of #JvmSynthetic in Kotlin?

I have come across the #JvmSynthetic annotation in kotlin-stdlib, and I'm wondering what it is for, but, unfortunately, it is undocumented. (UPD: it was at that moment)
As far as I understand, applying it to a program element will add the synthetic modifier to the corresponding bytecode elements. As a consequence, the element becomes invisible from Java:
class MyClass {
#JvmSynthetic
fun f() { }
}
Somewhere in Java code:
MyClass c = new MyClass();
c.f() // Error: cannot resolve method f()
But the same elements are still visible in Kotlin code:
val c = MyClass()
c.f() // OK
Is hiding declarations from non-Kotlin sources a valid use of #JvmSynthetic? Is it the intended use? What are the other appropriate use cases?
Since #JvmSynthetic hides functions from Java, they cannot be overridden in Java either (and when it comes to an abstract member, the calls then result into AbstractMethodError). Given that, can I use #JvmSynthetic to prohibit overriding members of a Kotlin class in Java sources?
In plain Java, synthetic methods are generated by the javac compiler. Normally the compiler must create synthetic methods on nested classes, when fields specified with the private modifier are accessed by the enclosing class.
Given the following class in java:
public final class SyntheticSample
{
public static void main(final String[] args)
{
SyntheticSample.Nested nested = new SyntheticSample.Nested();
out.println("String: " + nested.syntheticString);
}
private static final class Nested
{
private String syntheticString = "I'll become a method!";
}
}
when the SyntheticSample class accesses the nested.syntheticString field, it is indeed calling a static synthetic method generated by the compiler (named something like access$100).
Even if Kotlin exposes a #JvmSynthetic annotation that is able to "force" the creation of synthetic methods, I advice to not using it in normal "user" code. Synthetic methods are low-level tricks made by the compiler, and we should never rely on such things in everyday code. I think it's there to support other parts of the standard library, but you should ask the JetBrains guys directly if you're curious (try on the official Kotlin Discussion Forum)
First, to answer what synthetic methods actually are, let's have a look at the Java language specification:
11. A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS §2.9).
The #JvmSynthetic annotation does exactly that: prevent access from source code. The method will still appear in reflection and is then marked as synthetic.
More precisely, from the Kotlin documentation (emphasis mine):
#JvmSynthetic
Sets ACC_SYNTHETIC flag on the annotated target in the Java bytecode.
Synthetic targets become inaccessible for Java sources at compile time while still being accessible for Kotlin sources. Marking target as synthetic is a binary compatible change, already compiled Java code will be able to access such target.
This annotation is intended for rare cases when API designer needs to hide Kotlin-specific target from Java API while keeping it a part of Kotlin API so the resulting API is idiomatic for both.
As described in the last paragraph, #JvmSynthetic is a tool for API design, which lets a library writer avoid automatic generation of Java equivalents. Probably the most popular use cases are Kotlin-only features, such as operator overloading, componentN() methods or properties, which may have a more idiomatic way to be exposed in Java.
It is noteworthy that the target of this annotations are property setters/getters, functions and fields -- basically everything that translates in Java to a method.
#Target([
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.FIELD])
annotation actual class JvmSynthetic

Any risk using a single dollar sign `$` as a java class name?

Originally I was using the underscore _ as a class name. The new Java8 compiler complains that it "might not be supported after Java SE 8". I changed that to $, and there is no warning any more. However I remember that $ is used by Java to indicate an inner/embedded class in the byte code. I am wondering if there is any risk to use a dollar sign $ as a class name
Some background to this question. What I want to do is to overcome the fact that Java doesn't support pure function, and the _ or $ is to put an namespace to encapsulate some very generic concept (classes/static methods). and neither do I have a good name for this, nor do I want the lib user type too many things to reference that namespace. Here is the code showing what I am doing under the way: https://github.com/greenlaw110/java-tool/blob/master/src/main/java/org/osgl/_.java
It is bad style, and potentially risky to use $ in any identifier in Java. The reason it is risky is that the $ character is reserved for the use of the Java toolchain and third-party language tools.
It is used by Java compilers in "internal" class names for inner and nested classes.
It is used by Java compilers in the names of synthetic attributes.
It could be used by third-party code generators (e.g. annotation processors) for various purposes.
It could be used by other languages that target the JVM platform, and that might need to co-exist with your code.
You probably won't have technical issues with a plain $ classname at the moment (at least with respect to the standard Java toolchain). But there's always the possibility that this will change in the future:
They have (effectively) reserved the right to change this1.
There is a precedent for doing this in the _ example.
If you really, really need a one-character classname, it would be better to play it safe and use F or Z or something else that isn't reserved.
But to be honest, I think you'd be better off trying to implement (or just use) a real functional language than trying to shoe-horn a functional programming "system" into Java. Or maybe, just switch to Java 8 ahead of its official release. 'Cos I for one would refuse to read / maintain a Java codebase that looked like jquery.
I don't mean to create a functional lib for Java, just want to create a lib to maintain some common utilities I used. Again, I am a advocate of minimalism and feel suck with things like apache commons. The functional stuff is added to help me easier to manipulate collection(s).
If it is your code, you can do what you like. Make your own decisions. Act on your opinions. Be a "risk taker" ... :-). (Our advice on $, etcetera ... is moot.)
But if you are writing this code for a client or employer, or with the intention of creating a (viable) open source product, then you need to take account of other people's opinion. For example, your boss needs to have an informed opinion on how maintainable your code will be if you find a better paying job somewhere else. In general, will the next guy be able to figure it out, keep your code, fresh, etc ... or will it be consigned to the dustbin?
1 - JLS §3.8 states "The $ character should be used only in mechanically generated source code". That is saying "use it at your peril". The assumption is that folks who build their own source code generators can change them if the standard toolchain uses a bare $ ... but it is harder to change lots of hand written code, and that would be an impediment to upgrading.
Huh, you're right, using a $ in a classname works. Eclipse complains that it is against convention, but, if you are sure, you can do it.
The problem (conventionally) with using a $ is that the $ is used in the class hierarchy to indicate nested classes.... for example, the file A.java containing:
class A {
class SubA {
}
}
would get compiled to two files:
A.class
A$SubA.class
Which is why, even though $ works, it is ill advised because parsing the jars may be more difficult... and you run the risk of colliding two classes and causing other issues
EDIT, I have just done a test with the following two Java files (in the default package)
public class A {
private static final class SubA {
public String toString() {
return "I am initializing Nested SUBA";
}
}
private static final SubA sub = new SubA();
public A() {
System.out.println("What is " + sub.toString());
}
}
public class A$SubA {
#Override
public String toString() {
return "I am A$SubA";
}
}
public class MyMain {
public static void main(String[] args) {
System.out.println(new A());
System.out.println(new A$SubA());
}
}
And the code will not compile.....
Two problems, type A$SubA is already defined, and can't reference a nested class A$SubA by it's binary name.
Yes, to be pedantic about answering your question there is a risk. As some other folks have mentioned, it violates java naming conventions. So the risk is that with future versions of the JDK this may cause problems. But beyond that, and some issues if you try to use nested classes you should be fine.
I think you're trying to avoid ugly names like Util.andThen. Consider using static imports. That lets you import all the methods in the header import static org.ogsl.Util.*, so then you can simply use you andThen without any prefix at all.
The Selenide project does it. Just look at the top of this documentation:
https://selenide.org/documentation.html
Maybe it is a more acceptable thing to do only in test code.
API ref:
https://selenide.org/javadoc/current/com/codeborne/selenide/Selenide.html

How does JVM understand the byte code compiled by both the JDK and Eclipse while both are different?

Compiled byte code by Eclipse and JDK are different. Then how does the JVM understand both the byte codes? Example:
package com.hcl.raj.utilities;
public class StringTest {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String name = "Rajkumar";
byte[] byteCodes = new byte[] {15,22,35,48};
String str1 = new String(byteCodes);
System.out.println(str1);
}
}
The compiled code of the above source code by JDK and Eclipse are different.
Original attempt to post compiled code removed due to encoding and formatting issues
First of all, is the bytecode different, or is the difference only in other parts of the class file? A class file can contain a lot of optional information (for debugging).
But even if the bytecode itself is different, they behave like synonyms. Even in a language as tightly defined as Java bytecodes, you can express the same behaviour in different ways.
For example, switch/case statements can be compiled into either of two different opcodes: tableswitch or lookupswitch. They both do the same thing essentially, so in certain cases a compiler is more or less free to choose between them.
What is important though that these differences are all within the limits of standard bytecode, regardless of platforms or any other external circumstances, no Java compliant compiler will produce bytecode that a similarly compliant VM can't interpret (assuming that they support the same version of Java).
There is a huge chapter in the JLS dedicated to specifying the Java class file format, which is really the whole point of having that format in the first place. The javac compiler holds no special authority on the format of the files it happens to produce.
Eclipse uses an SDK internally (which can be the same you used to directly generate your bytecode, or another one).
Also, different SDKs can generate different Bytecode (for example if the JDK is from a diferent company or a diferent version), but if they meet the bytecode specification when they generate bytecode, they will be well interpreted by a JVM that also follows that specification.
Java bytecode is portable, this is one of key feature of java. You can read some info here. If you want to discover how this portability exactly works you can browse specification.

What features of Scala cannot be translated to Java?

The Scala compiler compiles direct to Java byte code (or .NET CIL). Some of the features of Scala could be re-done in Java straightforwardly (e.g. simple for comprehensions, classes, translating anonymous/inner functionc etc). What are the features that cannot be translated that way?
That is presumably mostly of academic interest. More usefully, perhaps, what are the key features or idioms of Scala that YOU use that cannot be easily represented in Java?
Are there any the other way about? Things that can be done straightforwardly in Java that have no straightforward equivalent in Scala? Idioms in Java that don't translate?
This question, in my opinion, misses the point about by asking us to compare JVM languages by looking at their generated bytecode.
Scala compiles to Java-equivalent bytecode. That is, the bytecode could have been generated by code written in Java. Indeed you can even get scalac to output an intermediate form which looks a lot like Java.
All features like traits (via static forwarders), non-local returns (via exceptions), lazy values (via references) etc are all expressible by a Java program, although possibly in a most-ugly manner!
But what makes scala scala and not Java is what scalac can do for you, before the bytecode is generated. What scalac has going for it, as a statically typed language, is the ability to check a program for correctness, including type correctness (according to its type system) at compile time.
The major difference then between Java and scala (as of course Java is also statically typed), therefore, is scala's type system, which is capable of expressing programmatic relations which java-the-language's type system cannot.For example:
class Foo[M[_], A](m : M[A])
trait Bar[+A]
These concept, that M is a type parameter which itself has type parameters or that Bar is covariant, just do not exist in Java-land.
Traits are one thing that does not have an equivalent. Traits are Interfaces with code in them. You can copy the code to all classes that have a trait mixed in, but that is not the same thing.
Also I believe scala type system is more complete. While it will eventually map to the JVM types (actually suffer erasure). You can express some things in the Scala type system that may not be possible in Java (like variances).
I think, there is no equivalent for dynamically mix in some Traits. In Scala you can add at the time you're creating new objects some Traits, which are mixed in.
For example, we create one dog which is hungry and thirsty and one dog which is just hungry.
val hungryThirstyDog = new Dog with Hungry with Thirsty
val onlyHungryDog = new Dog with Hungry
I don't know an equivalent way to do this in Java. In Java, the inheritance is statically defined.
Implicit conversions don't have a straightforward equivalent in Java.
One feature of scala that I have found a good use for is type reification through Manifests. Since the JVM strips out all type information from generics, scala allows you to conserve this information in variables. This is something that Java reflection AFAIK can't handle, since there are no arguments to types in the bytecode.
The case I needed them was to pattern match on a type of List. This is, I had a VertexBuffer object which stored data on the GPU, that could be constructed from a List of floats or integers. The Manifest code looked approximately like this:
class VertexBuffer[T](data:List[T])(implicit m:Manifest[T]) {
m.toString.match {
case "float" => ...
case "int" => ...
}
}
This link links to a blog post with more information.
There are plenty of SO pages with more information too, like this one.
Three words: higher kinded types.
Your topic is not clear wehther you mean Java the JVM or Java the language. Given that Scala runs on the JVM, the q makes no sense, as we all know Scala runs on the JVM.
Scala has a "native" support for XML. You can build the XML, find elements, match directly in the Scala code.
Examples: http://programming-scala.labs.oreilly.com/ch10.html

Categories

Resources