How to use BigDecimal in Kotlin Multiplatform? - kotlin

I followed the tutorial https://kotlinlang.org/docs/tutorials/native/mpp-ios-android.html, then I successfully create the folders of androidmain, iosmain and commonmain.
However when I want to implement the datatype BigDecimal in the commonmain. It won't work. I need the decimal dataype for the currency.

I know that the question is old, but, in case anyone stumbles upon this topic, I made a KigDecimal library that implements BigDecimal and BigInteger for kotlin multiplatform (for jvm and js). The library is distributed completely freely. Therefore, I invite everyone to supplement and expand it, if desired.
On the jvm side, BigDecimal and BigInteger are just the corresponding types from java. And on the js side is used https://www.npmjs.com/package/bigdecimal.
The main repository is located here: https://gitflic.ru/project/mikhaylutsyury/kig-decimal
There is also a mirror on github: https://github.com/YuryMikhailuts/kig-decimal
But the mirror can sometimes lag a little behind the main repository.

There is no support for BigDecimal in the Kotlin common code (yet).
You may have a look at the related thread
https://discuss.kotlinlang.org/t/multiplatform-bigdecimal-implementation/5631
You may create your own implementation for such a class with expect and actual keywords.
https://kotlinlang.org/docs/reference/platform-specific-declarations.html
The idea is as follows:
you declare expect declarations for the BigDecimal type in common code
you use the actual annotations at every platform to supply the platform specific implementation (e.g. JVM's BigDecimal class)

Related

What variable type can I use to hold huge numbers in kotlin?

Is there a class similar to BigInteger for Java in Kotlin to hold very large numbers? Eg: 100 Digits
There is currently no such class in the official Kotlin standard library other than Java's BigInteger. You might be able to use third-party libraries such as kotlin-multiplatform-bignum or kt-math, as long as you're ok with their licence conditions and be aware that both of them may change in future, and that neither of them is likely to be as fast as Java's BigInteger.

Why strip() is deprecated in Kotlin and what should I use instead?

For String.strip() I get warning 'strip(): String!' is deprecated. This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version"
Why is it? "strip" comes from Java String
What should I use?
First of all: String.strip() is a new function in Java 11. Kotlin targets JVM 6 by default, so I was unable to reproduce your issue at first, I got a compilation error. Using JVM 11 as target in Android Studio worked with your compiler warning.
Kotlin's string class (kotlin.String) is not the same as Java's string class (java.lang.String). The Kotlin type is however mapped to the Java type (quote):
Kotlin types such as List, MutableList, String, CharSequence etc. are all compiled to their java equivalents, and thus any runtime checks will not be able to distinguish between them. At compile-time, however, they are distinct types with different sets of members. In particular, the Kotlin types do not have all members that the corresponding Java types have. They have those listed in the Kotlin std lib reference, as well as a few extra JVM specific ones (such as Collection.stream())
kotlin.String does not have a .strip() function. You are just "incidentally" calling java.lang.String.strip() which happens to be there in some target JVMs but not defined in Kotlin. If you look at the kotlin.String source in your IDE you can see it is not defined there.
The reason it is not there is because it was explicitly graylisted by the Kotlin team:
Some methods in JDK classes are undesirable in Kotlin built-ins (e.g. a lot of String methods or List.sort(), because there are Kotlin analogues with better signatures already defined).
.strip() does the same thing as kotlin.String.trim(), so use that instead.
Extended Reading
Extended Reading 2
The commit which put .strip() on the graylist

Why Kotlin blindly change internal classes into public in JVM?

As you know the private classes in Kotlin change to package-private under the hood and internals changed to the public.
unfortunately, this can lead to the known problem here.
if the compiler sees the usage of Kotlin internal classes when it wants to change it to the byte code, it can choose package-private for internal kotlin classes that didn't use outside of the package and choose public for others, so we can handle above problem on our own.
Or they can define another annotation such as #JvmPackagePrivate before internal classes to tell the compiler we want a package-private class in java.
Or they can do both.
The question is, why they don't solve this obvious problem with such an obvious solution?
Are they have another approach to solve this?
I just got acquainted with the Kotlin, so I think that I cant create lib for java with kotlin because when I create internal concrete classes, all client can see them outside of the library and its serious problem with kotlin. why they can't see this obvious problem??????
I want to mention that none of the answers in here solve this problem because of #JvmSynthetic and #JvmName just target the fun in kotlin, not classes and at the end they both visible even if they change the name of classes.
at last kotlin claims that it is completely interoperable with java but I think it's not right. better to say that it is 99 percent interoperable with java :)

What is the purpose of actual keyword in Kotlin

I noticed that some functions for coroutines are marked with actual keyword.
From documentation:
actual denotes a platform-specific implementation in multiplatform
projects
As I understood from documentation actual keyword is used for multiplatform projects and should work in pair with expect keyword.
Something like this:
Common module:
package org.jetbrains.foo
expect class Foo(bar: String) {
fun frob()
}
fun main(args: Array<String>) {
Foo("Hello").frob()
}
Corresponding module:
package org.jetbrains.foo
actual class Foo actual constructor(val bar: String) {
actual fun frob() {
println("Frobbing the $bar")
}
}
That case is clear.
But in package kotlinx.coroutines.experimental I noticed that some functions like launch or withContext are marked as actual but there are no expect functions in package.
So what is the purpose of actual keyword without expect?
The kotlinx.coroutines library actually makes use of multiplatform projects since it supports both the JVM and JS compilation targets.
You can find the common module here, and the specific expect declarations for the functions you've mentioned here.
While the source code in the other answer helped, I found this page (linked off of the page #jim-andreas mentioned in the comments above) was much more helpful.
Specifically, this passage:
If you're developing a multiplatform application that needs to access platform-specific APIs that implement the required functionality (for example, generating a UUID), use the Kotlin mechanism of expected and actual declarations.
With this mechanism, a common source set defines an expected
declaration, and platform source sets must provide the actual
declaration that corresponds to the expected declaration. This works
for most Kotlin declarations, such as functions, classes, interfaces,
enumerations, properties, and annotations.
The compiler ensures that every declaration marked with the expect keyword in the common module has the corresponding declarations marked with the actual keyword in all platform modules. The IDE provides tools that help you create the missing actual declarations.
Again, for more information, you can visit this page.

Can anyone here explain the Kotlin/Native spinner app project structure in detail? Also the specifics on how different modules work

I would like to specifically know how the common module is used by the individual client modules. Which are the truly common parts that is shared by all the clients and the server.
Thank you.
This is easy. I suspect you're talking about Kotlin multiplatform modules.
Consider print and println.
In the common module we can expect a print function:
expect fun print(a: String)
But we don't know how was it implemented, because the common module doesn't know anything about Java's System.out, as well as JavaScript's console.
But the common module can expect such function that prints a String on screen, without providing an implementation.
Since we have print, we can implement println:
fun println(a: String) = print("$a\n")
All codes above are inside the common module.
And all you have to do is to to implement print for JVM/JS spererately.
For JVM:
actual fun print(a: String) = System.out.println(a)
For JS:
actual fun print(a: String) = console.log(a)
(Maybe) For Native:
actual fun print(a: String) = printf(a)
The three code blocks above are inside client modules.
Consider you've designed a data format, you have encoding and decoding code. Those codes are used in your Android device (JVM), your backend server (JVM), your frontend webpage (JS), your native app (Native).
You use Kotlin in all those sub projects but you want to write the encoder/decoder only once. Kotlin multiplatform module solves this probelm.
About the spinner app
It's not using the standard kotlin approach for creating multiplatform project. It's a trick on gradle.
There's a readResources (and randomInit as well, for osx/linux) function that implements differently on platforms but of the same signature, and gradle will decide which Kommon.kt should be compiled with the client projects.
readResources and randomInit should be marked as actual, and there should be a "common module" that has "expect"ed those two functions.
They didn't do this probably because Kotlin 1.2 (which brings stable multiplatform support) isn't out when KotlinConf holds.