Good afternoon friends, following up on a question...
# announcements
j
Good afternoon friends, following up on a question from a few weeks ago, I'd like to override some default
BigDecimal
extensions in the
kotlin
package:
Copy code
operator fun BigDecimal.plus(other: BigDecimal): BigDecimal = add(other, MathContext.DECIMAL128)

operator fun BigDecimal.minus(other: BigDecimal): BigDecimal = subtract(other, MathContext.DECIMAL128)

operator fun BigDecimal.div(other: BigDecimal): BigDecimal = divide(other, MathContext.DECIMAL128)

operator fun BigDecimal.times(other: BigDecimal): BigDecimal = multiply(other, MathContext.DECIMAL128)
The default implementation for
div
is:
Copy code
@kotlin.internal.InlineOnly
public inline operator fun BigDecimal.div(other: BigDecimal): BigDecimal = this.divide(other, RoundingMode.HALF_EVEN)
This will allow my implementation to always use
DECIMAL128
standard math context for all operations, eliminating any precision issues (for example
1.toBigDecimal() / 3.toBigDecimal()
results in
1
due to rounding. I want to help my engineers avoid this. What is the cleanest way to accomplish this? I tried adding a new file in package
kotlin
which works but feels like a code smell.
g
Sounds like you wanna extend a package or class and override one of its functions. I wouldn't go editing the original package, what it sounds like your trying to do... create a new class, extend from that one, override whatever.
j
@Gunslingor I was thinking that as well!
Copy code
class SafeDecimal(value: String) : BigDecimal(value, DECIMAL128) {
    operator fun plus(other: BigDecimal): BigDecimal = add(other, DECIMAL128)

    operator fun minus(other: BigDecimal): BigDecimal = subtract(other, DECIMAL128)

    operator fun div(other: BigDecimal): BigDecimal = divide(other, DECIMAL128)

    operator fun times(other: BigDecimal): BigDecimal = multiply(other, DECIMAL128)
    
    /**
     * Returns the value of this number as a [Byte], which may involve rounding or truncation.
     */
    override fun toByte(): Byte {
        TODO("Not yet implemented")
    }

    /**
     * Returns the [Char] with the numeric value equal to this number, truncated to 16 bits if appropriate.
     */
    override fun toChar(): Char {
        TODO("Not yet implemented")
    }

    /**
     * Returns the value of this number as a [Short], which may involve rounding or truncation.
     */
    override fun toShort(): Short {
        TODO("Not yet implemented")
    }
}
These definitions must exist as
BigDecimal
implements
kotlin.Number
.
g
Looks okay to me, what's the problem? Kotlin is big on extension like this... I tend to avoid it though, makes my code way to dependent on other peoples private everything, so when their code changes mine does too more often... effectively defeating the purpose of functions! lol IMHO... people write functions and classes to be atomic forever, they don't do so on the internals though so often. So me... I'd just define my own class MathWhatever and use those functions as is or, if that doesn't work for some reason, write your own version that you fully control... but that's just me, software engineer not programmer, hehe
j
I want
SafeDecimal.toChar
to match
BigDecimal.toChar
The latter does not exist on java.math.BigDecimal and is only in kotlin.Number. Somehow those are added to
BigDecimal
behind the covers and require implementation.
g
hmm... yeah, when I hear people talk like that I run in the other direction and write my own, lol, but I could be wrong
I only extend when I can extend a lot of things atomically, and generally to use not to override... e.g. a class Chevy can inherit from car, engine, tire, etc... but I see no reason to attempt to override the definition of a tire each time I define a new car type... if tire is designed right I absolutely shouldn't have to... maybe your re-purposing tire for use on aircraft instead of cars, maybe then it should be overridden? Not IMHO, in that case you should have a base class tires that gets inherited by airplaneTires and CarTires that can be used to EXTEND and definition of a car.... I don't know... I see the speed in doing it the way you and most Kotlin programmers describe, but it lacks in basic elegance and engineering practicality IMHO. Would love to hear another's opinion, why I'm crazy, lol. Abstraction is great when appropriate, but making real world relationships in code is just as important and far less potentially problematic.