Do we have a way to do some action with a lazy initializing object right after creation?
For example, smth like this:
val lazyInitObject by createLazyObject()
.apply {
// do some action with just created lazyInitObject
}
Not sure what your createLazyObject() is here, but with the standard lazy delegate you have full control over the initialization lambda:
val lazyInitObject by lazy {
createTheValue().also {
// do something with it
}
}
So if you want to allow this kind of thing you might want to design your custom delegate differently so it accepts a lambda.
Note that if what you want to do is only about changing the state of the lazily created object and not the enclosing class, you may want to simply use an init { } block in the object's class itself.
Using the build in object I can describe some of how Kotlin will allow you to do this, and will allow you to define this more specifically for your use case.
This can absolutely be accomplished with built in tools, if you need a more specific usage, the .also {} standard function will help you tack on functionality after any call
object MyObject {
fun myFunctions() {
println("I have done my work - MyObject")
}
init {
// Calls on first reference...
println("Hello world! - I am initialized - MyObject")
}
}
println("My app has started")
MyObject.myFunctions()
/*
This prints:
My app has started
Hello world! - I am initialized - MyObject
I have done my work - MyObject
*/
interface ILazy {
fun myFunction()
}
val myLazy: ILazy by lazy {
val myObject = object : ILazy {
override fun myFunction() {
println("myLazy has done its work")
}
init {
println("Object declarative is run instantly - MyLazy")
}
}
println("Post object declaration - Lazy")
myObject
}
myLazy.myFunction()
/*
This prints:
Object declarative is run instantly - MyLazy
Post object declaration - Lazy
myLazy has done its work
*/
Related
Suppose a Library's method takes a callback handler Handler, but for handling the result, the same logic is used over and over again. So, I created a class SimpleHandler that has the logic. The users that use that class are suppose to override its methods onSuccess onFail, if necessary. But if the handling is not necessary for the specific case, the user may not override them, and the SimpleHandler's default handler will be used.
The problem is that when I auto-complete the methods, the IDE automatically inserts super calls, like super.onFail(). For this code, as you see below, if it is overridden, the super method should not be called. Is there any way to mark that the super method should not be called when overridden, so the IDE will stop inserting it?
interface Handler
{
fun onFinished(result:Int);
}
abstract class SimpleHandler:Handler
{
override fun onFinished(result: Int)
{
if(result==0)
{
onSuccess();
}
else
{
onFail();
}
}
open fun onSuccess()
{
println("The developer is so lazy that he did not do anything.");
}
open fun onFail()
{
println("The developer is so lazy that he did not do anything.");
}
}
fun doSomething(handler:Handler)
{
handler.onFinished(10);
}
fun main(args: Array<String>)
{
doSomething(object: SimpleHandler(){
override fun onSuccess() {
println("I won! I won!");
}
override fun onFail() {
//super.onFail();
println("Me fail English?");
}
})
}
In IDEA/Android Studio, this is governed by Editor > File and Code Templates under Settings.
On my installation, I see Overridden Method Body and Overridden Scala Method Body but no special template for Kotlin. So I would expect Kotlin to be using the Java template.
You can change this template not to call super for a given method name, but it looks like you don't have access to the supertype's name. See the linked documentation for how templates can be shared.
AFAIK, there is no problem in writing something like this:
fun doSomething(handler:Handler, result: Int) {
handler.onFinished(result)
}
fun main() {
doSomething(object: SimpleHandler() {
override fun onFail() {
println("My custom message")
}
}, 10)
}
fun main2() {
doSomething(object : SimpleHandler() {
override fun onSuccess() {
println("My other custom message")
}
}, 0)
}
The developer only needs to override, if needed, the callback he's interested in.
In this case, in main() fails, it'll print "my custom message". If it succeeds, the default onSuccess() will be called.
The reverse is also true for main2(): If it succeeds, it'll print "My other custom message", but it it fails, it'll simply call the default onSuccess.
Tested on AS 3.1.1 with org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.31
You would need to define a separate lint detector for that.
Lint highlights overrides which should call super, but don't, by use of #CallSuper annotation, which is what this Lint detector enables:
https://cs.android.com/android/platform/superproject/+/master:tools/base/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/CallSuperDetector.java
Granted that might be something new to learn first, but writing custom Lint rules is not that hard. These are some good starting points:
Android Lint Tool Guide https://developer.android.com/studio/write/lint.html
2017 Kotlin Conference Lint Talk
https://www.youtube.com/watch?v=p8yX5-lPS6o
A previous question shows how to put a static initializer inside a class using its companion object. I'm trying to find a way to add a static initializer at the package level, but it seems packages have no companion object.
// compiler error: Modifier 'companion' is not applicable inside 'file'
companion object { init { println("Loaded!") } }
fun main(args: Array<String>) { println("run!") }
I've tried other variations that might've made sense (init on its own, static), and I know as a workaround I can use a throwaway val as in
val static_init = {
println("ugly workaround")
}()
but is there a clean, official way to achieve the same result?
Edit: As #mfulton26's answer mentions, there is no such thing as a package-level function really in the JVM. Behind the scenes, the kotlin compiler is wrapping any free functions, including main in a class. I'm trying to add a static initializer to that class -- the class being generated by kotlin for the free functions declared in the file.
Currently there is no way to add code to the static constructor generated for Kotlin file classes, only top-level property initializers are getting there. This sounds like a feature request, so now there is an issue to track this: KT-13486 Package-level 'init' blocks
Another workaround is to place initialization in top-level private/internal object and reference that object in those functions that depend on the effect of that initialization. Objects are initialized lazily, when they are referenced first time.
fun dependsOnState(arg: Int) = State.run {
arg + value
}
private object State {
val value: Int
init {
value = 42
println("State was initialized")
}
}
As you mentioned, you need a property with something that would run on initialisation:
val x = run {
println("The package class has loaded")
}
I got around it by using a Backing Property on the top-level, under the Kotlin file. Kotlin Docs: Backing Properties
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
// .... some other initialising code here
}
return _table ?: throw AssertionError("Set to null by another thread")
}
Let's say I declared a final field with private final String s (Java) or val s (Kotlin). During initialization I want to initialize the field with the result of a call to a remote service. In Java I would be able to initialize it in the constructor (e.g. s = RemoteService.result()), but in Kotlin I can't figure out how to do that because as far as I can tell the field has to be initialized in the same line it's declared. What's the solution here?
You can set val value in init block:
class MyClass {
val s: String
init {
s = "value"
}
}
You can also initialize the value with by lazy the value will be initialized the first time it is referred. An example
val s by lazy { RemoteService.result() }
kotlin will guess the type of s from the return type of the expression.
You can use run:
class MyClazz {
val prop = run {
// do stuff
// do stuff again
123 // return expression
}
}
From the docs (emphasis is mine):
Besides calling run on a receiver object, you can use it as a non-extension function. Non-extension run lets you execute a block of several statements where an expression is required.
It has been possible to do it simply like this since the very first official stable release of Kotlin:
class MyClass {
val s = RemoteService.result()
}
I'm trying to keep this minimal, but let me know if I'm being too minimal.
Suppose you have a class hierarchy like this, designed for generating HTML (inspired by the Kotlin tutorial; semi-pseudocode follows):
class Tag {
protected val children = arrayListOf<Tag>()
operator fun String.unaryPlus() = children.add(Text(this))
}
class TagWithChildren : Tag() {
fun head(init: Head.() -> Unit) = initializeTag(Head(), init)
fun script(init: Script.() -> Unit) = initializeTag(Script(), init)
fun <T : Tag> initializeTag(tag: T, init: T.() -> Unit): T {
tag.init()
children.add(tag)
return tag
}
}
class Head : TagWithChildren()
class Script : Tag()
class Text(val str: Text) : Tag()
Notice that Head has head and script methods while Script doesn't.
Now you can construct a template that looks like this:
head {
script {
+"alert('hi');"
}
}
Which works great! However, if the block passed to script tries to call methods that aren't available on Script, it can call the method on Head instead. For example,
head {
script {
script {
+"alert('hi');"
}
}
}
not only isn't a compile error, it's actually equivalent to
head {
script {
}
script {
+"alert('hi');"
}
}
which is super confusing, from a template author's perspective.
Is there any way to prevent method lookups from traveling up the scope like that? I only want it to look at the innermost scope.
UPDATE 11/24/2016:
Kotlin 1.1-M03 has introduced scope control, which I believe solves exactly this problem. https://blog.jetbrains.com/kotlin/2016/11/kotlin-1-1-m03-is-here/
The current behavior is intentional. Code in a lambda has access to receivers of all enclosing scopes. It is possible that a future version of Kotlin will add a modifier that will restrict a lambda with receiver to calling methods on that receiver only and not the enclosing scopes, but in the current version there's no way to change that behavior.
As a workaround, I can have it fail at runtime if I change the classes to look like this:
open class Tag {
operator fun String.unaryPlus()
// pulled up from TagWithChildren, call protected method
fun head(init: Head.() -> Unit) = addChild(Head())
fun script(init: Script.() -> Unit) = addChild(Head())
// throws in Tag
open protected fun addChild(t: Tag) = throw IllegalArgumentException()
}
class TagWithChildren : Tag() {
// overridden to not throw in subclass
protected override fun addChild(t: Tag) = children.add(t)
}
This way, every Tag has the builder methods (solving the scoping problem), but actually calling them may result in a runtime failure.
In Kotlin, is there a way to reference the listener instance when using this short notation for anonymous classes? In this case this refers to outer context (e.g. the Activity instance) where view is defined:
view.setOnClickListener {
val self: View.OnClickListener = this // Not compiling, "this" references outer context
}
When using the longer notation where you explicitly state the interface to be implemented and where you explicitly override the callback method, the listener can be referenced through this:
view.setOnClickListener(object: View.OnClickListener {
override fun onClick(v: View) {
val self: View.OnClickListener = this // Ok
}
})
You can get that resolved by adding an #ActivityName in front of 'this' reference
For example if your Activity name was MainActivity the solution would be:
view.setOnClickListener {
val self: View.OnClickListener = this#MainActivity
}
The term short notation for anonymous classes is not entirely correct. It's actually a short notation for anonymous functions, i.e. lambdas. Of course under the hood they are compiled to classes but from a programming language point of view, anonymous functions don't have identities and therefore it doesn't make sense to refer to their instances via this.
val animation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
val layoutParam: RelativeLayout.LayoutParams? = playerView.layoutParams as RelativeLayout.LayoutParams?
layoutParam?.topMargin = convertDpToPixel(position, this#SurahActivity).toInt()
playerView.layoutParams = layoutParam
}
}
Somewhat related - here is an example of removing a listener from the listener itself that came about after not being able to refer to itself as reported by the accepted answer
#Suppress("JoinDeclarationAndAssignment")
fun View.foo() {
// can't combine this with the assignment since it is referenced within the
// body of the layout listener to remove itself
lateinit var layoutListener: ViewTreeObserver.OnGlobalLayoutListener
layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
// ... do something ...
viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
}
viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
}
I don't typically see lateinit used in a local method field so this wasn't immediately obvious to me