Why Kotlin function with default parameters creates a method with unused parameter - kotlin

See this example code in Kotlin:
fun foo(bar: Int = 0, baz: Int) {
/* ... */
}
After decompiling it to Java code (Tools -> Kotlin -> Show Kotlin Bytecode -> Decompile) I got the following code
public static final void foo(int bar, int baz) {
}
// $FF: synthetic method
// $FF: bridge method
public static void foo$default(int var0, int var1, int var2, Object var3) {
if ((var2 & 1) != 0) {
var0 = 0;
}
foo(var0, var1);
}
I noticed that the resulting Java method has an unused Object var3 parameter.
I kind of thought that it may be related to functions in a class but when decompiling this code
class Foo {
fun foo(bar: Int = 0, baz: Int) {
/* ... */
}
}
I got this code
public final class Foo {
public final void foo(int bar, int baz) {
}
// $FF: synthetic method
// $FF: bridge method
public static void foo$default(Foo var0, int var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = 0;
}
var0.foo(var1, var2);
}
}
As you can see the Object parameter is still unused and just sits there.
Upon additional tests I noticed the same behavior for extension methods. The same goes when the default parameter is last (i.e. fun foo(bar: Int, baz: Int = 0) {})
I've also done a basic test to check what is that value set to when calling that function using the code below
fun main(args: Array<String>) {
foo(baz = 2)
}
And
class Something {
init {
foo(baz = 2)
}
}
After decompiling it I got the following code
public static final void main(#NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
foo$default(0, 2, 1, (Object)null);
}
And
public final class Something {
public Something() {
FooKt.foo$default(0, 2, 1, (Object)null);
}
}
Which makes even less sense whatsoever.
My question is: Why does Kotlin generate an unused parameter for functions with default parameters? Is it a bug?

According to this, currently it's unused, but is reserved for adding super calls with defaults later.
You can see it in action here:
open class Foo {
open fun foo(bar: Int = 0, baz: Int) {
/* ... */
}
}
class Blah: Foo() {
override fun foo(bar: Int, baz: Int) {
}
}
which will generate a bytecode-to-Java Foo of:
public class Foo {
public void foo(int bar, int baz) {
}
// $FF: synthetic method
// $FF: bridge method
public static void foo$default(Foo var0, int var1, int var2, int var3, Object var4) {
if(var4 != null) {
throw new UnsupportedOperationException("Super calls with default arguments not supported in this target, function: foo");
} else {
if((var3 & 1) != 0) {
var1 = 0;
}
var0.foo(var1, var2);
}
}
}

Related

Syntax of secondary constructors in Kotlin

I've got this code-snippet. It shall demonstrate the order, in which constructors are executed:
fun main(args: Array<String>) {
Sample("T","U")
}
class Sample(private var s : String) {
constructor(t: String, u: String) : this(t) { // I don't get what "this(t)" is!
this.s += u
}
init {
s += "B"
}
}
What's the ": this(t)" in the declaration of the secondary constructor?
That isn't the return-type? Isn't it?
In this particular case this is a keyword that delegates to the primary constructor. It is mandatory in Kotlin when your class has several ones.
The Java equivalent would be:
class Simple {
private String s;
public Simple(String s) { // Here is your primary constructor
this.s = s;
}
public Simple(String t, String u) { // Here is your secondary constructor
this(t);
this.s += u;
}
{
s += "B"; // Here is the init block
}
}
With
this(t)
you call the primary constructor and passes t as an argument for s.
Instead you could even write something like this:
this(s = "a")
Then you set s to "a".
So the order is: Primary constructor, init, secondary constructor. For more detail: https://kotlinlang.org/docs/reference/classes.html
In addition to the answers. This is a required invocation to the default primary constructor:
class Sample(private var s: String) { }
Like in Java:
public Sample(String s) {
}
public Sample(String t, String u) {
this(t); // invoke constructor Sample(String s)
}
To avoid this invocation, you can write like this:
class Sample {
private var s = ""
constructor(t: String) {
s = ...
}
constructor(t: String, u: String) {
s = ...
}
}

Kotlin: IllegalAccessException: Class BlockJUnit4ClassRunner can not access a member of class Foo with modifiers “private”

Using Kotlin with Junit 4 I get the following exception for Parameter field injection:
java.lang.IllegalAccessException: Class org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters can not access a member of class MyTestClass with modifiers "private"
Here's the code:
#RunWith(Parameterized::class)
class MyTestClass {
#Rule
#JvmField
val mockitoRule: MockitoRule = MockitoJUnit.rule()
companion object {
#Parameters(name = "{0}")
#JvmStatic
fun testData() = listOf(
arrayOf(1, 1),
arrayOf(2, 2),
arrayOf(3, 3)
)
}
#Parameter
var input: Int = 0 // Public
#Parameter(1)
var expected: Int = 0 // Public
#Test
fun foo() {
assertEquals(expected, input)
}
}
Any ideas?
Tl;dr: Adding #JvmField to both fields solved the problem.
Like so:
#JvmField
#Parameter
var input: Int = 0
#JvmField
#Parameter(1)
var expected: Int = 0
Explanation: By default, Kotlin will make the fields private and generate getters/setters as can be seen from the decompiled java code below, as a result JUnit won't be able to read the private fields hence the message: can not access a member of class MyTestClass with modifiers "private"
#Parameter
private int input;
#Parameter(1)
private int expected;
public final int getInput() {
return this.input;
}
public final void setInput(int var1) {
this.input = var1;
}
public final int getExpected() {
return this.expected;
}
public final void setExpected(int var1) {
this.expected = var1;
}

How to mock a top-level-function in kotlin with jmockit

Assuming the I have a function to be test below, declare at the file named "Utils.kt"
//Utils.kt
fun doSomething() = 1
Then we create a test class to test it
//UtilsTest.kt
#RunWith(JMockit::class)
class UtilsTest {
#Test
fun testDoSomething() {
object : Expectation() {
init {
doSomething()
result = 2
}
}
assertEquals(2, doSomething())
}
}
I want to mock doSomething, make it return 2, but it won't work, actual result is 1
Is there any workaround for this purpose?
A workaround mock it in Java side as you cannot reference the UtilsKt class from Kotlin files.
#RunWith(JMockit.class)
public final class UtilsFromJavaTest {
#Test
public final void testDoSomething(#Mocked #NotNull final UtilsKt mock) {
new Expectations() {
{
UtilsKt.doSomething();
this.result = 2;
}
};
Assert.assertEquals(2, UtilsKt.doSomething());
}
}
Thanks to #aristotll, we can simply extends the workaround to make it more easier to use.
first, declare a java class that return the UtilsKt class
//TopLevelFunctionClass.java
public class TopLevelFunctionClass {
public static Class<UtilsKt> getUtilsClass() {
return UtilsKt.class
}
}
then, mock this class in expectation using partial mock
//UtilsTest.kt
#RunWith(JMockit::class)
class UtilsTest {
#Test
fun testDoSomething() {
object : Expectation(TopLevelFunctionClass.getUtilsClass()) {
init {
doSomething()
result = 2
}
}
assertEquals(2, doSomething())
}
}

Kotlin type inference failed

Let's say we have a 3rd-party Java library with such class:
//----------------------------------------------------------------------------------------
package foo;
public final class Functions {
public interface VoidFunc0 {
void call();
}
public interface VoidFunc1<T> {
void call(T t);
}
#SuppressWarnings("unchecked")
public static <T> NoOpFunc<T> noOp() {
return new NoOpFunc();
}
/*public*/ static final class NoOpFunc<T> implements VoidFunc0, VoidFunc1<T> {
#Override public void call() { /* deliberately no op */}
#Override public void call(T t) { /* deliberately no op */ }
}
}
//----------------------------------------------------------------------------------------
We successfully used its Functions.noOp() method in our Java application, but when we began to rewrite it in Kotlin, we faced the issue that the code below doesn't compile and gives us two errors:
//----------------------------------------------------------------------------------------
package bar
import foo.Functions
object KotlinApp {
#JvmStatic
fun main(args: Array<String>) {
/*
* Error:(XX, XX) Kotlin: Type inference failed: Not enough information
* to infer parameter T in fun <T : Any!> noOp(): Functions.NoOpFunc<T!>!
* Please specify it explicitly.
*/
callVoidFunc0(Functions.noOp()) // ERROR 1
/*
* Error:(XX, XX) Kotlin: Type Functions.NoOpFunc<Any!>! is inaccessible
* in this context due to: Functions.NoOpFunc<Any!>!
*/
callVoidFunc1(Functions.noOp()) // ERROR 2
}
fun callVoidFunc0(func0: Functions.VoidFunc0) {
func0.call()
}
fun callVoidFunc1(func1: Functions.VoidFunc1<Any>) {
func1.call("A")
}
}
//----------------------------------------------------------------------------------------
but the same code previously written in Java compiles and works well:
//----------------------------------------------------------------------------------------
package bar;
import foo.Functions;
public class JavaApp {
public static void main(String[] args) {
callVoidFunc0(Functions.noOp()); // OK
callVoidFunc1(Functions.noOp()); // OK
}
public static void callVoidFunc0(Functions.VoidFunc0 func0) {
func0.call();
}
public static void callVoidFunc1(Functions.VoidFunc1<Object> func1) {
func1.call("A");
}
}
//----------------------------------------------------------------------------------------
Type inference fails even if we specify T explicitly. Error 2 goes away when NoOpFunc declared as public, but Error 1 still remains.
The problem is a bug in Kotlin.
Here's the link to the issue: https://youtrack.jetbrains.com/issue/KT-14499. Please vote.
UPD
To fix the issue there's a workaround:
#JvmStatic
fun main(args: Array<String>) {
#Suppress("INACCESSIBLE_TYPE")
callVoidFunc0(Functions.noOp()) // (1)
#Suppress("INACCESSIBLE_TYPE")
callVoidFunc1(Functions.noOp<Any>()) // (2)
}
To fix (1) one must suppress the compilation warning, to fix (2) - additionally specify the type explicitly.

Method and mock with same class

I have class with 2 methods
class A
{
void Fun()
{
if(FunRet()>0){///} else {///}
}
int FunRet()
{ return 4;}
};
I want to test Fun() method depend on what FunRet returns. So i want to mock FunRet.
I rather don't want make FunRet as virtual. How I can do that?
You can inject intra-class dependencies. In this case, make Fun accept a value instead of computing it:
class A
{
void Fun(int x)
{
if(x>0){///} else {///}
}
int FunRet()
{ return 4;}
};
Then your tests can pass arbitrary values into Fun(). If you need to enforce correct use, write a public version to expose in your API and a private version for testing:
class A {
public:
void Fun() { return Fun(FunRet()); }
private:
void Fun(int x); // for testing.
};
You could extract the Fun method into a calculator class that implements an interface. You should pass an instance of that interface to class A at constructor.
In testing you could have other classes implementing that interface, that return other values.
This method also have the big advantage, that you seperate the concerns of calculating a value and using the calculated value.
class A {
public:
A (IFunCalc calc) { m_calc = calc; }
void Fun { if calc.FunRet() > 4 ... }
private:
IFunCalc m_calc;
}
class FunCalc : IFunCulc {
public:
int FunRet { return 4; }
}
class FunCalc4Test : IFunCalc {
public:
int FunRet { return 27; }
}
I think you're missing the this pointer.
... if ( this->FunRet() > 0 ) { ...
If you use dependency injection and template your object under test, you can use mock objects without having to use virtual functions.
class AParameters
{
public:
int FunRet()
{ return 4;}
};
class MockAParameters
{
public:
MOCK_METHOD0(FunRet, int());
};
template<class Parameters>
class AImpl
{
public:
AImpl(Parameters& parameters):parameters(parameters){}
void Fun()
{
if(parameters.FunRet()>0){///} else {///}
}
private:
Parameters& parameters;
};
typedef AImpl<AParameters> A;
typedef AImpl<MockAParameters> ATestObject;
void Test::funUsesFunRet()
{
MockAParameters params;
EXPECT_CALL(params, FunRet());
ATestObject object(params);
object.Fun();
}
I believe FunRet is an internal implementation detail of Fun. As a result, Fun does not need to be tested in isolation from FunRet. Just test Fun and don't worry about the fact it calls FunRet.