'converting one function into multiple - Kotlin

how would I go about taking this one function and turning it into multiple functions? I need to create a local double variable called change and set it to a test value (e.g. 44.77) Create five separate functions dollars(), quarters(), dimes(), nickels() and pennies().
Each function will:

  • accept a double amount as an argument
  • calculate and display that denominations number (e.g. 7 Dollars)
  • then return the recalculated change (e.g. 0.67) In Kotlin, the function signature for quarters would be: quarters(myChange: Double): Double

I really wish we didn't have to do separate function as one function is so much easier.

here is my code so far:

fun main(args: Array<String>) {
var remChange = .03 ;
monies(remChange);
}

fun monies(remChange: Double){
    
var dollars = Math.floor(remChange/1.0);
var remChange1 = remChange-(dollars*1.00);
    print(Math.round(dollars*1)/1)
        if(dollars<2) println("_Dollar"); else if (dollars>=2) println("_Dollars")
   


var quarter = Math.floor(remChange1/0.25);
var remChange2 = remChange1-(quarter*0.25);
    print(Math.round(quarter*4)/4)
        if(quarter<2) println("_Quarter"); else if (quarter>=2) println("_Quarters")
 
 
var dime = Math.floor(remChange2 / 0.10);
var remChange3 = remChange2 - (dime*0.10);
    print(Math.round(dime*10)/10)
        if(dime<2) println("_Dime") else if(dime>=2) println("_Dimes")
  

var nickel = Math.floor(remChange3 / 0.05);
var remChange4 = remChange3 - (nickel*0.05);
    print(Math.round(nickel*20)/20)
        if(nickel<2) println("_Nickel") else if (nickel>=2) println("_Nickels")
   

var penny = Math.floor(remChange4*100);
    print(Math.round(penny*100)/100)
        if(penny<2) println("_Penny") else if (penny>=2) println("_Pennies")

return Unit;
}

here is my attempt at this:

fun main(args: Array<String>) {
val change = 10.88
Dollar(change);
Quarter(change);
Dime(change);
Nickel(change);
Penny(change);
}
fun Dollar(myChange: Double): Double{
val dollar = myChange/(1.00).toFloat();
val change1 = myChange - (dollar * 1.00);
print((dollar * 1)/1);
if(dollar<2) println("_Dollar"); else if (dollar>=2) println("_Dollars");
return change1
}
fun Quarter(myChange: Double): Double{
val quarter = myChange/(0.25).toFloat();
val change2 = myChange - (quarter * 0.25);
println((quarter*4)/4);
if(quarter<2) println("_Quarter"); else if (quarter>=2) println("_Quarters");
return change2
}
fun Dime(myChange: Double): Double{
val dime = myChange/(0.10).toFloat();
val change3 = myChange - (dime * 0.10);
println((dime * 10)/10);
if(dime<2) println("_Dime"); else if(dime>=2) println("_Dimes");
return change3
}
fun Nickel(myChange: Double): Double{
val nickel = myChange/(0.05).toFloat();
val change4 = myChange - (nickel * 0.05);
println((nickel*20)/20);
if(nickel<2) println("_Nickel"); else if (nickel>=2) println("_Nickels");
return change4
}
fun Penny(myChange: Double){
val penny = myChange/100);
print((penny * 100)/ 100);
if(penny<2) println("_Penny"); else if (penny>=2) println("_Pennies");

return Unit
}


OUTPUT:
Unexpected tokens (use ';' to separate expressions on the same line)
Expecting an element

I can't figure out where the rouge ';' is or lack there of

and I'm not sure why it's missing an element. I just want it to produce the same output as my first code. I've done everything from youtube, w3, chegg, online forum research.



Solution 1:[1]

Since this is homework I'm not just going to provide a solution, but here's something important to consider - usually, the point of breaking stuff down into multiple functions is to reduce repetition, and make code reusable by having it as its own function. Check this out, from your solution:

fun Dime(myChange: Double): Double{
    val dime = myChange/(0.10).toFloat();
    val change3 = myChange - (dime * 0.10);
    println((dime * 10)/10);
    if(dime<2) println("_Dime"); else if(dime>=2) println("_Dimes");
    return change3
}

fun Nickel(myChange: Double): Double{
    val nickel = myChange/(0.05).toFloat();
    val change4 = myChange - (nickel * 0.05);
    println((nickel*20)/20);
    if(nickel<2) println("_Nickel"); else if (nickel>=2) println("_Nickels");
    return change4
}

Obviously there's a lot of repetition there, which is probably part of the reason you're saying it's just making things harder - it's true, it is! It's bloating the code and making it harder to maintain, because any change in the logic has to be repeated for every function, because it's the same logic, just using different values.

So what you could do, is create one calculation function that handles this logic, using a set of values that's passed in. Then, each denomination's function can call that calculation one, passing in the set of values appropriate for that denomination. So they end up acting as helper functions, "configuring" the main one.


So now the question is, what are those parameters? What is it that changes in each of those functions, what are the things that vary, the variables? You should probably think about it yourself before you read the rest, but I see these:

  • the value you're dividing by to get a coin count (e.g. 0.05 for nickels)
  • the value you're multiplying by to get a money total, to work out how much change is remaining (e.g. 0.05 for nickels)
  • the value you're multiplying your coin total by in the println statement (e.g. 20 for nickels)
  • the value you're dividing by in the same statement (e.g. 20 for nickels)
  • singular and plural labels for the denomination (e.g. _Nickel and Nickels for nickels)

Some of those look the same (e.g. 0.05 and 0.05) so maybe you can pass in a single variable, which gets used in two places in the logic. You have to work out if this is the case, if they're the same value being referenced twice, or if it's a coincidence.

Some of those also look related to other values, e.g. 10 * 0.1 = 1.0, 20 * 0.05 = 1.0. If this is the case, and there's a consistent relationship between two values, then maybe you can derive one from the other, meaning you only need to pass one value in, and calculate the others you need to use from that. Again, you need to work out if this is logically sound - you're writing an algorithm here, you need to understand what those values are and what they mean. Breaking stuff down into reusable functions is all about this kind of generalisation and working out how things relate to each other.


Once you have your nice utility function that takes a set of parameters, you can make helper functions that call it with a fixed set of values:

fun nickels(myChange: Double): Double {
    return calculate(parameters relating to nickels go here)
}

and now, there's no repetition! The calculation code is in one function, the printing code is in one function, and each of the denomination functions just holds unique data (the parameters passed to the main function).

I wouldn't necessarily tackle this problem like this (and I'm not reviewing the actual logic in your functions either) but it's good as a general example of how you approach things in a more functional way. Basically - if you find yourself repeating things, maybe you can stick that in its own function, and have the repeats call that instead

Solution 2:[2]

import kotlin.math.floor

fun dollars(remChange: Double): Double {
  return arrayOf(1.0).fold(0.0 to remChange) { acc, dbl ->
    val amount = floor(acc.second / dbl) * dbl
    amount to acc.second - amount
  }.first
}

fun quarters(remChange: Double): Double {
  return arrayOf(1.0, 0.25).fold(0.0 to remChange) { acc, dbl ->
    val amount = floor(acc.second / dbl) * dbl
    amount to acc.second - amount
  }.first
}

fun dimes(remChange: Double): Double {
  return arrayOf(1.0, 0.25, 0.1).fold(0.0 to remChange) { acc, dbl ->
    val amount = floor(acc.second / dbl) * dbl
    amount to acc.second - amount
  }.first
}

fun nickels(remChange: Double): Double {
  return arrayOf(1.0, 0.25, 0.1, 0.05).fold(0.0 to remChange) { acc, dbl ->
    val amount = floor(acc.second / dbl) * dbl
    amount to acc.second - amount
  }.first
}

fun pennies(remChange: Double): Double {
  return arrayOf(1.0, 0.25, 0.1, 0.05, 0.01).fold(0.0 to remChange) { acc, dbl ->
    val amount = floor(acc.second / dbl) * dbl
    amount to acc.second - amount
  }.first
}

val amount = 44.77
println("Dollars : " + dollars(amount))     // 44.0
println("Quarters : " + quarters(amount))   //  0.75
println("Dimes : " + dimes(amount))         //  0.0
println("Nickels : " + nickels(amount))     //  0.0
println("Pennies : " + pennies(amount))     //  0.2

Solution 3:[3]

Your error is this extra closing parenthesis on this line:

val penny = myChange/100);

I don't know of any online playground that shows you the error in the proper location. If you use an IDE like IntelliJ IDEA, it will highlight the error in your code as you type it with a red squiggly underline, just like a typo in a word processor. I highly recommend using IntelliJ IDEA if you are trying to learn Kotlin. It would have saved you a lot of time here.

Regarding your homework task, I think the point of challenging you to break your function up is to remove the repetition, which is a core principle of effective programming. Your new solution breaks it up into multiple functions without removing the repetition, so that's why it seems like a less sensible solution to you. See @cactustictacs' answer for more info about that.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cactustictacs
Solution 2
Solution 3 Tenfour04