What is the difference between main and regular function? - kotlin

Kotlin allows me to create two main() functions. But does not allow two myfun() functions.
What is special about main()? Are there other special functions?
Can I create two static myfun() functions in same package? I want them to have file scope like main.
Test1.kt:
package start
fun main(args: Array<String>) {
}
fun myfun(args: Array<String>) {
}
Test2.kt:
package start
// OK!
fun main(args: Array<String>) {
}
// Error! Conflicting overloads
fun myfun(args: Array<String>) {
}

Kotlin allows to have multiple top-level main functions in the same package due to practical reasons — so that one could have an entry point in an each file without moving these files to different packages.
It is possible because each .kt file with top-level members is compiled to the corresponding class file, so these main functions do not clash, because they are located in separate class files.
Why is it allowed for main functions and not for other top-level functions? Having multiple functions with the same name and signature in the same package would make it impossible to distinguish them when calling from Kotlin. This is not a problem for main function, because when it is used as an entry point for a program, it's required to specify the class name where it is located.

What is special about main()? Are there other special functions?
To start a Java program you need
a class file,
static void main(String[]) method in that class file.
So from outside of the package you'd be able to start any of these main methods.
However if you try to call the main method from another Kotlin file inside of the package, you'd get an error, because Kotlin can't disambiguate one method from the other.
You can call any of them from Java as you please because they're compiled in different class files (see further).
Can I create two static myfun() functions in same package?
You can't define two top-level methods with the same name in the same package in Kotlin (with the above exception).
This is what your code compiles to:
public final class Test1Kt {
public static final void main(#NotNull String[] args) { /* ... */ }
public static final void myFun(#NotNull String[] args) { /* ... */ }
}
public final class Test2Kt {
public static final void main(#NotNull String[] args) { /* ... */ }
public static final void myFun(#NotNull String[] args) { /* ... */ }
}
As far as JVM is concerned all of these methods could coexist in peace. But this is an implementation detail of Kotlin.
Let's forget for a second that Kotlin apps run on JVM. Pretend your only tool is Kotlin, and you can't use Java, perhaps you're writing a Kotlin cross-platform module. How could you have two top-level functions with the same name? How would you pick which one to call? Again, you'd get an error, because Kotlin couldn't disambiguate one method from the other.
Edit: As noted by #Todd this behavior has been even more strict in the past: Why does Kotlin lang allow only single main function in project?

Regarding the question about how to have file-scoped functions, by default top-level functions (those not declared within a class) are public, which means their signatures must be unique, including the package name. You can make functions local to the file, rather than the package, by prefixing them with the private modifier, e.g., in each file:
private fun myfun(args: Array<String>) {
// method body here
}

Related

What's the use for Kotlin's #JvmSynthetic on a file target?

The #JvmSynthetic annotation is allowed to be used on a file, but I can't figure out what the purpose of this would be.
I was hoping I could hide a file containing a bunch of Kotlin-only extension methods from Java users, but that doesn't seem to be the case:
// Extensions.kt
#file:JvmSynthetic
#JvmSynthetic
fun Foo.mySyntheticExtension() = ...
fun Foo.myExtension() = ...
// Java usage
// This doesn't compile (as expected)
Extensions.mySyntheticExtension(foo);
// This compiles fine, so #JvmSynthetic on a file does not trickle down to all its functions
Extensions.myExtension(foo);
Even without the non-synthetic method Java users still see the cluttering ExtensionsKt class, although it appears empty to them.
If #file:JvmSynthetic doesn't hide the file('s generated class) from Java, nor trickles down the synthetic status to all functions in it, what is its intended purpose?
The original proposal that caused this annotation target to be added was KT-41884:
The rationale given was:
This would apply to the synthesized class which encapsulates top-level members. This allows hiding those members from Java when they are internal visibility.
For example:
// ManyInternals.kt, in module A
#file:JvmSynthetic
internal fun foo() {
}
internal fun bar() {
}
// Main.java, in module B
public class Main {
public static void main(String[] args) {
ManyInternalsKt.foo(); // error
}
}

Error: Main method not found despite I have declared a main function

I am new to kotlin and I am trying to use main function together with a class.
fun main() {
var demo = Person("Hello", 10)
println(demo)
}
private class Person (name: String, age: Int){
var name: String
var age: Int
init {
this.name = name
this.age = age
}
}
Although I have declared the main function, the compiler is still looking for the static main method in the class that I have defined, Person, and I got this error:
Error: Main method not found in class Person, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
What have I missed?
java Person is the problem, you are specifically telling it to look for the static void main method there. Top-level functions from Person.kt will be compiled into a PersonKt class by default and so you should run java PersonKt.
Also, the unnamed package you get by not specifying any package is weird in some ways, so I would recommend adding a package declaration from the start (and running java your.package.PersonKt).

Protected inline method in parent class can't access other protected methods

I am having a problem getting IllegalAccessError for the following example:
I have a base class declared in a gradle module called arch
abstract class BaseClass {
protected abstract val value: Int
fun run() {
Log.d("Printme", "value $value")
}
protected inline fun getMyValue(): Lazy<Int> = lazy {
getAnEight()
}
protected fun getAnEight() = 8
}
and a child class declared in gradle module called app
class ChildClass: BaseClass() {
override val value by getMyValue()
}
It is worth saying I am creating a Kotlin project using Android Studio, but these classes are all simple Kotlin objects without any Android specific references. Of course these two modules also have different packages.
Now, from my main entry method I am doing the following (inside app module)
ChildClass().run()
I am calling my run() method declared in base class, which is accessing lazy initiated value property, which is in turn calling getAnEight() method. Since all methods are protected I would expect there is no reason a child class can't call all these. Even if one of the methods is marked as inline and this call gets replaced with method contents, it should still be able to call getAnEight() just fine.
Instead I am receiving IllegalAccessError saying BaseClass.getAnEight() is inaccessible to class ChildClass$$special$$inlined$getMeValue$1. This problem disappears when I remove inline modifier, or if I place BaseClass in the same package as ChildClass.
Is this a bug in Kotlin compiler? Or can someone explain to me this behavior if it's working as intended? Thanks in advance!
https://kotlinlang.org/docs/reference/inline-functions.html#public-inline-restrictions
When an inline function is public or protected and is not a part of a
private or internal declaration, it is considered a module's public
API. It can be called in other modules and is inlined at such call
sites as well.
This imposes certain risks of binary incompatibility caused by changes
in the module that declares an inline function in case the calling
module is not re-compiled after the change.
To eliminate the risk of such incompatibility being introduced by a
change in non-public API of a module, the public API inline functions
are not allowed to use non-public-API declarations, i.e. private and
internal declarations and their parts, in their bodies.
An internal declaration can be annotated with #PublishedApi, which
allows its use in public API inline functions. When an internal inline
function is marked as #PublishedApi, its body is checked too, as if it
were public.
EDIT: I made some bytecode research. The problem is that protected getMyValue() function is inlined into public constructor. In decompiled bytecode, ChildClass public constructor has a following line:
Lazy var4 = LazyKt.lazy((Function0)(new ChildClass$$special$$inlined$getMyValue$1(this)));
As you can see, it creates an instance of class ChildClass$$special$$inlined$getMyValue$1. Let's look at its declaration:
public final class ChildClass$$special$$inlined$getMyValue$1 extends Lambda implements Function0 {
final BaseClass this$0;
public ChildClass$$special$$inlined$getMyValue$1(BaseClass var1) {
super(0);
this.this$0 = var1;
}
public Object invoke() {
return this.invoke();
}
public final int invoke() {
return this.this$0.getAnEight(); // Here lies the problem
}
}
When you create a ChildClass instance, its constructor only creates a ChildClass$$special$$inlined$getMyValue$1 instance, that does not throw any errors. But when you call run(), invoke() method of class above is called. This method is public, its class is public, constructor was public, but getAnEight method is protected. That's how we get this error.

Kotlin compiler issue with overriding of Java final function in Kotlin

I’m dealing with following issue with Kotlin/Java Compiler.
Imagine following scenario: let First be a Java class with a final function and Second be a Kotlin class extending First with a function of the same name like the final function in First class, example:
// Java class
class First {
final void foo() { }
}
// Kotlin class
class Second: First() {
fun foo() { }
}
Obviously, it’s wrong because the final function foo() can not be overridden. However, compilation pass successfully and in run-time I get java.lang.LinkageError: Method void Second.foo() overrides final method in class First.
Is this correct behavior of compiler? I supposed that there will be some validations for this case. Thank you!

Is there a way to hide the INSTANCE variable on a Kotlin singleton object

If I have code like this
object ObjectTest {
#JvmStatic
fun init() {
}
}
is it possible to hide the ObjectTest.INSTANCE variable that Kotlin automatically generates? I don't want the object to be accessible via an instance and nor will it have any instance methods, so the INSTANCE variable is just polluting autocomplete and could be confusing to potential users (This code is for a library that will be consumed by others).
Yes, you can do it, by converting an object into a plain file.
#file:JvmName("ObjectTest")
// maybe a package statement here
fun init() {
// here `init` is public static final void
}
And there's no INSTANCE object. In Kotlin this is a top-level function, but in Java it's a class named ObjectTest with a private constructor and it has a public static final void method called init.