When a condition is met -> convert public variable to private - kotlin

I am new to Kotlin and I was wondering if there is a way to make a variable that is originally public - to private, if a certain condition is met. And if the condition is met and the variable is private skip certain part of the program - something like the "go to" option in C.
For example:
var a = 10
var b = 20
if a == 10 -> make b private
go to fun something()
else -> b stays public
->continue the normal flow of the program

Related

Why am I able to have null values in non-null variables?

Here is my kotlin class:
class Test{
val x: String = run {
y
}
val y: String = run {
x
}
}
The variables x and y both end up as null, despite being declared as non-nullable strings.
You can run it here. As you can see, you end up with null pointer exceptions from trying to call methods on x or y.
Why is this possible? How can you really have null safety with this in mind?
Well this is what your class decompiles to in Java:
public final class Test {
#NotNull
private final String x;
#NotNull
private final String y;
#NotNull
public final String getX() {
return this.x;
}
#NotNull
public final String getY() {
return this.y;
}
public Test() {
Test $this$run = (Test)this;
int var3 = false;
String var5 = $this$run.y;
this.x = var5;
$this$run = (Test)this;
var3 = false;
var5 = $this$run.x;
this.y = var5;
}
}
So your backing fields, x and y are declared first. They're not assigned a value yet so, in Java, that means their value is null because that's the default for an unassigned object reference.
After the getters, you have the constructor which is where the assignation is taking place. There are a few weird variables going around, but
Test $this$run = (Test)this;
is basically creating a variable that refers to this, the current object. And we can kinda reduce the assignment code down to
this.x = this.y // y is null, so x is set to null
this.y = this.x // x is null, so y is set to null
Because that default value for object references is null, whichever of your assignments runs first will always be reading a null value from the other variable (which, remember, you haven't explicitly assigned a value to yet).
Basically the order of initialisation matters in Kotlin, you can't refer to something that hasn't been declared yet. Like this won't work either:
class Thing {
val a = b
val b = "hi"
}
On the line where a is being assigned, the value of b is currently undefined. It won't run on the JVM either, because that code decompiles to basically this:
public final class Thing {
#NotNull
private final String a;
#NotNull
private final String b;
public Thing() {
this.a = this.b;
this.b = "hi";
}
}
and that this.a = this.b line will fail because "b may not have been initialised yet". You can get around that with the same trick in the decompiled version of your code, with the other variable assigned to this:
public Thing() {
Thing thing = (Thing) this;
this.a = thing.b;
this.b = "hi";
}
which will run, but a ends up assigned with the default value of null.
So basically, the code you're using is a tricky way to get around that kind of error and ultimately give you unexpected behaviour. Obviously your example is unrealistic (the results of a = b = a are inherently undefined), but it can happen with this kind of code too, where initialisation goes through other functions:
class Wow {
val a = doSomething()
val b = 1
fun doSomething() = b
}
In this case a ends up 0 on the JVM, the default value for an int, because when assigning a it basically goes on a detour through a function that reads b before that's been assigned its value. Kotlin (currently) doesn't seem to be capable of checking the validity of this kind of thing - so you'll run into problems trying to initialise things via functions sometimes:
class Wow {
// unassigned var
var a: Int
val b = 1
init {
// calls a function that assigns a value to a
doSomething()
}
fun doSomething() { a = 5 }
}
That will fail because it can't determine that a has been initialised, even though the init block does so, because it's happening as a side effect of another function. (And you could bury that assignment in any number of chained calls, which is probably why it's not a thing that's been "fixed" - if you start making guarantees about that kind of thing, it needs to be consistent!)
So basically, during initialisation you can do things which the compiler isn't able to catch, and that's how you can get around things like non-null guarantees. It doesn't come up often, but it's something to be aware of! And I'm only familiar with the JVM side, I'm assuming the undefined behaviour is platform-specific.
According to the Kotlin docs, "Data inconsistency with regard to initialization" can result in a NullPointerException.
Here are a couple links related to the topic:
https://kotlinlang.org/docs/null-safety.html#nullable-types-and-non-null-types
https://kotlinlang.org/docs/inheritance.html#derived-class-initialization-order
Edit: An example of a wrong answer! It's not circular: x is initialised to null because y is null at the time x is initialised (being uninitialised).
Well, it's circular. x is not null because y is not null which is not null because x is not null.
So it's not a valid program. Meaningful type inference can only be applied to valid programs.

Preventing mistakes with property declaration order

I'm looking for a way to prevent problems in Kotlin with the order of property initialization. One of my biggest loves of Kotlin is all the ways you can lean on the compiler to prevent errors. But in this case it falls flat. Here's an example
class Test{
val b = computeB()
val a = computeA()
private fun computeA() = 4
private fun computeB() = a + 1
}
fun main(args: Array<String>) {
val a = Test()
println("value of b: " + a.b)
println("value of a: " + a.a)
}
In this scenario, you get a = 4 and b = 1. But you should get b = 5. I understand what's going on, a is not initialized yet so it defaults to 0 when it's accessed. I was hoping that Kotlin would at least throw an exception to let me know.
This is a trivial example, but in large classes with lots of code it's easy to accidentally do this. My question is, what is the best style/paradigm/pattern that I can use in Kotlin to ensure this kind of mistake doesn't happen. I'm looking for some sort of rule that I can hold myself, and my teammates to. Like "you should construct properties in this way, because otherwise you open the door to these kinds of bugs".
The thing that you really shouldn't do here is to call methods on this in the property initialiser, because as you have identified, this at that point is not fully initialised, and the method will see unspecified values for some of the properties it depends on.
So the first thing is to avoid calling instance methods, if you can.
I know this is just an example, but there is really no need to call a method just to say "4" and "a + 1". If you inline both of your methods, you get:
val b = a + 1
val a = 4
If the initialisation does need to call an instance method, use lazy:
val b by lazy { computeB() }
val a = 4
Another idea is to rewrite your functions to take the things they depend on as parameters:
private fun computeB(a: Int) = a + 1
This way, you will get an error when you try to write:
val b = computeB(a)
val a = 4

about comparator in kotlin

what's different between the two?
fun main(args: Array<String>) {
var a = printName("Jennie")
var b = printName("Jennie")
println(a == b) // compiler : false
var c = "Robert"
var d = "Robert"
println(c == d) // compiler : true
}
class printName(val name : String)
when I use the class, the result is false even if the String type is the same. but if I don't use class, then what happens is true.
If you want to use class, you must override equals and hashcode. But you can also use data class if you want to compare objects as equals and hashcode is already handled in data class.
In your case, c and d are references to the same String instance.  (The compiler sees that the two string literals are the same, and merges them.)  But even if they were different String instances, they'd still compare as equal.  That's because == calls the equals() method, and String overrides that to return true if the two strings have the same characters.
In your first case, a and b are references to different printName* instances.  (printName() is a call to its constructor, so each call returns a new instance.)  And your printName class does not override equals(), so it inherits the default implementation from its superclass (Any).  And that implementation always returns false for different instances, regardless of whether their contents are the same.
If you want different printName instances to compare as equal if they have the same contents, then you should override its equals() method.  You could do that manually, e.g.:
class PrintName(val name: String) {
override fun equals(other: Any?) = other is PrintName
&& name == other.name
}
Or you could make it a data class, which does that automatically.  (It also adds toString() and several other useful methods, but has some restrictions around constructors and inheritance.)
Another option might be to share or cache printNames instead of creating a new one each time.
(* By the way, it's conventional to use class names that start with a capital letter, so they stand out.)

Pass an Integer by Reference in Kotlin

I am trying to create a swap function which takes in two parameters as shown below:
fun swap(a :Int, b:Int) {
}
I call it like this:
var a = 10
var b = 5
swap(a,b)
// a should be 5
// b should be 10
The problem is that even if I swap the values inside the swap function it won't be reflected on the caller's side because it is passed as a copy and not as a reference.
Is there anyway to pass value types to swap function and allow the function the ability to change them.
There is absolutely no way to do it directly. Kotlin copies a value for scalar types (Double, Float, Boolean, Int, etc.). So any internal changes are lost.
For any other type, Kotlin copy a reference of parameter passed to the function. So any property/field alteration of parameter, also changes the caller parameter.
There is no way to change this behaviour.
After trying many ways to overcome the impossibility of passing scalar by reference, as happens in Kotlin, Java and some other languages; my current strategy is using for any scalar type a plain and generic wrap, as an above comment suggest.
Recently, I'm using this trick for everything, including inside a function that otherwise would demand that I return multiple values. The alternative is joining the returns in a artificial class or destructuring declarations: val (a, b, c) = function-call() syntax. However, I hate articial classes and destructuring declaration is for local variables only, and it's annoying when some needs visibility out of current block of commands.
My code is very simple:
data class p<T>( // It's a generic wrap class for scalar type T
var v:T
)
fun <T>swap(a:p<T>, b:p<T>){ // It's a generic swap for scalar types
var aux:p<T> = a.copy()
a.v = b.v
b.v =aux.v
}
fun main() {
var a:p<Int> = p<Int>(2) // 'a' is a kind of 'Int' variable
var b:p<Int> = p<Int>(3) // and so is 'b'
swap(a,b) // Exchange 'a' and 'b' values
println(a.v) // 3
println(b.v) // 2
}
The only drawback is not being able to use syntax sugar of a real scalar type.
I am forced to add .v on any use of a scalar variable.
I only uses that for variables that I need pass by reference in some function and it's not so common. I try, when possible, avoid collateral effects.
You can have a function that gets the references of variables
var x = 10
var y = 20
fun main() {
println("x=$x, y=$y") // x=10, y=20
swap(::x, ::y)
println("x=$x, y=$y") // x=20, y=10
}
fun <T> swap(firstRef: KMutableProperty0<T>, secRef: KMutableProperty0<T>) {
val temp = firstRef.get()
firstRef.set(secRef.get())
secRef.set(temp)
}
and you can pass the references of properties of some class like this swap(someClass::x, someClass::y)
the only limitation is that you can't pass references of local variables which is not the end of the world.
if you don't like the messy syntax you can always define a typealias and make it pretty:
typealias Ref<T> = KMutableProperty0<T>
fun <T> swap(firstRef: Ref<T>, secRef: Ref<T>) {
...
}
I know that OP didn´t ask for this, but idiomatic Kotlin would look like:
var a = 1
var b = 2
a = b.also { b = a }
Seems like Kotlin behaves pretty much like Java does:
Is Kotlin "pass-by-value" or "pass-by-reference"?
simple way to swap is make support class
private fun swap(pair: Pair) {
pair.a += pair.b
pair.b = pair.a - pair.b
pair.a = pair.a - pair.b
}
private data class Pair(var a: Int, var b: Int)
fun main() {
val pair = Pair(10, 5)
swap(pair)
println(pair)
}

Find all method calls with a specific parameter type with IntelliJ

I have this code base which is rather big ( +/- 500k lines). I'm looking in it to find all the method calls that use a single parameter and that parameter is a specific type.
This means, I want to be able to find method calls like the following:
public class Foo { }
public class Bar { }
public class Doer{
public void doSomethingFoo(Foo foo) { }
public void doSomethingObject(Object object) { }
}
public class Usage {
Doer doer = new Doer();
public doSomething() {
Foo anObject = new Foo();
Bar bar = new Bar();
doer.doSomethingFoo(anObject);
doer.doSomethingObject(anObject);
doer.doSomethingObject(bar);
}
}
Since both doer.doSomethingFoo(anObject) and doer.doSomethingObject(anObject) are called, both those statements should be returned by the search. Similarly, doer.doSomethingObject(bar) is not returned. Of course, I don't know that doer exists.
I'm trying to use the Structural Search of IntelliJ to do so. I've used the following template $Instance$.$Method$($Parameter$), with the following parameters:
$Instance$ -> Text/regexp = .*
$Method$ -> Text/regexp = .*
$Parameter$ -> Text/regexp = Foo
Minimum count = 1 // Minimum one Foo parameter
Maximum count = 1 // Maximum one Foo parameter
This returns everything that has a parameter named foo (case-insensitive, apparently). So I'm probably doing something wrong here. But what? How can I get all calls to any method where the only param is of type Foo?
You are almost there. All you need to do now is set the Expression type (regexp) of $Parameter$ to Foo and leave Text/regexp blank. Additionally you may want to enable the Apply constraint within type hierarchy checkbox, to find subclasses of Foo too.
Note that you can leave the Text/regexp of all variables blank. This is equivalent to .*.