You can swipe heading to copy link or swipe codeblock to copy its contents.

What's new

Amber 0.6.0 brings exciting new features, improved developer experience, multi-shell support, and important additions to the standard library. Let's delve into what's new.

Multi-shell support (Zsh, Ksh, Bash 3.2)

Amber now supports compiling not just to modern Bash, but also directly to Zsh, Ksh, and Bash 3.2 via the new --target argument! Now you can deploy Amber scripts in a broader range of UNIX environments.

amber my_script.ab --target zsh

Amber generated scripts now emit the correct shebang for the selected target. Range-related generated code no longer depends on external bc / sed in the same way, greatly improving portability, especially on macOS (where Bash 3.2 is default). You can also now use the new shellname() and shellversion() builtins for runtime shell introspection.

echo ( "Running on { shellname ()} version { shellversion ()} " )

Public ( pub ) variables

You can now declare variables as pub to expose them across modules, simplifying data sharing across your multi-file Amber projects.

pub const my_global = "value"

Please note that exposing mutable variables ( pub let ) is also supported but requires explicit opt-in using the #[allow_public_mutable] attribute at declaration.

Recursive Functions

Amber now supports recursive function calls, giving you more flexibility for implementing algorithms.

fun factorial ( n : Int ): Int { if n < = 1 { return 1 } return n * factorial ( n - 1 ) } echo ( " { factorial ( 4 )} " )

Ternary Control-Flow Validation

Added control-flow-aware validation for ternary expressions and related typing, making your inline conditional assignments much safer and smarter.

let result = value is Num then 42 else "Hello World"

Union Types

Union types provide a flexible way to define function parameters that can accept values of multiple distinct types.

fun print_value ( val : Int | Text | Bool ) { echo ( val ) } print_value ( 42 ) print_value ( "Amber" ) print_value ( true )

Testing suite

Amber now features a built-in testing suite. It allows you to write dedicated test blocks that are only executed when running the amber test command.

We also introduced a new std/test library.

test "can multiply numbers" { let result = 10 * 2 }

You can also name your tests for better readability and filter them by name or filename using CLI arguments. Read more in the Testing Guide.

Improved variable diagnostics

The compiler now surfaces clearer warnings when variables are not used, helping you catch mistakes earlier. It also warns when a variable declared with let is never modified, encouraging the use of const for bindings that never need reassignment. All same-scope redeclarations of symbols are now completely rejected, enforcing better coding practices.

let unused = 1 let count = 3 echo ( count )

Enhanced CLI and Failable diagnostics

Improved handling and messaging for unknown CLI commands, including typo suggestions to quickly help you fix your command. It also brings improved errors when external commands do not exist.

Rules around failable functions are also now strictly validated:

Failable functions must use ? syntax.

syntax. Infallible functions must not use ? .

. Invalid combinations of trust and ? are clearly diagnosed.

fun no_fail (): Int ? { return 1 } fun might_fail () { fail 1 } fun will_fail (): Int ? { fail 1 }

Improved runtime safety

A runtime error is now raised correctly if you attempt out-of-bounds indexing on arrays, including source location.

let items = [ "apple" , "banana" ] echo ( items [ 5 ])

New builtins and syntax reform

All builtins like echo have moved toward function-call syntax with parentheses, older no-parentheses builtin calls are still supported in relevant cases, but now emit deprecation warnings:

echo ( "Hello world" ) cd ( "newdir" ) mv ( "file.ab" , "newdir" ) exit ( 1 ) echo "Hello world"

Amber has gained many new builtins for common shell operations. These builtins generate valid, shellcheck-compatible Bash code and integrate with Amber's error handling system.

Creates an empty file or updates the modification timestamp of an existing file. Accepts a single file path. This is a failable builtin - use failed blocks or trust to handle

touch ( "newfile.txt" ) ?

rm - Remove files or directories

Removes files or directories from the filesystem. This is a failable builtin - use failed blocks or trust to handle errors.

rm ( "oldfile.txt" ) ? rm ( "/tmp/olddir" , true ) ?

sleep - Pause execution

Pauses script execution for the specified number of seconds. Supports decimal values for sub-second delays. Sleep value needs to be equal or greater than 0. This is a failable builtin - use failed blocks or trust to handle

sleep ( 5 ) sleep ( 0.5 )

ls - List directory contents

Returns an array of filenames in the specified directory. Accepts optional all and recursive boolean parameters. This is a failable expression that returns [Text] .

let files = trust ls ( "/tmp" ) let with_hidden_files = trust ls ( "/tmp" , true , false ) let with_files_in_subdir = trust ls ( "/tmp" , false , true ) let every_file = trust ls ( "/tmp" , true , true )

pwd - Print working directory

Returns the current working directory as a Text value.

const dir = pwd () echo ( "Current directory: { dir } " )

clear - Clear the terminal

Clears the terminal screen. Takes no parameters.

clear ()

cp - Copy files or directories

Copies files or directories from one location to another. This is a failable builtin.

cp ( "source.txt" , "backup.txt" ) ? cp ( "src_dir" , "dest_dir" , true ) ?

pid - Get process ID

Returns the PID (Process ID) of the last background job. Useful for process management.

let last_pid = pid () echo ( "Last process: { last_pid } " )

disown - Remove background jobs

Removes a job from the shell's active job table, allowing the script to continue without waiting for it. Accepts optional job pids to disown specific background jobs.

disown () disown ( pid ) disown ([ pid1 , pid2 ])

lock - File locking

Creates an exclusive lock on a file, useful for coordinating access between processes.

lock ( "/tmp/myapp.lock" ) ?

await - Wait for background processes

Waits for background processes to complete. It takes as an argument a pid or an array of pids. Requires failure handler.

trust $ sleep 2 & $ await ( pid ()) ?

shellname - Get shell name

Returns the name of the current shell as a Text value.

let current_shell = shellname () echo ( "Running in: { current_shell } " )

shellversion - Get shell version

Returns the version of the current shell as a [Int] value.

let version = shellversion () echo ( "Shell version: { version } " )

Array Type Resolution

Amber now supports type inference for empty arrays [] . You can initialize an empty array without specifying its type immediately. The type will be resolved later based on how the array is used, such as in assignments, binary operations, or function calls.

let arr = [] arr + = [ 1 ]

Array destructing

You can now destruct arrays into separate variables for both declarations and assignments:

let arr = [ 1 , 2 , 3 ] let [ key1 , key2 , key3 ] = arr echo ( " { key1 } { key2 } { key3 } " ) [ key1 , key2 , key3 ] = [ 4 , 5 , 6 ]

Comments are now accepted in more places where you naturally write them, improving code readability:

Inside array literals let config = [ "value1" , "value2" , ]

Inside import lists import { func1 , func2 , } from "utils.ab"

Between function parameters fun complex ( a : Int , b : Text , ): Text { .. . }

Between function arguments some_func ( arg1 , arg2 , )

Inside if chains if condition1 { } else if condition2 { } else { }

Standard library improvements

This release includes numerous improvements to the Standard Library such as cpad , file_compress , shopt_enable / shopt_disable , and array sorting functions ( sort() , sorted() ).

Other major additions include:

Filesystem helpers: file_glob() and file_glob_all() .

and . Environment and system helpers: env_const_set() , env_var_set() , uname_*() variants, mount() , umount() , and umount_force() .

, , variants, , , and . Process management: pgrep() , pgrep_exact() , pkill() , pkill_exact() , pkill_force() , and kill() .

, , , , , and . Text/output helpers: printf() , styled() , echo_colored() , count_lines() , count_words() , count_chars() , sort_lines() , and uniq_lines() .

import * from "std/env" import * from "std/fs" let files = file_glob_all ( "**/*.ab" ) env_var_set ( "DEBUG" , "1" )

New std/test module

We introduced a new std/test library that provides assert and assert_eq functions to help you write tests.

import { assert , assert_eq } from "std/test" test "can multiply numbers" { let result = 10 * 2 assert ( result = = 20 ) assert_eq ( result , 20 ) }

New fetch function for HTTP requests

The fetch function provides a functionality for making HTTP requests. It intelligently utilizes available command-line tools for network operations, with a failover to bash's network sockets. This function supports a comprehensive set of HTTP methods, including GET , POST , PUT , and DELETE .

import { fetch } from "std/http" let response = trust fetch ( "https://example.com" ) let post_request = trust fetch ( "https://example.com" , "POST" , "hello world!" , [ "content-type: text/plain" ])

Performance improvements

The Amber standard library has been optimized for better performance in the generated Bash code. Many functions now use more efficient shell constructs and avoid unnecessary subprocess spawning. Combined with the math improvements below, Amber scripts now run significantly faster, especially in loops and data processing tasks.

Math improvements

Integer arithmetic operations in Amber-generated Bash code now use native Bash arithmetic, eliminating bc and sed dependencies for whole number calculations. Floating-point arithmetic and certain text operations still depend on bc and sed, respectively.

Docs and Distribution

Amber now officially offers Debian and RPM packaging for our releases. In addition, we have improved the documentation generation around shell function declarations and more reliably preserve indentation in doc code blocks!

Internal improvements

These changes improve Amber's development workflow, code quality, and internal tooling:

Testing and code coverage

The Amber codebase now has more tests and code coverage reporting via Codecov. This helps ensure stability and catch regressions early in the development process.

CI improvements

The continuous integration pipeline has been improved with:

Nightly builds - automated builds published every night for early testing

Shellcheck validation - all generated Bash code is validated against shellcheck

Fixed action versions - GitHub Actions use pinned versions for reproducibility

rustfmt - Rust code is automatically formatted

Removed shfmt

The shfmt tool has been removed as a processing tool in the Amber build pipeline, simplifying the build process and reducing external dependencies.

Improved shellcheck error messages

Shellcheck error messages are now clearer and more helpful when the compiler encounters issues with generated Bash code.

Amber scripts in the codebase

More Amber scripts are now used internally in the project (see scripts/), demonstrating Amber's capabilities and dogfooding the language in its own development.

License change

Amber has switched its license from GPLv3 to LGPL (GNU Lesser General Public License). Here's what this means in practice:

GPLv3 required that any project distributing Amber-compiled code would also need to be licensed under GPLv3 - a "viral" copyleft license that applies to derivative works.

LGPL is more permissive: you can freely use Amber and its compiled scripts in proprietary or closed-source projects. The LGPL only applies to modifications of Amber itself, not to the scripts you write and compile with it.

This change makes Amber suitable for a wider range of use cases, including commercial and enterprise environments where GPL licensing may be a concern.

Breaking Changes / Migration Notes

Amber 0.6.0 introduces several important breaking changes to improve correctness and safety: