A modern, high-level programming language with beautiful syntax and powerful math
Try Online (no install needed) • Official Documentation • GitHub
- What is Sidef?
- Installation
- Your First Program
- How to Run Sidef Code
- Comments
- Variables
- Numbers
- Strings
- Booleans
- Operators and Expressions
- Operator Precedence — The Most Important Rule
- Printing Output
- Getting Input
- Control Flow — Making Decisions
- Loops
- Functions
- Arrays
- Hashes (Dictionaries)
- String Operations
- Working with Files
- Error Handling
- A Taste of Sidef's Math Powers
- Beginner Projects to Try
- Where to Learn More
Sidef is a modern, high-level programming language that runs on top of Perl. It takes inspiration from several languages:
- Ruby — clean, readable syntax
- Raku — expressive features and metaoperators
- Julia — powerful mathematical capabilities
- Exact numbers by default. Sidef stores decimals as exact fractions, so
0.1 + 0.2 == 0.3is actuallytrue— unlike most other languages. - Giant numbers, no effort. It handles arbitrarily large integers and floats without any special libraries.
- Rich built-in math. Prime numbers, factorization, number theory — all built in.
- Clean, readable syntax. Code reads almost like plain English.
- Functional and object-oriented. You can mix styles naturally.
# Print the first 10 prime numbers
say 10.primes
# Exact decimal math (no floating-point surprises!)
say (0.1 + 0.2 == 0.3) # true
# Factorial of 100 — a 158-digit number!
say 100!
# Sum all numbers from 1 to 100
say (1..100).sum💡 Want to try Sidef without installing anything? Head to https://tio.run/#sidef and run code right in your browser.
Sidef requires three C math libraries: GMP, MPFR, and MPC. These provide big-number support. Your package manager handles them automatically with the commands below.
sudo apt install libgmp-dev libmpfr-dev libmpc-dev libc-dev cpanminus
cpanm --sudo -n SidefThen verify:
sidef -vtrizen -S sidefbrew install gmp mpfr libmpc
cpan Sidefpkg install perl make clang libgmp libmpfr libmpc
cpan -T SidefDownload the ready-to-run executable from the GitHub Releases page. Unzip and run sidef.exe from the command prompt.
If you have Perl installed, you can always install via CPAN:
cpan Sidef
# Or skip the test suite for a faster install:
cpan -T Sidefwget 'https://github.com/trizen/sidef/archive/master.zip' -O master.zip
unzip master.zip
cd sidef-master
perl Build.PL
sudo ./Build installdeps
sudo ./Build installsidef -v # Print version
sidef -h # Print helpCreate a file called hello.sf (Sidef files use the .sf extension):
#!/usr/bin/sidef
say "Hello, World!"The first line (#!/usr/bin/sidef) is called a shebang — it's optional, but it tells the operating system which program to use to run this file. You can leave it out if you want.
Save the file and run it (see the next section for how to do that). You should see:
Hello, World!
Congratulations — you just ran your first Sidef program! 🎉
sidef hello.sfUse the -e flag for quick experiments:
sidef -e 'say "Hello!"'
sidef -e 'say (2 ** 10)'
sidef -e 'say 5.primes'Run sidef with no arguments to enter the interactive prompt, where you type expressions and see results immediately:
$ sidef
Sidef 26.04, running on Linux, using Perl v5.42.1.
Type "help", "copyright" or "license" for more information.
> say "Hello!"
Hello!
> (2 + 3)
5
> 10.primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
> 100!
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
The REPL is great for exploring the language and testing ideas. Press Ctrl+D or type exit to quit.
If you don't want to install anything, use the online playground: https://tio.run/#sidef
Comments are notes in your code that Sidef ignores when running. They're for humans, not computers.
# This is a single-line comment.
say "Hello!" # Comments can go at the end of a line too.
/*
This is a multi-line comment.
It can span as many lines as you need.
Useful for longer explanations.
*/
say "After the comment block."💡 Good habit: Write comments to explain why your code does something, not just what it does. Your future self will thank you.
Variables store values that your program can use and manipulate. The standard way to declare a variable in Sidef is with the var keyword:
var num = 42
var str = "42"
var bool = trueSidef has four kinds of variables, each with different scoping and lifetime behavior.
The most common type. Lexical variables are block-scoped — they exist only within the block { } where they are declared.
var x = 42
say x # prints: 42Static variables are also block-scoped, but they are only initialized once, no matter how many times the block runs.
for k in (1..10) {
static x = (41 + k) # assigned only on the first iteration (k=1)
say x # always prints: 42
}Global variables are accessible from anywhere in your program. Use them sparingly — local or lexical variables are usually a better choice.
global x = 42
say x # prints: 42Local variables temporarily override a global variable within a specific block. Once the block ends, the global value is restored.
global x = 42
do {
local x = 100
say x # prints: 100 (local value)
}
say x # prints: 42 (global value restored)All variables in Sidef are block-scoped. Inner blocks can see variables from outer blocks, but not the other way around. Declaring a variable with the same name in an inner block shadows the outer one — it does not overwrite it.
var x = 'o'
do {
say x # o (outer x)
var x = 'm'
say x # m (middle x)
do {
say x # m (still middle x)
var x = 'b'
say x # b (inner x)
}
say x # m (inner x is gone)
}
say x # o (back to outer x)You can declare several variables at once using parentheses:
var (x, y, z) = (3.14, false, "foo")You can also provide default values. If the right-hand side is shorter than the left-hand side, the remaining variables keep their defaults:
var (x, y=755, z=777) = (666, 655)
say x # 666
say y # 655 (overridden by the assignment)
say z # 777 (default kept, nothing assigned)It's also valid to skip the right-hand side entirely, leaving all variables at their declared defaults:
var (
a = 42,
*b = (1,2,3,4), # slurpy array (see below)
:c = (x => 1, y => 2), # slurpy hash (see below)
)
say a #=> 42
say b #=> [1,2,3,4]
say c #=> Hash(x => 1, y => 2)A previously declared variable can even be referenced as a default value for a later one in the same declaration:
var (
a = 42,
b = (10 + a) # refers to a above
)
say a #=> 42
say b #=> 52Prefixing a variable name with * makes it collect a list into an Array, and : makes it collect key-value pairs into a Hash:
var *arr = (1,2,3) # Array
var :hash = (a => 1, b => 2) # Hash
say arr # [1,2,3]
say hash # Hash(a => 1, b => 2)Any method called on a variable applies to the value it holds. The variable itself is not changed:
var x = 'sidef'
say x.uc # SIDEF
say x # sidef (unchanged)To modify the variable in place, append ! to the method name:
var x = 'sidef'
x.uc!
say x # SIDEFArithmetic assignment operators also modify variables in place:
var x = 5
x += 10
say x # 15:= assigns a value only if the variable is currently nil. It's commonly used to provide fallback values:
var x = nil
x := 42 # x is nil, so it gets assigned 42
x := 99 # x is already defined, so this is ignored
say x # 42This is especially useful when building a hash of arrays:
var hash = Hash()
hash{:key} := [] << (1,2)
hash{:key} := [] << 3
say hash{:key} #=> [1,2,3]The := operator also returns an lvalue, so you can chain further method calls on the result:
var hash = Hash()
hash{:key} := 0 -> max!(10)
hash{:key} := 0 -> max!(42)
say hash{:key} #=> 42\\ checks whether a value is defined, without assigning anything:
var x = nil
x \\ say "x is not defined" # prints: x is not definedUse the del keyword to permanently remove a variable. Any attempt to use it afterward causes a parse-time error:
var foo = 42
del foo
say foo # parse-time error: attempt to use deleted identifierEvery block in Sidef has a pre-declared variable _ (underscore) that holds the current element being iterated over. You rarely need to write _ explicitly, because the unary dot (.) operator is shorthand for _.method:
[25, 36, 49].map { .sqrt }
.each { .log.say }Here .sqrt means _.sqrt, and .log.say means _.log.say. You can also use _ directly to index into arrays or hashes stored in the topic variable:
say [[41,'a'], [42,'b'], [43,'c']].map { .[0] }
#=> [41, 42, 43]
say [Hash(a=>41), Hash(a=>42), Hash(a=>43)].map { .{:a} }
#=> [41, 42, 43]Two built-in variables are always available:
ARGV— command-line arguments passed to the scriptENV— environment variables
ARGV.each { |arg| say arg }
say ENV{:HOME}Sidef exposes some of Perl's special "magic" variables for low-level control over I/O behavior:
local $/ = nil # change the input record separator
local $\ = "\n" # change the output record separator
local $, = "\n" # change the field separator
say $^PERL # path to the Perl executable
say $^SIDEF # path to the Sidef executableThese look like variables but are actually I/O handles:
STDERR.say("Some error!")
STDOUT.say("Some output...")
STDIN.readline() # reads one line from standard inputARGF reads lines from files passed as arguments, or from standard input if none are given — useful for writing cat-like utilities:
ARGF.each { |line| say line }DATA reads content placed after __END__ or __DATA__ in the same file:
DATA.each { |line| say "=>> #{line}" }
__DATA__
here are
some data
linesSidef provides three ways to declare constants.
Declared and initialized at runtime. Once set, they cannot be changed.
const pi = 3.14
say pi # 3.14When declared inside a function, a const is re-created on each call, but remains immutable within that call:
func f(a) {
const x = a
return (x + 2)
}
say f(40) #=> 42
say f(50) #=> 52Evaluated at compile time. The value must be a standalone constant expression. These are the most efficient kind of constant.
define PHI = (1.25.sqrt + 0.5)
define IHP = -(1.25.sqrt - 0.5)
say (PHI**12 - IHP**12 / (PHI-IHP)) #=> 144Attempting to reassign a define constant produces a compile-time error (vs. const, which gives a runtime error).
enum declares a sequence of constants with automatically incrementing values (starting at 0):
enum |Black, White|
say Black # 0
say White # 1You can specify a starting value. Each subsequent constant is produced by calling .inc on the previous one:
enum |α="a", β|
say α # 'a'
say β # 'b'All three constant types support the same multi-declaration syntax:
const ( # or: define ( ... ) or static ( ... )
a = 42,
*b = (1,2,3,4),
:c = (x => 1, y => 2),
)You can take a reference to a variable with \ and dereference it with *:
var name = "sidef"
var ref = \name # take a reference
var original = *ref # dereferenceReferences are most useful for passing variables into functions so the function can assign a new value to them:
func assign2ref(ref, value) {
*ref = value
}
var x = 10
assign2ref(\x, 20)
say x # 20The Ref type can be used in type signatures to indicate that a parameter should be a variable reference.
Sidef has excellent number support. You don't need to worry about separate types for most uses — it handles integers, decimals, and large numbers automatically.
var a = 255 # decimal
var b = 0xff # hexadecimal (same value: 255)
var c = 0b11111111 # binary (same value: 255)
var d = 0377 # octal (same value: 255)
# Underscores make large numbers readable
var million = 1_000_000
var big = 1_234_567_890This is one of Sidef's best features. Decimals are stored as exact fractions internally, so there are no floating-point surprises:
say (0.1 + 0.2) # 0.3 (exact!)
say (0.1 + 0.2 == 0.3) # true (unlike most languages)
say (1/3 + 1/3 + 1/3) # 1 (exact fraction arithmetic)Sidef handles arbitrarily large numbers without any special setup:
say (2 ** 100) # 1267650600228229401496703205376
say 50.factorial # a 65-digit number
say 100! # a 158-digit number (! is factorial postfix)say 42.is_even # true
say 43.is_odd # true
say (-5).abs # 5
say 3.14.floor # 3
say 3.14.ceil # 4
say 3.75.round # 4
say 16.sqrt # 4
say 2.log # natural logarithm of 2
say 100.log10 # 2 (log base 10)
say 7.is_prime # true
say 12.is_prime # falsesay Inf # infinity
say -Inf # negative infinity
say NaN # not a number (result of invalid operations)A string is a piece of text. Sidef has two kinds of string literals.
var name = "Alice"
say "Hello, #{name}!" # Hello, Alice!
say "Two plus two is #{(2+2)}" # Two plus two is 4
say "Tab:\there" # Tab: here
say "Newline:\nSecond line" # prints on two linesInside #{} you can put any Sidef expression:
var items = 5
say "You have #{items} item#{(items == 1 ? '' : 's')}."
# You have 5 items.say 'Hello, #{name}!' # Hello, #{name}! (printed literally)
say 'No \n escape here' # No \n escape herevar first = "Hello"
var second = "World"
say (first + ", " + second + "!") # Hello, World!say ("ha" * 3) # hahaha
say ("-" * 20) # --------------------var message = <<'END'
This is a
multi-line string.
No interpolation here.
END
var greeting = <<-"END"
Hello, #{name}!
Welcome to Sidef.
ENDBoolean values are simply true and false.
var is_raining = true
var is_sunny = false
say is_raining # true
say is_sunny # falseIn Sidef, the following values are falsy (treated as false in conditions):
falsenil(the absence of a value)0""(empty string)
Everything else is truthy.
if (0) {
say "This won't print."
}
if ("hello") {
say "This will print!" # prints
}var x = nil
say x.is_nil # true
# Conditional assignment: only assign if currently nil
var result = nil
result := compute_value() # only called if result is nilsay (10 + 3) # 13 addition
say (10 - 3) # 7 subtraction
say (10 * 3) # 30 multiplication
say (10 / 3) # 10/3 (exact fraction)
say (10 % 3) # 1 modulo (remainder)
say (10 ** 3) # 1000 exponentiation (power)These return true or false:
say (5 == 5) # true (equal)
say (5 != 3) # true (not equal)
say (5 > 3) # true (greater than)
say (5 < 10) # true (less than)
say (5 >= 5) # true (greater than or equal)
say (5 <= 10) # true (less than or equal)say (true && false) # false (and — both must be true)
say (true || false) # true (or — at least one must be true)
say (!true) # false (not — flips true/false)var n = 5
n++ # n is now 6
n-- # n is now 5
++n # n is now 6 (prefix: increments before returning value)say ("apple" == "apple") # true
say ("apple" != "banana") # true
say ("apple" lt "banana") # true (alphabetically less than)
say ("banana" gt "apple") # true (alphabetically greater than)
⚠️ This is the single most important rule to understand in Sidef. Get this wrong and your programs will produce surprising results.
Most languages have complex precedence rules (multiply before add, etc.). Sidef is different: it uses whitespace to determine how operators group.
When operators are written without spaces around them, they are grouped into a single unit first. When operators are written with spaces around them, they are evaluated left to right.
#
# Example 1: spaces between ALL operators → left to right
#
say (1 + 2 * 3 + 4) # means: ((1+2) * 3) + 4 = 13
# ↑
# evaluated as: ((1 + 2) * 3) + 4
#
# Example 2: no spaces → binds tightly
#
say (1 + 2*3 + 4) # means: 1 + (2*3) + 4 = 11
# ↑
# 2*3 is one tight unit
#
# Example 3: mixing both
#
say (1+2 * 3+4) # means: (1+2) * (3+4) = 21
# ↑↑↑ ↑↑↑
# tight tight → each becomes a unit, then * is evaluatedWhen in doubt, use explicit parentheses. This always works correctly and makes your intention clear to anyone reading the code:
# These are all clear and unambiguous:
var area = (length * width)
var average = ((a + b + c) / 3)
var hyp = ((a**2 + b**2).sqrt)
var tax = (price * (1 + tax_rate))You can use \ or a leading . to force a different grouping:
say (1 + 2 \* 3) # means 1 + (2 * 3) = 7
say (1 + 2 .* 3) # same thing| Expression | Meaning | Result |
|---|---|---|
1 + 2 * 3 |
(1 + 2) * 3 |
9 |
1 + 2*3 |
1 + (2*3) |
7 |
1+2 * 3+4 |
(1+2) * (3+4) |
21 |
(1 + 2) * 3 |
(1 + 2) * 3 |
9 |
💡 Best practice: Until you are very comfortable with this rule, wrap every binary operation in its own parentheses. It costs nothing and prevents bugs.
say "Hello, World!" # prints with a newline at the end
print "No newline here" # prints without a newline
say "" # prints a blank linesay "Name: ", "Alice" # Name: Alice
say 1, 2, 3 # 123
say [1, 2, 3] # [1, 2, 3]> is a shorthand alias for say:
> "Hello!" # same as: say "Hello!"var name = "Alice"
var score = 98.5
say "Player: #{name}, Score: #{score}"
# Player: Alice, Score: 98.5
# Formatting numbers
say "Pi ≈ #{Num.pi.round(4)}" # Pi ≈ 3.1416
say "Big: #{(10**20).commify}" # Big: 100,000,000,000,000,000,000Read a line of input from the user with read:
print "What is your name? "
var name = read(String)
say "Hello, #{name}!"Read a number:
print "Enter a number: "
var n = read(Number)
say "You entered: #{n}"
say "Its square is: #{(n ** 2)}"print "Enter your age: "
var age = read(Number)
if (age >= 18) {
say "You are an adult."
} else {
say "You are a minor."
}var temperature = 22
if (temperature > 30) {
say "It's hot outside!"
} elsif (temperature > 20) {
say "It's a nice day."
} elsif (temperature > 10) {
say "It's a bit chilly."
} else {
say "It's cold — grab a coat!"
}For simple one-line conditions, you can put if after the statement:
say "You win!" if (score > 100)
say "Game over." if (lives == 0)
var n = read(Number)
die "Must be positive!" if (n < 0)A compact way to pick one of two values:
var age = 20
var status = (age >= 18 ? "adult" : "minor")
say status # adultvar logged_in = false
say "Please log in." unless logged_ingiven/when is Sidef's switch-like construct. It uses "smart matching" to check each when clause:
var day = "Monday"
given (day) {
when ("Saturday") { say "Weekend!" }
when ("Sunday") { say "Weekend!" }
when (/^Mon/) { say "Start of the work week." }
else { say "A regular weekday." }
}You can match against numbers, strings, regex patterns, and more.
with runs its block only when the value is defined (not nil):
var result = some_function()
with (result) { |val|
say "Got a result: #{val}"
}
orwith (fallback_function()) { |val|
say "Got fallback: #{val}"
}
else {
say "Nothing was returned."
}Keeps running as long as the condition is true:
var count = 1
while (count <= 5) {
say "Count: #{count}"
count++
}Output:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Runs the body at least once before checking the condition:
var n = 0
do {
n++
say n
} while (n < 3)
# prints: 1, 2, 3for i in (1..5) {
say "Step #{i}"
}var fruits = ["apple", "banana", "cherry"]
for fruit in fruits {
say "I like #{fruit}"
}3.times {
say "Hello!"
}
# prints Hello! three times
5.times { |i|
say "Iteration #{i}" # i goes from 0 to 4
}[10, 20, 30].each { |n|
say "Value: #{n}"
}var n = 1
loop {
say n
n++
break if (n > 5)
}# next: skip to the next iteration
for i in (1..10) {
next if (i % 2 == 0) # skip even numbers
say i
}
# prints: 1, 3, 5, 7, 9
# break: exit the loop early
for i in (1..100) {
break if (i > 5)
say i
}
# prints: 1, 2, 3, 4, 5for i in ((0..20).by(5)) {
say i # 0, 5, 10, 15, 20
}
for i in ((10^..1).by(-1)) {
say i # 10, 9, 8, ..., 1
}1.upto(5) { |i| say i } # 1 2 3 4 5
5.downto(1) { |i| say i } # 5 4 3 2 1Functions let you name and reuse pieces of code.
func greet(name) {
say "Hello, #{name}!"
}
greet("Alice") # Hello, Alice!
greet("Bob") # Hello, Bob!The last expression in a function is returned automatically. You can also use return explicitly:
func add(a, b) {
(a + b) # returned automatically
}
func multiply(a, b) {
return (a * b) # explicit return
}
var sum = add(3, 4) # 7
var product = multiply(3, 4) # 12
say sum # 7
say product # 12func greet(name = "World", greeting = "Hello") {
say "#{greeting}, #{name}!"
}
greet() # Hello, World!
greet("Alice") # Hello, Alice!
greet("Bob", "Good morning") # Good morning, Bob!You can pass arguments by name, in any order:
func make_box(width, height, depth) {
say "Box: #{width} × #{height} × #{depth}"
}
make_box(width: 10, depth: 5, height: 3)
# Box: 10 × 3 × 5func sum(*numbers) {
numbers.reduce(0, { |acc, n| (acc + n) })
}
say sum(1, 2, 3) # 6
say sum(10, 20, 30, 40) # 100You can require arguments to be a specific type:
func square(Number n) {
(n ** 2)
}
func shout(String s) {
s.uc + "!!!"
}
say square(5) # 25
say shout("hello") # HELLO!!!If you pass the wrong type, Sidef will raise an error.
A function can call itself — this is called recursion:
func factorial(n) {
return 1 if (n <= 1)
(n * factorial((n - 1)))
}
say factorial(5) # 120
say factorial(10) # 3628800is cached makes Sidef automatically remember results so the same calculation is never repeated:
func fib(n) is cached {
return n if (n <= 1)
(fib((n - 1)) + fib((n - 2)))
}
say fib(10) # 55
say fib(50) # 12586269025 (fast, thanks to caching)
say fib(100) # 354224848179261915075Without is cached, fib(50) would take an impossibly long time.
Functions can be stored in variables:
var double = { |n| (n * 2) }
var square = { |n| (n ** 2) }
var add = { |a, b| (a + b) }
say double(5) # 10
say square(4) # 16
say add(3, 7) # 10A closure is a function that "remembers" the variables from where it was created:
func make_counter(start = 0) {
var count = start
func {
count++
say "Count: #{count}"
}
}
var counter_a = make_counter()
var counter_b = make_counter(10)
counter_a() # Count: 1
counter_a() # Count: 2
counter_b() # Count: 11
counter_a() # Count: 3 (independent from counter_b)An array is an ordered list of values. Arrays can hold any mix of types.
var fruits = ["apple", "banana", "cherry"]
var numbers = [1, 2, 3, 4, 5]
var mixed = [1, "hello", true, 3.14]
var empty = []Arrays are zero-indexed — the first element is at index 0:
var fruits = ["apple", "banana", "cherry", "date"]
say fruits[0] # apple (first)
say fruits[1] # banana (second)
say fruits[-1] # date (last)
say fruits[-2] # cherry (second to last)var arr = [1, 2, 3]
arr.push(4) # add to end → [1, 2, 3, 4]
arr.pop # remove last → [1, 2, 3]
arr.unshift(0) # add to start → [0, 1, 2, 3]
arr.shift # remove first → [1, 2, 3]
arr[1] = 99 # replace by index → [1, 99, 3]var nums = [3, 1, 4, 1, 5, 9, 2, 6]
say nums.length # 8
say nums.sort # [1, 1, 2, 3, 4, 5, 6, 9]
say nums.reverse # [6, 2, 9, 5, 1, 4, 1, 3]
say nums.sum # 31
say nums.min # 1
say nums.max # 9
say nums.uniq # [3, 1, 4, 5, 9, 2, 6] (remove duplicates)
say nums.first # 3
say nums.last # 6
say nums.first(3) # [3, 1, 4]These are the methods you'll use most often with arrays:
map — transform every element:
var numbers = [1, 2, 3, 4, 5]
var squared = numbers.map { |n| (n ** 2) }
say squared # [1, 4, 9, 16, 25]
var names = ["alice", "bob", "carol"]
var uppered = names.map { .uc }
say uppered # ["ALICE", "BOB", "CAROL"]grep — keep only elements that match a condition:
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var evens = numbers.grep { .is_even }
var odds = numbers.grep { .is_odd }
var big = numbers.grep { |n| (n > 5) }
say evens # [2, 4, 6, 8, 10]
say odds # [1, 3, 5, 7, 9]
say big # [6, 7, 8, 9, 10]reduce — combine all elements into one value:
var numbers = [1, 2, 3, 4, 5]
var sum = numbers.reduce(0, { |acc, n| (acc + n) })
var product = numbers.reduce(1, { |acc, n| (acc * n) })
say sum # 15
say product # 120each — loop over every element:
["red", "green", "blue"].each { |color|
say "Color: #{color}"
}each_with_index — loop with both index and value:
["a", "b", "c"].each_with_index { |val, i|
say "#{i}: #{val}"
}
# 0: a
# 1: b
# 2: cvar words = ["Hello", "World", "from", "Sidef"]
say words.join(" ") # Hello World from Sidef
say words.join(", ") # Hello, World, from, Sidef
say words.join # HelloWorldfromSidef
# word arrays with %w notation (shorthand for array of strings)
var fruits = %w(apple banana cherry)
# same as: ["apple", "banana", "cherry"]var arr = [10, 20, 30, 40, 50]
say arr[1..3] # [20, 30, 40] (indices 1 to 3)
say arr[0..^3] # [10, 20, 30] (indices 0 to 2, exclusive end)
say arr[2..] # [30, 40, 50] (from index 2 to the end)var fruits = ["apple", "banana", "cherry"]
say fruits.contains("banana") # true
say fruits.contains("grape") # false
say fruits.index("cherry") # 2 (position of element)say (1..5).to_a # [1, 2, 3, 4, 5]
say (1..10).grep { .is_prime }.to_a # [2, 3, 5, 7]A hash stores key-value pairs. Keys are usually strings (or symbols), and values can be anything.
var person = Hash(
name => "Alice",
age => 30,
city => "London",
)say person{:name} # Alice
say person{:age} # 30
say person{:city} # Londonperson{:email} = "[email protected]" # add new key
person{:age} = 31 # update existing keysay person.has(:name) # true
say person.has(:phone) # falseperson.delete(:city)say person.keys # ["name", "age", "email"] (order may vary)
say person.values # ["Alice", 31, "[email protected]"]
say person.len # 3person.each { |key, value|
say "#{key}: #{value}"
}# Count word frequencies
var text = "the cat sat on the mat the cat"
var words = text.split(" ")
var freq = Hash()
words.each { |word|
freq{word} := 0 # set to 0 if not yet defined
freq{word}++
}
freq.keys.sort.each { |word|
say "#{word}: #{freq{word}}"
}
# cat: 2
# mat: 1
# on: 1
# sat: 1
# the: 3var s = "Hello, World!"
say s.uc # HELLO, WORLD! (uppercase)
say s.lc # hello, world! (lowercase)
say s.length # 13
say s.reverse # !dlroW ,olleH
say s.trim # removes leading/trailing whitespace
say s.contains("World") # true
say s.begins_with("Hello") # true
say s.ends_with("!") # true
say s.index("World") # 7 (position where it starts)var text = "I like cats and cats like me."
say text.sub("cats", "dogs") # I like dogs and cats like me. (first only)
say text.gsub("cats", "dogs") # I like dogs and dogs like me. (all)
say text.gsub(/cats?/, "animals") # with regex patternvar csv = "Alice,30,London"
var parts = csv.split(",")
say parts[0] # Alice
say parts[1] # 30
say parts[2] # London
say parts.join(" | ") # Alice | 30 | Londonvar s = "Hello, World!"
say s[0..4] # Hello
say s[7..11] # World
say s[0, 5] # Hello (start, length)Regular expressions let you match complex text patterns:
var email = "[email protected]"
if (email =~ /\w+@\w+\.\w+/) {
say "Valid email format."
}
# Capture parts of a match
var date = "2024-03-15"
var match = date.match(/(\d{4})-(\d{2})-(\d{2})/)
say "Year: #{match[0]}" # 2024
say "Month: #{match[1]}" # 03
say "Day: #{match[2]}" # 15say "42".to_i # converts string to integer: 42
say "3.14".to_r # converts string to number: 3.14
say 42.to_s # converts number to string: "42"
say 255.to_s(16) # convert to hex string: "ff"
say 255.to_s(2) # convert to binary string: "11111111"# Read the entire file as a string
var content = File("myfile.txt").read
say content
# Read line by line (memory efficient for large files)
File("myfile.txt").each_line { |line|
say line.trim
}
# Read all lines into an array
var lines = File("myfile.txt").lines
say "File has #{lines.len} lines."# Write (overwrites any existing content)
File("output.txt").write("Hello, File!\n")
# Append (adds to the end without erasing)
File("output.txt").append("Second line.\n")var f = File("data.txt")
if (f.exists) {
say "File found! Size: #{f.size} bytes."
var content = f.read
} else {
say "File not found."
}# Save a shopping list to a file and read it back
var list = ["apples", "bread", "milk", "eggs"]
File("shopping.txt").write(list.join("\n") + "\n")
say "Saved shopping list. Reading it back:"
File("shopping.txt").each_line { |line|
say "- #{line.trim}"
}Use try and catch to handle errors gracefully:
try {
var result = (10 / 0)
say result
}
catch { |error|
say "An error occurred: #{error}"
}func divide(a, b) {
die "Cannot divide by zero!" if (b == 0)
(a / b)
}
try {
say divide(10, 2) # 5
say divide(10, 0) # raises error
}
catch { |msg|
say "Error: #{msg}"
}var x = 5
assert(x > 0, "x must be positive")
assert_eq(x, 5, "x must be 5")
assert_ne(x, 0, "x must not be zero")If an assertion fails, the program stops with a clear message.
One of Sidef's greatest strengths is its built-in mathematical capabilities. Here's a brief preview — these work out of the box, no libraries needed.
say 17.is_prime # true
say 10.primes # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
say primes(100, 150) # all primes between 100 and 150
say 1000.prime # 7919 (the 1000th prime)
say prime_count(10**6) # 78498 (number of primes up to a million)say factor(360) # [2, 2, 2, 3, 3, 5]
say factor_exp(360) # [[2,3],[3,2],[5,1]] (prime, exponent pairs)
say divisors(36) # [1, 2, 3, 4, 6, 9, 12, 18, 36]
say euler_phi(36) # 12 (Euler's totient)say gcd(48, 18) # 6
say lcm(4, 6) # 12say (2 ** 1000) # a 302-digit number
say 100.factorial # a 158-digit number
say (10 ** 100) # a googolsay Num.pi # π ≈ 3.14159265358979...
say Num.e # e ≈ 2.71828182845904...
say sqrt(2) # √2 ≈ 1.41421356237309...
say sin(Num.pi / 2) # 1
say cos(0) # 1
say log(Num.e) # 1
say (2.718281828).log # ≈ 1 (natural log)say 255.to_s(2) # "11111111" (binary)
say 255.to_s(16) # "ff" (hexadecimal)
say 255.to_s(8) # "377" (octal)
say "ff".to_i(16) # 255 (hex string to integer)Work through these projects to practice what you've learned. They're ordered roughly from easiest to most challenging.
func celsius_to_fahrenheit(c) {
((c * 9/5) + 32)
}
func fahrenheit_to_celsius(f) {
((f - 32) * 5/9)
}
print "Enter temperature in Celsius: "
var c = read(Number)
say "#{c}°C = #{celsius_to_fahrenheit(c).round(2)}°F"
say "#{c}°C = #{(c + 273.15).round(2)} K"A classic exercise: for each number 1–100, print "Fizz" if divisible by 3, "Buzz" if by 5, "FizzBuzz" if by both, otherwise the number:
for i in (1..100) {
say (
((i % 15) == 0) ? "FizzBuzz" :
((i % 3) == 0) ? "Fizz" :
((i % 5) == 0) ? "Buzz" :
i
)
}func calculate(a, op, b) {
given (op) {
when ("+") { (a + b) }
when ("-") { (a - b) }
when ("*") { (a * b) }
when ("/") {
die "Cannot divide by zero!" if (b == 0)
(a / b)
}
else { die "Unknown operator: #{op}" }
}
}
print "First number: "
var a = read(Number)
print "Operator (+, -, *, /): "
var op = read(String)
print "Second number: "
var b = read(Number)
try {
say "Result: #{calculate(a, op, b)}"
}
catch { |msg|
say "Error: #{msg}"
}var secret = (1..100).rand # random number between 1 and 100
var guesses = 0
say "I'm thinking of a number between 1 and 100."
say "Can you guess it?"
loop {
print "Your guess: "
var guess = read(Number)
guesses++
if (guess < secret) {
say "Too low! Try higher."
} elsif (guess > secret) {
say "Too high! Try lower."
} else {
say "Correct! You got it in #{guesses} guess#{(guesses == 1 ? '' : 'es')}!"
break
}
}func stats(data) {
var n = data.len
var mean = (data.sum / n)
var sorted = data.sort
var median = (n.is_odd
? sorted[n / 2]
: ((sorted[(n/2) - 1] + sorted[n/2]) / 2)
)
var variance = (data.map { |x| ((x - mean)**2) }.sum / n)
var std_dev = variance.sqrt
Hash(
count => n,
sum => data.sum,
mean => mean.round(4),
median => median,
min => data.min,
max => data.max,
std_dev => std_dev.round(4),
)
}
var data = [4, 8, 15, 16, 23, 42]
var s = stats(data)
say "Count: #{s{:count}}"
say "Sum: #{s{:sum}}"
say "Mean: #{s{:mean}}"
say "Median: #{s{:median}}"
say "Min: #{s{:min}}"
say "Max: #{s{:max}}"
say "Std Dev: #{s{:std_dev}}"# Method 1: Simple recursive with caching
func fib(n) is cached {
return n if (n <= 1)
(fib((n - 1)) + fib((n - 2)))
}
say "First 15 Fibonacci numbers:"
say (0..14).map { |n| fib(n) }
# Method 2: Iterative
func fib_sequence(count) {
var result = [0, 1]
while (result.len < count) {
result.push((result[-1] + result[-2]))
}
result.first(count)
}
say fib_sequence(20)say "=== Prime Number Explorer ==="
say ""
# First 20 primes
say "First 20 primes:"
say 20.primes
say ""
# Check if numbers are prime
[2, 7, 13, 25, 97, 100, 101].each { |n|
var status = n.is_prime ? "prime" : "not prime"
say "#{n} is #{status}"
}
say ""
# Factorize some numbers
[12, 60, 100, 360, 2310].each { |n|
say "#{n} = #{factor(n).join(' × ')}"
}
say ""
# Twin primes (pairs that differ by 2)
say "Twin prime pairs up to 100:"
var prev = 2
primes(3, 100).each { |p|
say "(#{prev}, #{p})" if ((p - prev) == 2)
prev = p
}# Count and display word frequencies from a string
var text = <<'END'
To be or not to be that is the question
Whether tis nobler in the mind to suffer
The slings and arrows of outrageous fortune
Or to take arms against a sea of troubles
END
var words = text.lc.split(/\W+/).grep { .len > 0 }
var freq = Hash()
words.each { |w|
freq{w} := 0
freq{w}++
}
say "Word frequencies (sorted by count, descending):"
say "=" * 35
freq.keys
.sort_by { |k| -freq{k} }
.first(10)
.each { |word|
var count = freq{word}
var bar = "█" * count
say "#{ '%-12s' % word } #{bar} (#{count})"
}This draws a famous fractal pattern using simple string operations:
func sierpinski(n) {
var rows = ["*"]
n.times { |i|
var sp = (" " * (2**i))
rows = (rows.map { |r| (sp + r + sp) } +
rows.map { |r| (r + " " + r) })
}
rows.join("\n")
}
say sierpinski(4)You've covered the fundamentals! Here's where to go next.
| Resource | Description |
|---|---|
| 📘 Sidef GitBook | The complete language reference — covers everything |
| 📄 PDF Book | The full book in PDF format for offline reading |
| 📝 Advanced Tutorial | An advanced tutorial covering the full language |
| 🔢 Number Theory Tutorial | Deep dive into Sidef's mathematical superpowers |
| Resource | Description |
|---|---|
| 📂 sidef-scripts | Hundreds of real Sidef programs — the best way to learn by reading |
| 🌹 RosettaCode — Sidef | Classic programming tasks solved in Sidef, side-by-side with other languages |
| Resource | Description |
|---|---|
| 💬 GitHub Discussions | Ask questions, share ideas, get help |
| 🐛 GitHub Issues | Bug reports and feature requests |
| 📦 MetaCPAN | CPAN package page with additional documentation |
https://tio.run/#sidef — Run Sidef code instantly in your browser.
Once you're comfortable with the basics here, the natural next steps are:
- Object-oriented programming — classes, inheritance, methods
- Modules and namespaces — organizing larger programs
- Lazy evaluation — working with infinite sequences efficiently
- Number theory — Sidef's extraordinary built-in math functions
- Perl module integration — using any CPAN library from Sidef
All of these are covered in detail in the Sidef Advanced Guide and the official book.
You're ready to start coding! Happy hacking with Sidef. 🚀
Start with small programs, experiment freely in the REPL, and don't be afraid to break things — that's how you learn.