angryziber / kotlin-puzzlers Goto Github PK
View Code? Open in Web Editor NEWA collection of Kotlin Puzzlers
A collection of Kotlin Puzzlers
Is project dead?
What will be:
println(17.0 / 5 / 2 / 2)
println(17 / 5.0 / 2 / 2)
println(17 / 5 / 2.0 / 2)
println(17 / 5 / 2 / 2.0)
private fun foo(one: (String) -> Unit = {}, two: (String) -> Unit = {}) {
one("one")
two("two")
}
fun main(args: Array) {
foo({ print(it)} )
foo { print(it)}
}
// What will it print?
// a). oneone
// b). twotwo
// c). onetwo
// d). Will not compile
suspend fun getAny(): Any = COROUTINE_SUSPENDED
suspend fun main() {
val result = withTimeoutOrNull(100) { getAny() == getAny() }
println(result)
}
a) true
b) false
c) null
d) None of the above
Correct answer: d (this code never finished). Returning COROUTINE_SUSPENDED (using only in library functions) implies coroutine suspension, even though you use withTimeout() coroutine launcher it will never finish
fun main() {
val write = { a: Byte -> print("$a ") }
val typeSafety =
if (write as? (Double) -> Unit == null) {
true
} else {
write(127)
write(128.9)
false
}
val nullSafety =
if (write as? (Any?) -> Unit == null) {
true
} else {
try {
write(null)
true
} catch (e: java.lang.NullPointerException) {
false
}
}
when {
typeSafety && nullSafety -> println("Kotlin is type safety and null safety language")
typeSafety -> println("Kotlin is type safety language")
nullSafety -> println("Kotlin is null safety language")
else -> println("Kotlin is a language")
}
}
If you use "as?" for checking lambdas, Kotlin will check only arity but not arguments types
@UseExperimental(ExperimentalContracts::class)
inline fun runLambda(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
}
fun getNothing(): Nothing {
runLambda { throw UnsupportedOperationException("Functions cant return Nothing!") }
}
fun main() {
val nothing: Nothing = getNothing()
print("Hello ")
print(nothing as String)
}
a) UnsupportedOperationException
b) NullPointerException
c) Hello TypeCastException
d) Hello NullPointerException
e) Will not compile
Correct answer is b, We trick the compiler using the AT_LEAST_ONCE contract (it means that lambda must be called at least once, but we don’t do this). Due to this getNothing() function returns null with no expection. Than compiler looks at the main function and thinks: "Hmm... getNothing() returns Nothing, but its impossible without throwing an exception. In this case I will remove all instructions after getNothing() invocation, because they are redundand, and write "throw null' instead of "return"
@UseExperimental(ExperimentalContracts::class)
inline fun runLambda(block: () -> Unit) {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
}
fun hello(): String {
var hello: String
runLambda { hello = "Hello " }
return hello
}
fun world(): String {
var world: String
runLambda { world = "world!" }
return world
}
fun main() {
val result = hello().plus(world())
println(result)
}
a) Hello world!
b) Will not compile
c) NullPointerException
d) nullnull
e) Not of the above
Correct answer is d. We trick compiler again, but now we used contracts to return uninitialized (null) String variable from NotNull function. But why we didnt get NullPointerException by invoking plus() function on null string? Because plus() compiles into StringBuilder like this:
StringBuilder builder = new StringBuilder();
builder.append(hello());
builder.append(world());
String result = builder.toString();
Thats why we got "nullnull"
This rationale contains these problems:
import import
);"""$dollarHome"""
looks to kotlinc
like an attempt to interpolate dollarHome
variable, which does not exist.Hello!
class Error(val code: Int) {
override fun toString(): String = "Error code is $code"
}
enum class Errors(code: Int, val error: Error = error(code)) {
ERROR_1(1),
ERROR_2(2),
ERROR_3(3);
fun error(code: Int) = Error(code)
}
fun main(args: Array<String>) {
Errors.values().forEach { println(it.error) }
}
This code throws ExceptionInInitializerError. I spent about 3 hours to find why. As it turned out there is Intelij Idea bug: if you ask Idea: "Where is error function declared", it will say: "In enum class Errors", but it's not true. It declared in kotlin standart lib.
public inline fun error(message: Any): Nothing = throw IllegalStateException(message.toString())
To fix this, you need to move error function out of enum
fun Any.toConsole(): Unit = print("$this ")
fun main() {
val list = listOf(1, 2, 3)
val array = IntArray(1)
{ 42 }.toConsole()
list.toConsole()
array.toConsole()
}
Correct answer: first. Because { 42 } its a second argument of IntArray constructor
I found a way to get instance of Nothing class and created some puzzlers with it
1) Returning null from NotNull function
fun main() {
println(thisFunctionNeverReturnsNull())
}
fun thisFunctionNeverReturnsNull(): String {
val unsafe =
Class.forName("sun.misc.Unsafe")
.declaredFields
.first { it.name == "theUnsafe" }
.apply { isAccessible = true }
.get(null)
as Unsafe
unsafe.allocateInstance(Nothing::class.java) as Nothing
}
2) Throwing java.lang.NPE in function (in this case "main") where nothing can thow NPE
fun main() {
getNothing()
}
fun getNothing(): Nothing {
val unsafe =
Class.forName("sun.misc.Unsafe")
.declaredFields
.first { it.name == "theUnsafe" }
.apply { isAccessible = true }
.get(null)
as Unsafe
return unsafe.allocateInstance(Nothing::class.java) as Nothing
}
3) Breaking compiler
fun main() {
val unsafe =
Class.forName("sun.misc.Unsafe")
.declaredFields
.first { it.name == "theUnsafe" }
.apply { isAccessible = true }
.get(null)
as Unsafe
val nothing = unsafe.allocateInstance(Nothing::class.java) as Nothing
println(if (nothing) {}.toString())
}
this code throws java.lang.VerifyError. It means that Kotlin compiled wrong bytecode. Let's look on the wrong bytecode line:
CHECKCAST java/lang/Void
ASTORE 1
ALOAD 1
INVOKEVIRTUAL kotlin/Unit.toString ()Ljava/lang/String;
As we can see, we try to invoke kotlin.Unit.toString() on java.lang.Void instance
fun <T> weirdPrint(a: ArrayList<in T>) =
try {
print(a) as T
} catch (e: Throwable) {
throw UnsupportedOperationException()
}
weirdPrint(if (false) arrayListOf(42) else arrayListOf("Hello"))
// a) [Hello]
// b) [Hello] NullPointerException
// c) [Hello] UnsupportedOperationException
// d) Will not compile
Correct answer is b. T implicitly infers to Nothing and if function returns Nothing, compiler inserts "throw null" after invocation. Why "throw null"? Because its shortest way to throw any exception
The feature is initially designed in ambiguous way.
Companions are for illustration because identifier is a type and value at the same time.
object Wtf
fun context(i: Wtf) {
Throwable().printStackTrace()
}
context(Wtf)
fun foo() {
context(Wtf)
fun bar() {
}
}
fun main() {
Wtf.run { foo() }
}
Answer:
context()
on a top-level fun is a context accepting a type. context()
above a local function is just an invocation accepting a value. The only stack trace will be printed, with foo() on top of stack.
Hi! Don't know English very well so create an issue instead of a PR. Hope you will adopt this description.
Puzzler idea:
for (i in 1..10 step 2 step 3) {
println(i)
}
What will happen?
Correct answer:
Why?
Because (1) step
overwrites the previous step and constructs a new object (Kotlin sources):
public infix fun IntProgression.step(step: Int): IntProgression {
checkStepIsPositive(step > 0, step)
return IntProgression.fromClosedRange(first, last, if (this.step > 0) step else -step)
}
And (2) in the new object the last element is recalculated (Kotlin sources):
internal fun getProgressionLastElement(start: Int, end: Int, step: Int): Int = when {
step > 0 -> if (start >= end) end else end - differenceModulo(end, start, step)
step < 0 -> if (start <= end) end else end + differenceModulo(start, end, -step)
else -> throw kotlin.IllegalArgumentException("Step is zero.")
}
So 1..10 step 2
becomes 1..9 step 2
because of (2).
Then 1..9 step 2 step 3
becomes 1..9 step 3
because of (1)
and finally becomes 1..7 step 3
because of (2) again.
fun printAndReturn(string: String): Int {
print(string)
return 43
}
suspend fun suspendFunction(): String =
suspendCoroutineUninterceptedOrReturn {
printAndReturn("42 ")
}
suspend fun main() {
print(suspendFunction())
}
Correct answer: 1. As far as i understand all suspend functions have an Object as return type (thats why there is no ClassCastException) and suspendCoroutineUninterceptedOrReturn allows you to return anything regardless return type (its needed for some library functions)
Your jpoint 2017 performance was more like introduction to kotlin and not puzzlers :)
Here is a couple of puzzlers for people who uses kotlin already:
operator fun Nothing?.not() = Unit
operator fun Unit.not() = null
var aaaa = null
fun main(args: Array<String>) {
!!!!aaaa!!!! // will it work?
(!!!!aaaa)!!!! // how about it?
!!!!(aaaa!!!!) // or it?
}
operator fun Nothing?.not() = null
var aaaa = null
fun main(args: Array<String>) {
!!!!aaaa!!!! // will it work?
(!!!!aaaa)!!!! // how about it?
!!!!(aaaa!!!!) // or it?
}
Late night brain-fart, could be fun.
Inspiration: https://youtu.be/MYQWtNG2so8?t=1101 (took the section heading too literally)
package by
object by {
val by: by by by
}
operator fun `by`.getValue(by: by, prop: Any): by =
TODO("by by by")
fun main() {
println(by.by.by)
}
Not sure what the question would be, I guess "What happens when you try to compile & run this?"
/**
Exception in thread "main" java.lang.ExceptionInInitializerError
at b.y.ByKt.main(by.kt:11)
at b.y.ByKt.main(by.kt)
Caused by: java.lang.IllegalArgumentException:
Parameter specified as non-null is null: method b.y.ByKt.getValue, parameter $this$getValue
at b.y.ByKt.getValue(by.kt)
at b.y.by.getBy(by.kt)
at b.y.by.<clinit>(by.kt:4)
... 2 more
*/
Explanation: the last by
in val by: by by by
refers to the same property it's trying to initialize.
(Suprising: the backticks are required to compile, not sure yet why.)
package b.y
open class by<by : b.y.by<by>> {
val by: by by by
}
operator fun `by`<*>.getValue(by: by<*>, prop: Any): Nothing =
TODO("by by by")
fun main() {
class by : b.y.by<by>()
println(b.y.by().by)
}
fun main() {
println((2.0..3.0).lessThanOrEquals(0.0, 1.0))
}
true
, false
, or compilation error?
After (or before) this puzzler the next puzzler may be shown:
fun main() {
println((2..3).lessThanOrEquals(0, 1))
}
true
, false
, or compilation error?
Those two have different answers. The first one has the answer true
because what lessThanOrEquals
does is that it compares two arguments, not the ranges themselves. And the second puzzler is a compilation error.
lessThanOrEquals
is only needed for floating point numbers to make it possible to implement coerceIn
(1.0.coerceIn(1.0..2.0)
) for floating point numbers. Inside coerceIn
function we use lessThanOrEquals
not compareTo
because compareTo
compares by total order but lessThanOrEquals
compares according to IEEE.
You may observe total order vs IEEE comparison difference in this example:
fun main() {
println(-0.0 == 0.0) // true. IEEE
println(0.0.compareTo(-0.0) == 0) // false. Total Order
// or try NaN :)
}
The credit also goes to https://github.com/ilya-g
Ideasource:
class SomethingᐸTᐳ
fun main() {
SomethingᐸTᐳ()
}
may need to add more red herrings, but this is already interesting: it compiles and executes! but what is T?
Missing answers for:
fun main() {
recursive()
}
tailrec fun recursive() {
::recursive()
}
Correct answer: 3. Because foo::baz(args) syntax is reserved for future use
What will this print?
fun main() {
Fun().things()
}
data class Stuff(
val s: String
)
class Fun {
private val stuff: Stuff = createStuff()
private val x: String = "x"
fun things() {
println(stuff.s)
}
private fun createStuff(): Stuff {
return Stuff(x)
}
}
KotlinNullPointerException
: null
is passed to non-null parameter s
in Stuff.constructor
The value of x
is null at the point of Stuff constructor call, because the Fun
val
s are initialized in order.
Because it's in a function, Kotlin thinks it's safe, when inlined the problem becomes obvious.
Is there anything similar already?
FYI I created this repo https://github.com/dkandalov/kotlin-puzzlers which includes some of the puzzlers from this repo and some new puzzlers. In particular these two might be interesting:
when
needs to be an expression in order to be exhaustive, e.g.: fun printClassOf(x: X) = when (x) {
is X.A -> println("is A")
is X.B -> println("is B")
}.exhaustive
val Unit.exhaustive get() = this
Color.from
is extension method on instances of enum, not on the enum class. For this to work enum needs companion object and semicolon: enum class Color {
Red, Green, Blue;
companion object
}
fun Color.Companion.from(s: String) = when (s) {
"#FF0000" -> Red
"#00FF00" -> Green
else -> null
}
It should probably be "execute" instead of "ececute".
Double import in rationale.md import import kotlin.text.Typography.dollar
val number: Number = 0.0 / 0.0
println(if (number is Double) number == number else "number !is Double")
a) true
b) false
c) number !is Double
d) None of the above
Correct answer: a. Compiler ignores smart cast to Double and compares numbers like Objects, i.e. using equals() method. And equals() method returns true if it compares two NaNs.
enum class E { e }
val e = E.e
val a = when (E.e) {
e -> "1"
}
fun main(args: Array) {
print(a)
}
// What will it print?
// a) 1
// b) Will not compile
// c) null
// d) NullPointerException
fun main() {
doSomething()
doSomeThing()
}
fun f(block: () -> Unit) {
block()
}
fun doSomething() {
f { println("doSomething") }
}
fun doSomeThing() {
f { println("doSomeThing") }
}
What's the output on Windows?
doSomething
doSomeThing
doSomething
doSomething
doSomeThing
doSomething
doSomeThing
doSomeThing
java.lang.NoClassDefFoundError
java.lang.NoClassDefFoundError: MainKt$doSomething$1 (wrong name: MainKt$doSomeThing$1)
at Main.doSomething(Main.kt:11)
Encountered in Kotlin 1.4.32, verified fixed in 1.6.0 (not sure about 1.5.x)
On 1.6.0 two class files are generated: MainKt$doSomething$1
and MainKt$doSomeThing$2
On Unix this is not an issue because most file systems are case sensitive.
What will this print in Kotlin 1.3.X and then in Kotlin 1.4.X ?
enum class EnumWithConst(val theValue: Int) {
One(0),
Two(EnumWithConst.constValue),
Three(2 * EnumWithConst.constValue);
companion object {
const val constValue: Int = 100
}
}
enum class EnumWithoutConst(val theValue: Int) {
One(0),
Two(EnumWithoutConst.simpleValue),
Three(2 * EnumWithoutConst.simpleValue);
companion object {
val simpleValue: Int = 100
}
}
fun main() {
println(EnumWithConst.values().joinToString { "$it => ${it.theValue}" })
println("##############################")
println(EnumWithoutConst.values().joinToString { "$it => ${it.theValue}" })
}
The related playground : https://pl.kotl.in/NjuR92qlu
This code makes the compiler crash.
The bug is know and referenced here: https://youtrack.jetbrains.com/issue/KT-31135
class foo(var bar : String)
fun main() {
var baz : foo? = foo("test")
baz?.bar += "test"
}
It seems to be relate to the fact that
+=
is operated on an immutable class (String
) and the statement is re-written as baz?.bar = baz?.bar + "test"
andplus
extension function on a String
takes a nullable receiver: operator fun String?.plus(other: Any?): String
Rewriting it by hand, this bug goes away. It looks like the compiler messes up the re-write.
If the plus
's receiver were non-nullable, a compiler error would have been generated instead of it crashing.
I haven't seen your presentation but thanks a lot for these great puzzlers!
The puzzlers not detected by IDE static analysis are the best :)
In case you're interested, here are some puzzlers I came across:
val whatAmI = {}()
println(whatAmI)
throw throw throw Exception()
return return 123
val map = mapOf<Any, Any>().withDefault{ "default" }
println(map["1"])
will it compile and write my name?
class Being<T>(val name: T? = null) {
fun greet(being: Matter) {
(being as this.Human).sayHello(name)
}
inner class Human: Matter() {
fun sayHello(name: T?) {
print("hello $name")
}
}
open class Matter
}
fun main() {
val human = Being("shalva97")
human.greet(Being.Matter())
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.