Search code examples
erlangerlang-shell

Error evaluating arithmetic expression


I am an Erlang beginner and am trying to make a simple command-line application where the user enters the width and height of a floor, the cost per square foot of flooring and they are returned a price. Essentially I'm just accepting three integer values and returning the product.

23> c(costcalc).
{ok,costcalc}
24> costcalc:start().
Calculate the cost of flooring based on width, height, and cost per square foot.

Width in feet: 5
Height in feet: 5
Cost in dollars per square foot: $4
** exception error: an error occurred when evaluating an arithmetic expression in function  costcalc:start/0 (costcalc.erl, line 23)

Here is the code I am using:

start() ->
  io:format("Calculate the cost of flooring based on width, height, and cost per square foot.\n"),
  W = string:to_integer(io:get_line("Width in feet: ")),
  H = string:to_integer(io:get_line("Height in feet: ")),
  C = string:to_integer(io:get_line("Cost in dollars per square foot: $")),
  Cost = W * H * C,
  io:fwrite(Cost).

Line 23 is Cost = W * H * C, which should be 100. When I run 5 * 5 * 4. in the shell directly it calculates without issue. I should also note that this happens whether or not I use string:to_integer() which I would imagine I can get by without.

What am I missing?


Solution

  • As mentioned by @Khashayar, the problem in your code is that string:to_integer/1 returns a pair (a tuple with two elements) and the integer is the first element.

    However, you should not use this function. A string in Erlang is just a list of integers, and what you meant to use is list_to_integer/1. This is the common way to convert a string to an integer.

    If you used list_to_integer/1, you would have avoided the bug in @Khashayar's code where the second pair element is matched with anything. Indeed, you can enter the following:

    Calculate the cost of flooring based on width, height, and cost per square foot. 
    Width in feet: 1.9
    Height in feet: 1.9
    Cost in dollars per square foot: $ 4.9
    4
    

    While 1.9*1.9*4.9 actually equals 17.689.

    Unfortunately, there is no list_to_number/1 function which would return either an integer or a float. The most common way to handle this is to perform a try/catch with list_to_float/1 and fallback to list_to_integer/1. Alternatively, you could use io_lib:fread/2 or string:to_float/1 which do not raise exceptions (still, as mentioned above, using string:to_float/1 is judged a bad practice).