Companion object with extension function in kotlin? - kotlin

I would like to have extension function and use logger from kotlin-logging and have constants inside companion object.
My function:
fun String.toFoo(): Foo {
logger.debug { "Mapping [$this] to Foo" }
if(MY_CONST.equals(this) {
...
}
Question is where I should put val logger = KotlinLogging.logger {} and MY_CONST since I cannot use companion object with an extension function?

If you just want you logger to be a singleton you can make an object that contains and instance of the logger and reach it from there.
Object LoggerSingleton( val logger = KotlinLogging.logger{})
Then in your extension function
fun String.toFoo(): Foo {
LoggerSingleton.logger.debug { "Mapping [$this] to Foo" }
if(MY_CONST.equals(this) {
}
Since an Object in Kotlin is guaranteed to have only one instance you won't have a different logger for each use of toFoo.
EDIT
To keep the desired class name
Use this signature
Like so:
Object StringLoggerSingleton( val logger = KotlinLogging.logger("String"))

I do not know what you want to accomplish with your logger, but I show you what I did already ;-)
Usually I put extension functions in its own file named similar to what the function is actually extending (e.g. either StringExtensionFunction or if is more related to its purpose and maybe only available if certain dependencies are available, I also did something like, e.g. JsoupExtensionFunctions (where there was a String.toJsoupHtml(), File.toJsoupXml(), etc.)).
If I then need constants I just place them within that file, e.g. by just writing something like:
private const val MY_CONST = "my_const_value"
No surrounding class, no surrounding object.
Regarding the logger... as loggers are usually tied to a certain name/class, I usually put a logger inside every (important) class or associate some logger to specific names... So I am not completely sure what your intent is here... If it's ok for you that the logger is returning the container of your extension function (maybe StringExtensionFunction.kt), then you can also put a logger-val inside that file similar to what I showed with MY_CONST.
If your intention was rather to reuse the callers logger, that might not work so easily... (the easiest would then probably be to pass it to the function, but usually you do not want that)... and other mechanisms may not really be worth it ;-)

Related

Kotlin constructor val vs private val

If I have something like the following:
interface IRecordService {
fun doSomething () : Record
}
#MongoRepository
interface IRecordRepository : MongoRepository<Record, String> {
}
#Service
class RecordService (
private val recordRepository : IRecordRepository // or just val instead of private val
) : IRecordService
{
override fun doSomething () : Record {
// does something
}
}
Is there any difference between using private val in the RecordService constructor vs just val? I've seen both being used but couldn't tell if there was a recommended way or why.
This isn't specific to Spring or Mongo; it's just core Kotlin. There are several things going on here; I'll try to unpick them.
Consider the simpler definition:
class MyClass(i: Int)
The parens specify the primary constructor: any parameters there (such as i) are passed into the class, and are available during construction. So you could pass them up to the superclass constructor, use them in property initialisers, and/or in an init block:
class MyClass(i: Int) : MySuperclass(i) {
val someProperty = i
init {
println("i is $i")
}
}
However, they don't persist after the instance has been constructed — so you couldn't refer to them in methods, or from outside the class.
If you want to do that, you have to define a property for each parameter you want to persist. You could do that explicitly, e.g.:
class MyClass(i: Int) {
val i2 = i
}
Here every instance of MyClass has a property called i2 which is initialised to the i constructor parameter.
However, because this is a common pattern, Kotlin provides a shortcut. If you specify val or var in the primary constructor:
class MyClass(val i: Int)
then Kotlin creates a property with the same name as the parameter, and initialises it for you. So every instance of the above class has a property called i that you can refer to at any time.
By default, properties in Kotlin are public: you can access them from inside the class, from subclasses, from other classes in the same module, and from any other code that has a MyClass instance.
However, in some cases it's useful to restrict access, so you can add a visibility modifier: internal prevents code in other modules from seeing it, protected allows only subclasses to see it, and private makes it visible only inside the class itself.
So, to answer your question: without the private modifier, any code that had access to your RecordService would be able to access its recordRepository property; adding private prevents that, and means that only code within RecordService can see it.
In general, it might be a good idea to centralise all access to the recordRepository in the one class; then making it private would ensure that no other code can muck around with it. That would make it easier to see what's going on, easier to debug, and safer to work on. (However, we obviously don't know about the rest of your program, and can't advise on whether that would be a good plan in your case.)
By the way, using an I prefix for interfaces is not a convention that's used much in Kotlin (or Java). There's often little point in having an interface with only one implementation; and if you could have multiple implementations, then better to use a simple term for the interface and then more specific terms for the implementations.  (For example: the List interface with ArrayList and LinkedList classes, or Number with Int and Long.)
If you put val, it will be a constructor parameter and property. If you don't, it will be a constructor parameter (NOT property).
See Why to put val or var in kotlin class constructors
Firstly if you use val it converts this constructor parameter to property,If you do not want to hide this property (to set it) from other classes,you can use val.But if you do not want your property to be changed by other classes you should use private val instead.
Well, you can use both val and private val in your constructor there's no problem in that, it's just that with private keyword your properties wont be modified or accessed by some other class, so it basically provides some data hiding. If you talking about difference in functionality inside your RecordService class, then no there wont be any difference.

What is the benefit of having a private constructor and a use a method inside companion object to instantiate a class?

I've bumped into this code and I'm not sure why would anyone do this. Basically the author decided for making the class constructor private so that it cannot be instantiated outside the file, and added a public method to a companion object in the class that creates a new instance of this class. What is the benefit of this approach?
This is what I found:
class Foo private constructor(private val arg1: Any) {
//more code here..
companion object {
fun newFoo(arg1: Any) = Foo(arg1 = arg1)
}
}
Why is it better than this?
class Foo(private val arg1: Any) {
//more code here..
}
There are several benefits to providing a factory method instead of a public constructor, including:
It can do lots of processing before calling the construstor. (This can be important if the superclass constructor takes parameters that need to be calculated.)
It can return cached values instead of new instances where appropriate.
It can return a subclass. (This allows you to make the top class an interface, as noted in another answer.) The exact class can differ between calls, and can even be an anonymous type.
It can have a name (as noted in another answer). This is especially important if you need multiple methods taking the same parameters. (E.g. a Point object which could be constructed from rectangular or polar co-ordinates.) However, a factory method doesn't need a specific name; if you implement the invoke() method in the companion object, you can call it in exactly the same way as a constructor.
It makes it easier to change the implementation of the class without affecting its public interface.
It also has an important drawback:
It can't be used by subclass constructors.
Factory methods seem to be less used in Kotlin than Java, perhaps due to Kotlin's simpler syntax for primary constructors and properties. But they're still worth considering — especially as Kotlin companion objects can inherit.
For much deeper info, see this article, which looks at the recommendation in Effective Java and how it applies to Kotlin.
If you want to change Foo into an interface in the future the code based on the method will keep working, since you can return a concrete class which still implements Foo, unlike the constructor which no longer exists.
An example specific to android is, that Fragments should be constructed with an empty constructed, and any data you'd like to pass through to them should be put in a bundle.
We can create a static/companion function, which takes in the arguments we need for that fragment, and this method would construct the fragment using the empty constructor and pass in the data using a bundle.
There are many useful cases, for example what Kiskae described. Another good one would be to be able to "give your constructors names":
class Foo<S: Any, T: Any> private constructor(private val a: S, private val b: T) {
//more code here...
companion object {
fun <S: Any> createForPurposeX(a: S) = Foo(a = a, b = "Default value")
fun createForPurposeY() = Foo(a = 1, b = 2)
}
}
Call site:
Foo.createForPurposeX("Hey")
Foo.createForPurposeY()
Note: You should use generic types instead of Any.

KClass::memberExtensionFunctions always be empty

Code
import kotlin.reflect.full.*
class FooBar(val bar: String)
fun FooBar.baz(): Unit {println(this.bar)}
fun main(args: Array<String>) {
FooBar::class.declaredMemberExtensionFunctions.forEach {
println(it)
}
FooBar::class.memberExtensionFunctions.forEach {
println(it)
}
}
Output is empty
This is because declaredMemberExtensionFunctions only returns extension functions that are declared inside a class (as seen in the docs) and FooBar.baz() is a top level declaration (So it is not declared inside FooBar.
class FooBar(val bar: String) {
fun FooBar.baz(): Unit {
println(this.bar)
}
}
While I imagine this is not what you want, structuring the extension function like this would make your main method output lines.
TLDR: You aren't going to be able to do this. Because extension functions can be declared everywhere, you are limited in what the reflection system can do for you.
There is a thread on kotlinlang.org that covers this exact question and why it is not possible.
Essentially, Kotlin's declaredMemberExtensionFunctions function is able to list extension functions which are declared as part of the class, not externally. The docs state:
Returns extension functions declared in this class.
And of course, memberExtensionFunctions behaves similarly:
Returns extension functions declared in this class and all of its superclasses.
Here's what #Yole says in that thread as to why this is not possible:
The task of finding all extension functions for Foo is equivalent to finding all methods which have Foo as the first parameter. Neither of these is possible without accessing every single class in your application through reflection.
#Yole is on here, he might be able to provide a more authoritative answer for you.

Kotlin: Difference between constant in companion object and top level

The general pattern to create constants in Kotlin seems to be using companion objects. However, I can also define a constant at the file level. Why is that not so popular? Am I missing something?
With companion object:
class Example {
companion object {
const val CONSTANT = "something"
}
On top level:
const val CONSTANT = "something"
class Example {
}
In Java you're forced to put all static field and method declarations in a class and often you even have to create a class just for that purpose. Coming to Kotlin, many users look for the equivalent facility out of habit and end up overusing companion objects.
Kotlin completely decouples the notions of a file and a class. You can declare any number of public classes in the same file. You can also declare private top-level functions and variables and they'll be accessible only to the classes within the same file. This is a great way to organize closely associated code and data.
Compared to top-level declarations, the syntax of companion objects is quite unwieldy. You should use them only when you specifically want to associate some public static code or data with a class and want your users to qualify access to it with the class's name. The use cases for this are quite rare and in most cases the top-level declarations are more natural.
Whenever you have some private static code/data that you want to couple to a class, you'll be better served with private top-level declarations.
Finally, sometimes the concern of the generated bytecode matters. If, for whatever reason, you have to produce a Java class with Kotlin code such that the class has a static member, you must resort to a companion object and a special annotation.
Differences in usage
Defining the field in a companion object limits the scope it is available in without importing to only that class, which can help keeping the data from being used in unexpected places.
Defining in the file makes the field available to any code in the same package as the field.
Differences in Bytecode
const val CONSTANT = "something"
class Example {
}
Creates the following:
Example.java
public final class Example {}
XKt.java
import kotlin.Metadata;
import org.jetbrains.annotations.NotNull;
public final class XKt {
public static final String CONSTANT = "something";
}
Whereas:
class Example {
companion object {
const val CONSTANT = "something"
}
}
Creates the following:
public final class Example {
public static final String CONSTANT = "something";
public static final Example.Companion Companion = new Example.Companion((DefaultConstructorMarker) null);
public static final class Companion {
private Companion() {}
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
I think that basically depends on whether you want that constant to be part of a class. If you put it inside a companion object, it will be accessed like this:
Example.CONSTANT
If you choose to put a constant on file level, it will be imported from other files and accessed with simply CONSTANT normally.
There are reasons for putting constants in classes as well as for putting them top-level.
Note that the const keyword can only be applied to variables of type String or primitive types (Int etc.) (reference). For most cases though, there's no need to apply the keyword. Defining constant values as shown in the following works as well:
val constantFIS = FileInputStream("path")
Sometimes you actually need to put constant outside of companion object. Apparently constants in companion objects are not that “that much” constant as one would suppose. For instance:
internal const val MY_FOO = "It's my ${Foo.FOO}";
open class Foo {
internal companion object {
const val FOO = "foo";
}
}
#Kaboom(name=MY_FOO)
open class Bar {}
Above code is not compiling. As long some “constans” are part of companion objects, they're not really constants. But when you move FOO outside of companion object, everything works.
On the other hand I'd like the compiler to do the work for me and to find out if it is possible to functionally turn some static final field to a constant or not. Why should I put my effort and time to decide what is or is not a literal constant for the compiler? It is just wrong.

Can extension functions be called in a "static" way?

Is it possible to create an extension function and call it as if it were static?
For Example...
fun System.sayByeAndExit() {
println("Goodbye!")
System.exit()
}
fun main(args: Array<String>) {
System.sayByeAndExit() // I'd like to be able to call this
}
I know that the code sample doesn't work...
I understand that kotlin's extension functions are resolved statically, as mentioned in the Kotlin Reference (Extension Functions), but this does not mean they can be called as if they were static functions within a class (in a Java sense).
I also understand that this code will not work because there is no instance of System to pass into the method that the compiler will generate; therefore it won't compile.
Why would I want this?
Some of you might be wondering why this behaviour is desirable. I can understand why you would think that is isn't, so here are some reasons:
It has all of the benefits that standard extension functions give.
An instance of the class doesn't need to be created just to access the extra functionality.
The functions can be accessed from an application-wide context (provided the class is visible).
To summarise...
Does Kotlin have a way to "hook" a static function onto a class? I'd love to know.
You are really asking for "extension functions for a Class reference" or "adding static methods to existing classes" which was covered by another question here: How can one add static methods to Java classes in Kotlin which is covered by a feature request KT-11968
Extension functions cannot be added to anything that does not have an instance. A reference to a Class is not an instance and therefore you cannot extend something like java.lang.System. You can however extend a companion object of an existing class. For example:
class LibraryThing {
companion object { /* ... */ }
}
Allows you to extend LibraryThing.Companion and therefore calling some new myExtension() method would look like you are extending the Class reference itself, when really you are extending the singleton instance of the companion object:
fun LibraryThing.Companion.myExtension() = "foo"
LibraryThing.Companion.myExtension() // results in "foo"
LibraryThing.myExtension() // results in "foo"
Therefore you might find some Kotlin libraries add empty companion objects just for this case. Others do not, and for those you are "out of luck." Since Java does not have companion objects, you cannot do the same for Java either.
The other commonly requested feature is to take an existing Java static method that accepts an instance of a class as the first parameter, and make it behave as an extension function. This is tracked by issues KT-5261, KT-2844, KT-732, KT-3487 and probably other feature requests.
You can define extension function for an object and use it from system-wide context. An object will be created only once.
object MyClz
fun MyClz.exit() = System.exit(0)
fun main(args: Array<String>) {
MyClz.exit()
}
Or
class MyClz {
companion object
}
fun MyClz.Companion.exit() = System.exit(0)
fun main(args: Array<String>) {
MyClz.exit()
}