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.
-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.
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.
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.
(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.
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.