Is it possible to write a "double" extension method? - kotlin

In Kotlin, it is possible to write
class A {
fun B.foo()
}
and then e.g. write with (myA) { myB.foo() }.
Is it possible to write this as an extension method on A, instead? My use case is writing
with (java.math.RoundingMode.CEILING) { 1 / 2 }
which I would want to return 1, the point being that I want to add operator fun Int.div(Int) to RoundingMode.

No it's not possible. operator div is required to have Int as a receiver.
You can't add also RoundingMode as receiver, since there can only be single function receiver.
What you can do, though, is use Pair<RoundingMode, Int> as a receiver:
operator fun Pair<RoundingMode, Int>.div(i: Int): BigDecimal =
BigDecimal.valueOf(second.toLong()).divide(BigDecimal.valueOf(i.toLong()), first)
with(RoundingMode.CEILING) {
println((this to 1) / 2) // => 1
}

That's not possible, Int already has a div function, thus, if you decide to write an extension function div, you won't be able to apply it, because member functions win over extension functions.
You can write this though:
fun RoundingMode.div(x: Int, y: Int): Int {
return if (this == RoundingMode.CEILING) {
Math.ceil(x.toDouble() / y.toDouble()).toInt()
} else {
Math.floor(x.toDouble() / y.toDouble()).toInt()
}
}
fun main(args: Array<String>) {
with(java.math.RoundingMode.CEILING) {
println(div(1,2))
}
}

It's not possible for a couple of reasons:
There's no "double extension functions" concept in Kotlin
You can't override a method with extension functions, and operator div is already defined in Int
However you can workaround these issues with
A context class and an extension lambda (e.g. block: ContextClass.() -> Unit)
Infix functions (e.g. use 15 div 4 instead of 15 / 4)
See the example below:
class RoundingContext(private val roundingMode: RoundingMode) {
infix fun Int.div(b: Int): Int {
val x = this.toBigDecimal()
val y = b.toBigDecimal()
val res = x.divide(y, roundingMode)
return res.toInt()
}
}
fun <T> using(roundingMode: RoundingMode, block: RoundingContext.() -> T): T {
return with(RoundingContext(roundingMode)) {
block()
}
}
// Test
fun main(args: Array<String>) {
using(RoundingMode.FLOOR) {
println(5 div 2) // 2
}
val x = using(RoundingMode.CEILING) {
10 div 3
}
println(x) // 4
}
Hope it helps!

Related

Kotlin functions inside a const

I am learning kotlin, and want to know how to add functions to a const,
here the JS example...
function suma (a, b){
return a + b
}
console.log("sua suma::", suma(2,3))
function multiplica (a, b){
return a * b
}
console.log("sua multiplik::", multiplica(2,3))
const operations = {
suma,
multiplica
}
console.log ("sum of first class::", operations.suma(2,3))
console.log ("mult of first class::", operations.multiplica(2,3))
so how do I achieve the same on Kotlin?
Here what I have tried:
fun suma(a: Int, b: Int): Int{
return a + b
}
fun multiplica (a: Int, b: Int): Int{
return a * b
}
const operations = {
suma(),
multiplica()
}
fun main() {
println("sua suma:: ${suma(2, 3)}")
println("sua multiplica:: ${multiplica(2, 3)}")
println("sua multiplica:: ${operations.multiplica(2,3)}")
}
It can be done using object keyword, like following:
fun suma(a: Int, b: Int): Int {
return a + b
}
fun multiplica(a: Int, b: Int): Int {
return a * b
}
fun main() {
val operations = object {
val _suma = ::suma
val _multiplica = ::multiplica
}
println("sua suma:: ${operations._suma(2, 3)}")
println("sua multiplica:: ${operations._multiplica(2, 3)}")
}
The only disadvantage is that you have to choose a name for operations.XXXXX that is different from the name of referenced function: note var _suma vs fun suma. Otherwise the compiler will consider it recursive problem
"Only Primitives and String are allowed" for const
The operator you're looking for is :: (Double colon)
An enum example of this is
enum class Operations(function: KFunction<Int>) {
Suma(function = ::suma),
Multiplica(function = ::multiplica)
}
The main issues here are that Kotlin is a statically typed language, and doesn't have the same idea of Objects that can contain arbitrary attributes, like Javascript does.
I'm kinda new to Kotlin, so there may be a better way to do this, but what I'd do is define a Map to do the same sort of thing:
fun suma(a: Int, b: Int): Int{
return a + b
}
fun multiplica (a: Int, b: Int): Int{
return a * b
}
val operations: Map<String, (a: Int, b:Int) -> Int> = hashMapOf(
"suma" to ::suma,
"multiplica" to ::multiplica)
fun main() {
println("sua suma:: " + operations.get("suma")?.invoke(2, 3))
println("sua multiplica:: " + operations.get("multiplica")?.invoke(2, 3))
}
Result:
sua suma:: 5
sua multiplica:: 6
Note that operations is an immutable Map ('const' kinda) in that its contents can't be changed once it's defined.
The access and having to use invoke seems kinda messy. This seems to be due to the fact that a Map can only contain nullable types. That's the main reason I think there's probably a better way to do this.

How to combine variable argument definitions and function with receiver in Kotlin

In Kotlin I am able to define a function that accepts a variable number of arguments (see: testVariableArguments below) and I can define a function with a specified receiver (see: testFunctionWithReceiver below). I am wondering if there is a way to combine both of these concepts?
fun main(args: Array<String>) {
testVariableArguments { a: Int -> println(a) }
testVariableArguments { a: Int, b: Int -> println("$a, $b") }
testVariableArguments { a: Int, b: Int, c: Int -> println("$a, $b, $c") }
testVariableArguments { a: Int, b: Int, c: Int, d: Int -> println("$a, $b, $c, $d") }
testFunctionWithReceiver {
doSomething()
doAnotherThing()
}
}
fun <R, T : Function<R>> testVariableArguments(function: T) {
val method = function::class
.java
.declaredMethods
// May need to do something else here to get the
// correct method in case the return type is
// expected to be Object, but for my case it
// would never be Object
.first { m -> m.name == "invoke" && m.returnType != Object::class.java }
val args = method
.parameterTypes
// Mapping to Int here for demonstration, in real
// situations would use the parameter types to
// create the correct value
.withIndex()
.map { i -> i.index }
// Not really needed, but would be if I were
// using multiple types and not just Int
.map { i -> i as Any }
.toTypedArray()
method.invoke(function, *args)
}
fun <R> testFunctionWithReceiver(function: MyInterface.() -> R) {
val myObject = object : MyInterface {
override fun doSomething() {
println("doing something")
}
override fun doAnotherThing() {
println("doing another thing")
}
}
function(myObject)
}
interface MyInterface {
fun doSomething()
fun doAnotherThing()
}
EDIT:
I have found a way to combine these two features, but it is a bit messy at the call site, so if there is a better approach I would be interested.
What I did was add the following operator function to MyInterface
operator fun <R, T : Function<R>> T.unaryPlus() {
testVariableArgumentDefinition(this)
}
Then when I call testFunctionWithReceiver I do the following:
testFunctionWithReceiver {
+{ a: Int, b: Int ->
println("$a, $b")
doSomething()
doAnotherThing()
}
}
You can add parameter requirements to the closure called with receiver by adding:
MyInterface.(P) -> R
Replacing your creation of test parameters with a fixed one, this is what it might look like:
fun <R, P> testVariableArgumentsWithReceiver(param: P, function: MyInterface.(P) -> R) {
function.invoke(myObject, param)
}
fun main(args: Array<String>) {
testVariableArgumentsWithReceiver(17) { a: Int ->
println("$a")
doSomething()
doAnotherThing()
}
}
Of course, you're not as flexible here as you need to pass a single value of type P (which could be an array). You can extend it to MyInterface.(P,Q) but not arbitrary signatures per se.
What you truly want is a signature like this:
fun <R, T: Function<R>> someName(function: MyInterface.T)
or
fun <R, T: FunctionWithReceiver<MyInterface, R>> someName(function: T)
To my knowledge, neither can currently be expressed:
Only function-type literals seem to be allowed as part of extension types; MyInterface.T is not valid code.
There doesn't seem to be a first-class type for functions with receiver; we can't declare FunctionWithReceiver.
This may be worthwhile to bring up on discuss.kotlinlang.org

how to implement an applyif for Kotlin?

I'd like to have an applyif to work like:
builder.applyif(<condition expression>) {
builder.set...
}
to be equal with:
builder.apply {
if (<condition expression>) {
builder.set...
}
}
Is that possible?
Yes, of course. You can nearly program anything, but don't reinvent the wheel. Look at the bottom of the answer to see a standard Kotlin approach without own extension function(s) which may already suffice your needs (not exactly applyIf though).
Now, however, lets see how an applyIf might be implemented:
inline fun <T> T.applyIf(predicate: T.() -> Boolean, block: T.() -> Unit): T = apply {
if (predicate(this))
block(this)
}
Don't forget the inline if you are implementing extension functions with lambdas.
Here is an example usage of the above.
// sample class
class ADemo {
fun isTrue() = true
}
// sample usage using method references
ADemo().applyIf(ADemo::isTrue, ::println)
// or if you prefer or require it, here without
ADemo().applyIf( { isTrue() } ) {
println(this)
}
If you just want to supply a boolean instead, you can use the following extension function:
inline fun <T> T.applyIf(condition : Boolean, block : T.() -> Unit) : T = apply {
if(condition) block(this)
}
and call it with:
val someCondition = true
ADemo().applyIf(someCondition) {
println(this)
}
And now a possible Kotlin standard way with which more people could be familiar:
ADemo().takeIf(ADemo::isTrue)
?.apply(::println)
// or
ADemo().takeIf { it.isTrue() }
?.apply { println(this) }
If they do remember (I actually didn't until I saw Marko Topolniks comment) they should immediately know what's going on.
However, if you require the given value (i.e. ADemo()) after calling takeIf this approach might not work for you as the following will set the variable to null then:
val x = ADemo().takeIf { false }
?.apply { println(this) /* never called */ }
// now x = null
whereas the following will rather set the variable to the ADemo-instance:
val x = ADemo().applyIf(false) { println(this) /* also not called */ }
// now x contains the ADemo()-instance
Chaining the builder calls might not be so nice then. Still you can also accomplish this via standard Kotlin functions by combining the takeIf with apply or also (or with, let, run, depending on whether you want to return something or not or you prefer working with it or this):
val x = builder.apply {
takeIf { false }
?.apply(::println) // not called
takeIf { true }
?.apply(::println) // called
}
// x contains the builder
But then again we are nearly there where you were already in your question. The same definitely looks better with applyIf-usage:
val x = builder.applyIf(false, ::println) // not called
.applyIf(true) {
println(this) // called
}
// x contains the builder
Sure you can, you just need an extension function so you can call it on the builder, and you need it to take a Boolean parameter and the lambda to execute.
If you look at the source of the apply function itself, it will help with most of the implementation:
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
Based on this, applyIf can be as simple as:
inline fun <T> T.applyIf(condition: Boolean, block: T.() -> Unit): T {
return if (condition) this.apply(block) else this
}
Usage looks like this:
builder.applyIf(x > 200) {
setSomething()
}
fun <T> T.applyIf(condition: Boolean, block: T.() -> T) = if (condition) block() else this
fun main() {
println("a".applyIf(true) { uppercase() }) // A
println("a".applyIf(false) { uppercase() }) // a
}

What is Kotlin's way to have similar effect as flags enum variable in C#

In C#, I can do this.
[Flags]
enum BeerProperty
{
Bold = 1,
Refreshing = 2
}
static void Taste(BeerProperty beer)
{
if (beer == (BeerProperty.Bold | BeerProperty.Refreshing))
{
Debug.WriteLine("I can't qutie put my finger on...");
}
}
static void Main(string[] args)
{
var tickBeer = BeerProperty.Bold | BeerProperty.Refreshing;
Taste(tickBeer);
}
In Kotlin, it seems that I cannot "OR" two flags. What is the Kotlin's way to do this? Using a list of enum variables?
enum class BeerProperty(value:Int)
{
Bold(1),
Refreshing(2)
}
fun taste(beer:BeerProperty)
{
if(beer == (BeerProperty.Bold | BeerProperty.Refreshing))
{
print("I can't qutie put my finger on...");
}
}
fun main(args: Array<String>)
{
val tickBeer = BeerProperty.Bold | BeerProperty.Refreshing;
taste(tickBeer);
}
Added: Thank you for the answer (which I cannot mark as answer yet, due to time limitation). I modified the code like below and achieved what I wanted.
fun taste(beer: EnumSet<BeerProperty>)
{
if(beer.contains(BeerProperty.Bold) && beer.contains(BeerProperty.Refreshing))
{
print("I can't qutie put my finger on...");
}
}
fun main(args: Array<String>)
{
val tickBeer = EnumSet.of(BeerProperty.Bold, BeerProperty.Refreshing);
taste(tickBeer);
}
Using extension functions
import java.util.*
enum class BeerProperty
{
BOLD,
REFRESHING,
STRONG;
infix fun and(other: BeerProperty) = BeerProperties.of(this, other)
}
typealias BeerProperties = EnumSet<BeerProperty>
infix fun BeerProperties.allOf(other: BeerProperties) = this.containsAll(other)
infix fun BeerProperties.and(other: BeerProperty) = BeerProperties.of(other, *this.toTypedArray())
fun taste(beer: BeerProperties) {
if(beer allOf (BeerProperty.BOLD and BeerProperty.REFRESHING and BeerProperty.STRONG)) {
print("I can't qutie put my finger on...")
}
}
fun main(args: Array<String>) {
val tickBeer = BeerProperty.BOLD and BeerProperty.REFRESHING and BeerProperty.STRONG
taste(tickBeer)
}
I use extension functions to allow properties to be added with and, and allof to check all flags are set.
Indeed, in Kotlin every enum constant is an instance of the class corresponding to the enum, and you can't use 'OR' to combine multiple class instances. If you need to track multiple enum values, the most efficient way to do that is to use the EnumSet class.
You can achieve the same result of c# enum flags in this way
enum class TestType(val value: Int)
{
x(1),
y(2),
z(4)
}
fun Int.hasFlag(flag: Int): Boolean
{
return ((this and flag) == flag)
}
Usage:
val myType = TestType.x.value or TestType.y.value //myType = 3
println(myType.hasFlag(TestType.x.value)) //true
println(myType.hasFlag(TestType.y.value)) //true
println(myType.hasFlag(TestType.z.value)) //false
println(myType.hasFlag(TestType.x.value or TestType.y.value)) //true
println(myType.hasFlag(TestType.x.value or TestType.z.value)) //false

Simpler or more functional way of chaining objects in Kotlin

I have created a helper method buildChain which essentially creates a
chain of objects given that they implement the interface IChain<T>
and set the contracts next member
The Code
interface Chain<T> {
var next: T?
operator fun plus(next: T): T?
}
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T {
var next: T? = null
members.forEachIndexed { i, t ->
if (i == 0) {
next = first + t
} else {
next = next?.run { this + t }
}
}
return first
}
Implementation example
data class Person(val name: String) : Chain<Person> {
override var next: Person? = null
override fun plus(next: Person): Person? {
this.next = next
return next
}
}
fun createPersonChain()
= buildChain(Person("Bob"), Person("Bitzy"), Person("Blitzy"))
Implementaion output example
#JvmStatic fun main(args: Array<String>) {
var first = createPersonChain()
// first.name = "Bob"
// first.next.name = "Bitzy"
// first.next.next.name = "Blitzy"
}
Is there a functional or simpler way for acheiving the code above keeping the implementaion usage the same?
A functional idiom fold suits your needs well: it takes an initial item and then iterates over the other items, maintaining an accumulated value, which is updated on each item being processed with the function you provide.
In Kotlin, it is fold extension function for Iterable, Sequence or Array.
You can use it in the following way:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T {
members.fold(first as T?) { acc, i -> acc?.let { it + i } }
return first
}
Here first as T? cast is needed for the accumulator type to be inferred as nullable T?, because plus in your Chain<T> returns nullable value (by the way, is it necessary?).
You can also use foldRight, which just iterates in the opposite order:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T? =
(listOf(first) + members)
.foldRight(null as T?) { i, acc -> acc?.let { i + acc }; i }
And there are reduce and reduceRight with similar semantics but using the first and the last item respectively for the accumulator's initial value. Here's the example with reduceRight:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T? =
(listOf(first) + members).reduceRight { i, acc -> i.apply { plus(acc) } }
Try apply{}. In the {} block pass your methods separated with ';'
Object().apply{ method1(); signUp(user) }