Statements in Kotlin constructor - constructor

Is there a way to mix statements (like print statements) and member assignments in Kotlin?
Here is an example of what I would like to do (in Java):
class MySystem {
ComponentA componentA;
ComponentB componentB;
public MySystem() {
System.out.println("Initializing components");
this.componentA = new ComponentA();
System.out.println("Constructed componentA");
this.componentB = new ComponentB();
System.out.println("Constructed componentB");
}
}
Grateful for any input, thanks.

Yes, there is: use the init blocks. The init blocks and property initializers are executed in the same order as they appear in the code:
class MyClass {
init { println("Initializing components") }
val componentA = ComponentA()
init { println("Constructed componentA") }
val componentB = ComponentB()
init { println("Constructed componentA") }
}
Or, alternatively, separate the declaration and initialization:
class MyClass {
val componentA: ComponentA
val componentB: ComponentB
init {
println("Initializing components")
componentA = ComponentA()
println("Constructed componentA")
componentB = ComponentB()
println("Constructed componentB");
}
}
This will also work with secondary constructors.

Declare the fields and use an init block:
internal class MySystem {
val componentA: ComponentA
val componentB: ComponentB
init {
println("Initializing components")
this.componentA = ComponentA()
println("Constructed componentA")
this.componentB = ComponentB()
println("Constructed componentB")
}
}

Related

Kotlin: Initialize class attribute in constructor

I create a Kotlin-class with a class attribute, which I want to initialize in the constructor:
public class TestClass {
private var context : Context? = null // Nullable attribute
public constructor(context : Context) {
this.context = context
}
public fun doSomeVoodoo() {
val text : String = context!!.getString(R.string.abc_action_bar_home_description)
}
}
Unfortunately I have to declare the attribute as Nullable with the "?" sign, although the attribute will be initialized in the constructor. Declaring this attribute as Nullable-attribute makes it always necessary to force an NonNull-value with "!!" or to provide a Null-check with "?".
Is there any way to avoid this, if the class attribute will be initialized in the constructor? I would like to appreciate a solution like this one:
public class TestClass {
private var context : Context // Non-Nullable attribute
public constructor(context : Context) {
this.context = context
}
public fun doSomeVoodoo() {
val text : String = context.getString(R.string.abc_action_bar_home_description)
}
}
As shown by D3xter you have the option of setting it in the constructor. You also have other options. Here they all are...
Create the property within the constructor (as per #D3xter), this is the most common case for simple properties initialized directly by the primary constructor:
class TestClass(private val context: Context) {
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
You can declare the val property and not initialize it, assuming all possible constructors do actually initialize it (as per your second example in the question being asked). This is normal when you have more than one constructor that could initialize a value differently:
public class TestClass {
private val context: Context
public constructor(context : Context) {
this.context = context
}
// alternative constructor
public constructor(pre: PreContext) {
this.context = pre.readContext()
}
public fun doSomeVoodoo() {
val text : String = context.getString()
}
}
You can pass in constructor parameters that are not property declarations, and then use those within property initializations. This is common when you have more complex initializations or need to use delegated properties:
class TestClass(context: PreContext) {
private val context : Context by lazy { context.readContext() }
private val other: List<Items> = run {
context.items.map { it.tag }.filterNotNull()
}
private val simpleThing = context.getSimple()
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
Using lateinit modifier when you cannot initialize the value during construction, but you are sure it will be done before your first read access. This is common when a dependency injection, IoC container, or something creates an empty version of your class and then initializes it immediately:
class TestClass() {
private lateinit var context : Context // set by something else after construction
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
For lateinit the property must currently be a var and does not work with primitive types.
You can also declare a var property and not initialize it if you use a delegate designed for that purpose, such as Delegates.notNull(). This is similar to lateinit and common when you want a var that has no initial state, but is set later after construction at unknown point in time:
public class TestClass() {
private var context: Context by Delegates.notNull()
public fun doSomeVoodoo() {
// if context is not set before this is called, an exception is thrown
val text : String = context.getString()
}
}
If the only thing you are doing in the constructor is an assignment,
then you could use the Primary Constructor with a private Property.
e.g:
public class TestClass(private val context: Context) {
public fun doSomeVoodoo() {
val text = context.getString(R.string.abc_...)
}
}
I had a similar problem where I didn't want to hold onto the object after construction. Using lazy or lateinit resulted in inefficient bytecode so after some research I settled on this approach and returned to post the answer in case it helps:
Solution
class TestClass(context: Context) {
private val homeDescription: String
init {
homeDescription = context.getString(R.string.abc_action_bar_home_description)
}
fun doSomeVoodoo() {
val text : String = homeDescription
}
}
alternatively, the above can be further simplified into:
class TestClass(context: Context) {
private val homeDescription: String = context.getString(R.string.abc_action_bar_home_description)
fun doSomeVoodoo() {
val text : String = homeDescription
}
}
Decompiled Bytecode
And the decompiled java version of this feels a bit more acceptable than the other approaches and no reference to the context is held after construction:
public final class TestClass {
private final String homeDescription;
public final void doSomeVoodoo() {
String text = this.homeDescription;
}
public TestClass(#NotNull Context context) {
Intrinsics.checkParameterIsNotNull(context, "context");
super();
String var10001 = context.getString(2131296256);
Intrinsics.checkExpressionValueIsNotNull(var10001, "context.getString(R.striā€¦ion_bar_home_description)");
this.homeDescription = var10001;
}
}

Attempted to assign to readonly property ECMAScript React Native

I am trying to assign a value to an array declared in my Component. Unfortunately, exception is thrown.
TypeError: Attempted to assign to readonly property
Even if I remove strict mode, still exception is being raised. Can please someone guide me how can I make a variable both readable and writable? Thanks..!
Code:
class RootView extends Component {
cachedData : []; //declared array here
//trying to assign dictionary in some function
someFunction(results) {
this.cachedData[this.state.searchString.length - 1] = results;
//exception raised here
}
}
Your syntax is incorrect. Add it to a constructor.
class RootView extends Component {
constructor() {
super();
this.cachedData = [];
}
someFunction(results) {
this.cachedData[this.state.searchString.length - 1] = results;
}
}
If your transpiler supports experimental code (stage 0), you can use the following:
class RootView extends Component {
cachedData = [];
someFunction(results) {
this.cachedData[this.state.searchString.length - 1] = results;
}
}

Linking a massive amount of string keys to classes using a static dictionary-like class

Currently, I have two classes MC_Dictionnary_Bad, and MC_Dictionnary_Good, initialized like so:
package classes
{
import flash.utils.Dictionary;
public dynamic class MC_Dictionnary_Bad extends Dictionary
{
public function Custom_Dictionary()
{
this["monster,0,0,0"] = "Monster_Light_Swanp_Red";
this["monster,0,0,1"] = "Monster_Light_Swanp_Blue";
this["monster,0,0,2"] = "Monster_Light_Swanp_Yellow";
this["monster,0,0,3"] = "Monster_Light_Swanp_Dark";
...
}
}
}
They are initialized during loading, and are saved like so during the entire game.
I need to link a name and three indexes to class names, so I can create the appropriate class when needed, given user input.
However, I don't want to use a dynamic class.
Is there a clean way not to use a dynamic class here?
There's no need to extend Dictionary for this model - simply have two dictionaries in a class:
package {
import flash.utils.Dictionary;
public final class Game {
protected var MC_Dictionnary_Bad:Dictionary = new Dictionary();
protected var MC_Dictionnary_Good:Dictionary = new Dictionary();
public function Game() {
initialize();
}
protected function initialize():void {
MC_Dictionnary_Bad["monster,0,0,0"] = "Monster_Light_Swanp_Red";
MC_Dictionnary_Bad["monster,0,0,1"] = "Monster_Light_Swanp_Blue";
MC_Dictionnary_Bad["monster,0,0,2"] = "Monster_Light_Swanp_Yellow";
MC_Dictionnary_Bad["monster,0,0,3"] = "Monster_Light_Swanp_Dark";
}
}
}
If your keys are always strings, this could be defined as JSON which would also enable easy data loading. Instead of embedding the object in your app, it could be loaded from a url and parsed.
package {
public final class Game {
protected var monsters:Object = {
"good": {
"monster": {
0: {
0: {
0: "Monster_Light_Swanp_Red",
1: "Monster_Light_Swanp_Blue",
2: "Monster_Light_Swanp_Yellow",
3: "Monster_Light_Swanp_Dark"
}
}
}
},
"bad": {
/* etc... */
}
};
public function Game() {
// Example accessor:
trace(monsters["good"]["monster"][0][0][1]);
}
}
}

How to access a public array/vector from another class

I have a vector in my Main class file that store objects. I will like to be able to add more objects to that SAME vector from a different class. I gave the vector in my main class the "public" modifier. I now need the syntax to reference it in my other class file
public var badChar:Vector.;
You have options. How you approach it is dependent on your project setup, and the needs of the property. Is it an instantiated object, or should there ever only be one (even if the class is instantiated multiple times)? Do you need direct access to it regardless of any relationship to the stage? Each solution below has pros and cons.
Class-to-Class via Stage
Assuming the following main foo.as class:
package {
public class Foo {
public var bool:Boolean = true;
}
}
Bar class:
package {
public class Bar extends Sprite {
import flash.events.Event;
public function Bar() {
addEventListener(Event.ADDED_TO_STAGE, accessFoo);
}
private function accessFoo(e:Event):void {
trace(this.parent["f"].bool); // traces "true"
}
}
}
Document Code:
var f:Foo = new Foo();
var b:Bar = new Bar();
addChild(b);
Inheritance
Foo Class:
package {
public class Foo {
public var bool:Boolean = true;
}
}
Bar Class
package {
public class Bar extends Foo {
public function Bar() {
trace(bool); // traces "true"
}
}
}
Class-to-Class via Static
Some disclaimers should be in order for Static properties, but I'll leave you to read up on those.
Foo Class:
package {
public class Foo {
public static var bool:Boolean = true;
}
}
Bar Class
package {
public class Bar {
public function Bar() {
trace(Foo.bool); // traces "true"
}
}
}
Direct Access via New Declaration
Foo Class:
package {
public class Foo {
public var bool:Boolean = true;
}
}
Bar Class
package {
public class Bar {
import Foo;
public function Bar() {
trace(new Foo().bool); // traces "true"
}
}
}
Access via Sharing
Foo Class:
package {
public class Foo {
public var bool:Boolean = true;
}
}
Bar Class
package {
public class Bar {
import Foo;
public var fluffy:Foo;
public function Bar() {
trace(fluffy.bool);
}
}
}
Document Code:
var f:Foo = new Foo();
var b:Bar = new Bar();
b.fluffy = f;
Note that after the third line in the document code, fluffy is no longer an undeclared variable and will now point to the f object, where the properties updated in it (such as bool) will reflect inside of Bar.

Defining a constructor of a private class

Queue and airportSim classes are defined.
class Queue
{
public:
Queue(int setSizeQueue = 20);
//Queue's contents
}
class airportSim
{
public:
airportSim(int setSizeRunway = 20);
private:
Queue airQueue;
Queue groundQueue;
//Other airportSim contents.
}
Queue::Queue(int setSizeQueue)
{
//Contents of airportSim constructor supposed to come here.
}
airportSim::airportSim(int setSizeRunway)
{
airQueue(setSizeRunway);
groundQueue(setSizeRunway);
}
It says it has trouble accessing the constructors. Anyone know how to define the constructor of the queues?
Use the initialization list syntax:
airportSim::airportSim(int setSizeRunway)
: airQueue(setSizeRunway),
groundQueue(setSizeRunway)
{
}