How to access top level functions referring to the file they're declared in? - kotlin

If you have a file MyUtils.kt in app/utils/:
package app.utils
fun log(message: String) {
println(message)
}
And you want to access this log() function from another file App.kt at app/, you will do this:
package app
import app.utils.log
fun main() {
log("hey")
}
But I don't like how the log() function is imported from the /utils package and not from the MyUtils.kt file explicitly.
One alternative would be to declare MyUtils.kt with package app.utils.MyUtils but I don't think it's a good practice to declare files in packages that don't have a matching folder.
Is there a way around this?
Edit: declaring an object or class wouldn't be a good solution either because of memory issues.

TL;DR
You can't.
Long answer
You seem to have a misconception that a class or object somehow adds some memory issues to your application.
That's not the case.
In fact, if you're running on the JVM, your log function will compile to the following:
public final class UtilsKt {
public static final void log(#NotNull String message) {
Intrinsics.checkParameterIsNotNull(message, "message");
System.out.println(message);
}
}
You can hit Meta+Shift+A on IntelliJ, then do Show Kotlin bytecode if you don't believe me.
Also, you seem to believe it should be possible to refer to a file name explicitly in a Kotlin import. There isn't a way to do that. Files have almost no bearings on the Kotlin compiled-code (it's kind of an accident that the file name actually reflects on the generated Java class name, as shown above).
Packages in Kotlin are usually arranged to meet the directories they are in... but that's not mandatory, by the way. You can write classes in several packages under the same directory. This means that the file names and even directory names do not really affect Kotlin runtime types and imports.
If you are worried about not being able to quickly find out where your functions are declared, I suggest you use the Java convention of calling the files by the name of the class that live in it, and then wrap all functions into an object (there's absolutely no runtime costs associated with that).
package app.utils
object MyUtils {
fun log(message:String) => println(message)
}
File: app/utils/MyUtils.kt
But notice that with any decent IDE, navigating to the declaration of a function is trivial (Meta+B in IntelliJ, usually) regardless of in which file it is in, so this problem is not normally an issue when you work with an IDE.

Related

How to find source file path by compiled class file programmatically in kotlin?

In kotlin, package can be declared randomly, which is not relative to source file path, then compiler will generate class file in package folder. How to find source file path by compiled class file programmatically?
Example:
package kt.notsamepackage_another
class NotSamePackageKotlin {
fun call() {
}
}
NotSamePackageKotlin.class will be generated in folder: ../kt/notsamepackage_another, but source file may be in ../kt/notsamepackage.
I tried these methods:
decompile class file. But source file path can't be found in byte code
adjust kotlin compiler parameters. I want find a parameter to output a mapping contains path relationship, but nothing was found
traverse source folder recursively. This method is not efficient, it's the last choice.
Is there any method more efficient?
I don't think this is possible.  If the full source path isn't compiled into the bytecode, then there's no way to find it programmatically.  And I'm not aware of any compiler parameters which would do this.  (The simple filename is often compiled in, of course; that's how stack traces can show the filename and line number at which an exception was thrown.  But not the full path.)
Even your third method won't work in general; programs aren't usually run on the same machine on which they were compiled, so your code would have to make some very risky assumptions.
But I'm curious as to why you'd want to know this at all.  What problem are you trying to solve?

What is the purpose of actual keyword in Kotlin

I noticed that some functions for coroutines are marked with actual keyword.
From documentation:
actual denotes a platform-specific implementation in multiplatform
projects
As I understood from documentation actual keyword is used for multiplatform projects and should work in pair with expect keyword.
Something like this:
Common module:
package org.jetbrains.foo
expect class Foo(bar: String) {
fun frob()
}
fun main(args: Array<String>) {
Foo("Hello").frob()
}
Corresponding module:
package org.jetbrains.foo
actual class Foo actual constructor(val bar: String) {
actual fun frob() {
println("Frobbing the $bar")
}
}
That case is clear.
But in package kotlinx.coroutines.experimental I noticed that some functions like launch or withContext are marked as actual but there are no expect functions in package.
So what is the purpose of actual keyword without expect?
The kotlinx.coroutines library actually makes use of multiplatform projects since it supports both the JVM and JS compilation targets.
You can find the common module here, and the specific expect declarations for the functions you've mentioned here.
While the source code in the other answer helped, I found this page (linked off of the page #jim-andreas mentioned in the comments above) was much more helpful.
Specifically, this passage:
If you're developing a multiplatform application that needs to access platform-specific APIs that implement the required functionality (for example, generating a UUID), use the Kotlin mechanism of expected and actual declarations.
With this mechanism, a common source set defines an expected
declaration, and platform source sets must provide the actual
declaration that corresponds to the expected declaration. This works
for most Kotlin declarations, such as functions, classes, interfaces,
enumerations, properties, and annotations.
The compiler ensures that every declaration marked with the expect keyword in the common module has the corresponding declarations marked with the actual keyword in all platform modules. The IDE provides tools that help you create the missing actual declarations.
Again, for more information, you can visit this page.

Javassist NotFoundException when getting java.io.Serializable with JDK9

I have the following code:
private static CtClass resolveCtClass(String clazz) throws NotFoundException {
ClassPool pool = ClassPool.getDefault();
return pool.get( clazz );
}
When running under JDK8, if this method is called using java.io.Serializable, it works, but when running under the JDK9 environment, it throws the NotFoundException.
Is there something I overlooked here?
This does no longer happen with the current EA builds of Java 9. Class files are now always locatable even if they are encapsulated in a module.
This is a consequence of Java 9's module encapsulation where non-exported resources are no longer available via the ClassLoader API. Under the covers, Javassist calls
ClassLoader.getSystemClassLoader().findResource("java/io/Serializable.class");
to get hold of the class file for Serializable. It then parses this class file and represents the information similarly to the Java reflection API but without loading the class such that it can be edited prior to loading it.
Until Java 8, this class file was accessible as most class loaders rely on looking up a class file before loading it such that the above call returned a URL pointing to the file. Since Java 9, resources of named modules are only available via the new API method findResource(String, String) where the second arguments names the module of that class.
The short answer is: Javassist does no longer work with Java 9 and none of its dependant projects will. This is a known issue with the current Java 9 implementation and will hopefully be fixed prior to release.
(I never used Javassist so I'm just shooting in the dark, here...)
The documentation of ClassPool says:
If get() is called on this object, it searches various sources represented by ClassPath to find a class file and then it creates a CtClass object representing that class file.
This seems to be bound to the concept of the class path. Looking at ClassPath and CtClass supports that assumption.
If that is the case, then Javassist might just not be fit to look into JDK 9's brand new modules.
If my guess is correct, you should not be able to get any JDK class from the pool. This should be easily verifiable.

Find Self-Referential Code in IntelliJ

In IntelliJ when code is not used anywhere it will be "grayed out." Is there any way to see if a set of classes aren't used anywhere?
I have this set of classes with references to each other so IntelliJ is counting this set of classes as being used. In this case I know the code is useless but it would be nice to have the ability to automatically detect this sort of thing. The logic to do this isn't amazingly difficult... Does anyone know if this is possible in IntelliJ?
This "greyed out" mark simply reflects declaration usages in other source code files or framework configuration files. Declaration usage search cannot detect orphan clusters of classes as these classes are formally referenced.
There is a technique, that may help here: define some root set of entry points (main() methods, web.xml declarations, etc) and trace all the references, effectively building a graph of used classes/methods. Once graph is completed, you can treat unvisited classes as dead code. Pretty similar to what Java garbage collector does during young gen collection. It is quite difficult and resource consuming for on-the-fly code analysis, so Intellij has it implemented as a separate inspection one can run manually.
To demonstrate it let's create a fresh project containing the following code:
public class Main {
public static void main(String[] args) {
System.out.println(new Used());
}
}
class Used {}
class ObviouslyUnused {}
class TrickyUnused1 {
TrickyUnused1() {
System.out.println(new TrickyUnused2());
}
}
class TrickyUnused2 {
TrickyUnused2() {
System.out.println(new TrickyUnused1());
}
}
In the editor we can see, that only ObvoiuslyUnused is greyed out. Let's run an "Unused declaration" inspection:
and here we go, inspections shows, that our unused self-referenced class cluster is not reachable:
You should be aware, though, that there are always means of referencing code in implicit ways: reflection, native calls, runtime code generation, SPI implementations, references from framework configuration files, etc. So no static anlisys tool can be 100% accurate when detecting dead code.

How to enumerate all java classes in a directory in jython

I find it tedious to import a java class in jython because of the long package names. e.g. com.example.x.y.z.SomeClass. It's a lot of typing. I want to import by using only the simple name of the class (SomeClass in my example). Is there a way of achieving it? Current solution in my head is to enumerate all the classes in the classpath and prepare a map of simple class name to the complete package name like -
SomeClass -> com.example.x.y.z.SomeClass
SomeOtherClass -> com.example.p.q.r.SomeOtherClass
etc. Then call a function something like below-
def intelligent_import(simple_class_name):
#No error checking, simplified for clarity
package_name = dict[simle_class_name]
simple_class_name = __import__(package_name)
for each of the classes. The only problem is that I don't know a method to enumearte all classes in a directory. Is there's a better way to do this? If not a method to enumerate all java classes in a directory will do.
This is a bit of a hack, I'm sure there's better our there, but if everything else fails, remember that JAR files are just ZIPs, and that each class will have a .class file in the jar.
However, rather than hacking the import mechanism like this, I'd rather just use an IDE with proper autocompletion (i.e. Eclipse/PyDev, it's the only one that can do it reliably in my experience), and rock the ctrl-space.