← Code Compare

Input & Output

The shared task: print a formatted line that mixes text with a number (here Item 7 costs $3.50, with the price padded to two decimal places), then read a line of input from the user. The headline difference is the format string: Erlang and LFE use io:format with ~-prefixed control sequences (~p, ~.2f), Lua uses C-style string.format with %-placeholders (%d, %.2f), while Elixir and Gleam avoid format strings entirely - Elixir interpolates with #{...} and Gleam concatenates explicitly with <>. Watch too how each reads input: Erlang/LFE's io:get_line, Elixir's IO.gets, Gleam binding Erlang's io:get_line via @external (returning a Charlist), and Lua's io.read.

Show: ErlangElixirGleamLFELuerl
Erlang
-module(io_demo).
-export([main/0]).

main() ->
    Item = 7,
    Price = 3.5,
    %% ~p prints the integer, ~.2f formats the float to 2 decimals.
    io:format("Item ~p costs $~.2f~n", [Item, Price]),
    %% io:get_line/1 prints the prompt and returns the line, \n included.
    Name = io:get_line("Your name? "),
    io:format("Hello, ~s", [Name]).
%% => Item 7 costs $3.50
%% => Your name? <user types here>
%% => Hello, <name>

io:format/2 takes a control string where ~p pretty-prints any term and ~.2f renders a float with two decimals; io:get_line/1 reads one line (keeping its trailing newline), which the final ~s then echoes.

Elixir
item = 7
price = 3.5

# No format string: #{...} interpolates, and a format spec rounds the float.
IO.puts("Item #{item} costs $#{:erlang.float_to_binary(price, decimals: 2)}")

# IO.gets returns the line with its trailing \n, so trim before using it.
name = IO.gets("Your name? ") |> String.trim()
IO.puts("Hello, #{name}")
# => Item 7 costs $3.50
# => Your name? <user types here>
# => Hello, <name>

Elixir interpolates values with #{...} rather than a format string; for fixed decimals it reaches for :erlang.float_to_binary/2. IO.gets/1 reads a line (newline and all), so it is piped through String.trim/1 before display.

Gleam
import gleam/io
import gleam/int
import gleam/float
import gleam/string
import gleam/erlang/charlist.{type Charlist}

// gleam_erlang no longer ships a get_line; bind Erlang's io:get_line
// directly. It returns a charlist (the line, with its trailing newline).
@external(erlang, "io", "get_line")
fn get_line(prompt: String) -> Charlist

pub fn main() -> Nil {
  let item = 7
  let price = 3.5

  // No format strings: build the line with <> and explicit conversions.
  io.println(
    "Item "
    <> int.to_string(item)
    <> " costs $"
    <> float.to_string(price),
  )

  // Convert the charlist to a String and trim the trailing newline.
  let name = string.trim(charlist.to_string(get_line("Your name? ")))
  io.println("Hello, " <> name)
}

Gleam has no interpolation or format strings, so the line is assembled with <> and explicit int.to_string / float.to_string calls. Current gleam_erlang no longer exposes get_line, so the example binds Erlang's io:get_line via @external; it returns a Charlist, which charlist.to_string converts to a String before string.trim strips the trailing newline.

LFE
(defmodule io-demo
  (export (main 0)))

(defun main ()
  (let ((item 7)
        (price 3.5))
    ;; Same Erlang control string: ~p for the int, ~.2f for the float.
    (io:format "Item ~p costs $~.2f~n" (list item price))
    ;; io:get_line returns the line with its trailing newline.
    (let ((name (io:get_line "Your name? ")))
      (io:format "Hello, ~s" (list name)))))
;; => Item 7 costs $3.50
;; => Your name? <user types here>
;; => Hello, <name>

LFE calls the very same io:format BEAM function with Erlang's ~p and ~.2f directives, just written as an S-expression with the arguments in a (list ...). io:get_line likewise reads one line, newline included.

Luerl
local item = 7
local price = 3.5

-- C-style format: %d for the integer, %.2f for two decimal places.
print(string.format("Item %d costs $%.2f", item, price))

-- io.write avoids the trailing newline so the prompt stays on one line;
-- io.read("l") reads a line WITHOUT the newline.
io.write("Your name? ")
local name = io.read("l")
print("Hello, " .. name)
-- => Item 7 costs $3.50
-- => Your name? <user types here>
-- => Hello, <name>

Standard Lua uses string.format with C-style placeholders (%d, %.2f) and joins strings with ... io.write prints the prompt without a newline, and io.read("l") returns the next line already stripped of its trailing newline.