fb new hello; fb run hello
Write it like BASIC. Ship it like C.
FutureBlitz is a compiled, general-purpose language with BASIC's readability, native speed, and a standard library for real programs.
stock.fb
Import std.core
Struct Item
Field name: String
Field count: Int
End Struct
Local stock = [Item("apples", 12), Item("pears", 0),
Item("plums", 7)]
For item In stock
Local left = item.count > 0 ? "{item.count} left" : "sold out"
Print("{item.name}: {left}")
End For
$ fb run stock.fb
apples: 12 left
pears: sold out
plums: 7 left What you get
Readable code, compiled to machine code
-
Native executables
fb compiles each program to machine code through LLVM and links it into one executable, with nothing to install beside it.
fb build --release -
Memory safety, no pauses
Reference counting frees each value when the last reference to it goes, so there's no garbage collector to pause the program.
Field parent: Weak<Node> -
Null safety
A value that can be missing has a type that says so, and the compiler checks it before the program can use it.
name?.Length ?? 0 -
Concurrency built in
Async and Await, Spawn, and Parallel For are part of the language, and the compiler stops data races between threads.
Spawn · Parallel For · Await -
C libraries without glue
Declare a C library's functions in an Extern block and call them like your own, or have fb bindgen write the block from its header.
Extern "C" Lib "sqlite3" -
One tool
fb builds, runs, tests, formats, and documents programs, and adds and publishes packages.
fb test · fb fmt · fb add
Code
Whole programs, with what they print
Each program here is complete. The site's build ran each one with fb and recorded its output.
A command-line tool @Program, Args, and File
Import std.core
Import std.io
Import std.os
Import std.text
@Program(Name: "count", About: "Counts the lines and words in files.")
Struct Options
@Positional(Help: "The files to read", Name: "file")
Field Files: String[]
End Struct
Local options = Args.Parse<Options>()
For path In options.Files
Try
Local text = Try File.ReadText(path)
Print("{text.SplitLines().Count:>4} lines {text.SplitWhitespace().Count:>5} words {path}")
Catch e As IOError
PrintError("count: can't read {path}: {e.Kind}")
End Try
End For
3 lines 16 words poem.txt count: can't read missing.txt: NOT_FOUND
An HTTP service HttpServer's routes and HttpClient
Import std.core
Import std.net
Import std.net.http
Struct Greeting
Field Name: String = "world"
End Struct
Class Api
@Get("/hello")
Async Method Hello(args: Greeting): HttpResponse
Return HttpResponse.Of(Body.Text("Hello, {args.Name}!"))
End Method
End Class
Local server = HttpServer()
server.Routes(Api())
Try
server.Listen(SocketAddress(IpAddress.Loopback, 0))
Local serving = server.Serve()
Local client = HttpClient()
Local base = "http://127.0.0.1:{server.LocalAddress.Port}"
For path In ["/hello", "/hello?name=Ada", "/goodbye"]
Local response = Await client.GetAsync(base + path)
Print("GET {path}: {response.Status} {response.Text}")
End For
server.Stop()
Await serving
Catch e As Error
PrintError("failed: {e.Message}")
End Try
GET /hello: 200 Hello, world! GET /hello?name=Ada: 200 Hello, Ada! GET /goodbye: 404
Concurrency Spawn, Parallel For, and Channel
Import std.core
Import std.collections
Function CountPrimes(from: Int, below: Int): Int
Local count = 0
For n = Max(from, 2) Until below
Local d = 2
While d * d <= n && n % d != 0
d += 1
End While
If d * d > n Then count += 1
End For
Return count
End Function
// Four tasks on the worker pool, each counting a quarter of the numbers.
Local tasks: Task<Int>[] = []
For part = 0 Until 4
tasks.Add(Spawn(Function() => CountPrimes(part * 50_000, (part + 1) * 50_000)))
End For
Local total = 0
For task In tasks
total += task.Wait()
End For
Print("primes below 200,000: {total}")
// Parallel For splits a loop over the cores; each pass writes only its own element.
Local squares: Int[] = []
squares.Resize(8, 0)
Parallel For i = 0 Until squares.Count
squares[i] = i * i
End For
Print(squares)
// A Channel carries values from one thread to another, in order.
Const results = Channel<String>(4)
Spawn(Function()
For n = 1 To 3
results.Send("job {n} done")
End For
results.Close()
End Function)
For message In results
Print(message)
End For
primes below 200,000: 17984 [0, 1, 4, 9, 16, 25, 36, 49] job 1 done job 2 done job 3 done
Generics and interfaces Interface, Class, and a constraint
Import std.core
Import std.math
// An Interface names what a type promises; each Class that implements it keeps the promise.
Interface Shape
Method Area(): Float
ReadOnly Property Name: String
End Interface
Class Circle Implements Shape
Field radius: Float
New(radius: Float)
Self.radius = radius
End New
Method Area(): Float => Pi * radius * radius
Property Name: String
Get => "circle"
End Property
End Class
Class Rect Implements Shape
Field width: Float
Field height: Float
New(width: Float, height: Float)
Self.width = width
Self.height = height
End New
Method Area(): Float => width * height
Property Name: String
Get => "rect"
End Property
End Class
// A generic Function works for every type its constraint allows, compiled for each one.
Function Largest<T: Comparable>(items: T[]): T
Local best = items[0]
For item In items
If item > best Then best = item
End For
Return best
End Function
Local shapes: Shape[] = [Circle(1), Rect(2, 3)]
For shape In shapes
Print("{shape.Name}: {shape.Area():.2}")
End For
Print(Largest([3, 9, 4]))
Print(Largest(["pear", "apple", "plum"]))
circle: 3.14 rect: 6.00 9 plum
Calling a C library Extern and @CLayout
Import std.core
// A C struct, laid out as C lays it out, so it passes to and from C by value.
@CLayout Struct DivResult
Field quot: Int32
Field rem: Int32
End Struct
// C's own functions, declared once and called like any other Function. A library of your own
// is named with Lib, and project.toml's [native] says where it is.
Extern "C"
Function abs(n: Int32): Int32
Function strlen(text: CString): UInt64
Function div(numerator: Int32, denominator: Int32): DivResult
End Extern
Print(abs(-42))
Print(strlen("FutureBlitz"))
Local result = div(17, 5)
Print("17 / 5 is {result.quot} remainder {result.rem}")
42 11 17 / 5 is 3 remainder 2
A test @Test, Expect, and fb test
Import std.core
Import std.test
Public Class OutOfStock Extends Error
End Class
/// The price of `count` items at `each`, with one free for every ten.
Public Function Price(count: Int, each: Int): Int
Return (count - count / 10) * each
End Function
/// Takes `count` from `stock`, or throws when there aren't that many.
Public Function Take(stock: Int, count: Int): Int Throws OutOfStock
If count > stock Then Throw OutOfStock("only {stock} left")
Return stock - count
End Function
@Test
Function TenthItemIsFree()
Expect(Price(9, 5) == 45)
Expect(Price(10, 5) == 45)
Expect(Price(20, 5) == 90)
End Function
@Test
Function TakingTooManyThrows() Throws OutOfStock
Expect(Try Take(5, 2) == 3)
Local error = ExpectThrows<OutOfStock>(Take(1, 2))
Expect(error?.Message == "only 1 left")
End Function
Running 2 tests test prices.prices.TakingTooManyThrows ... ok test prices.prices.TenthItemIsFree ... ok test result: ok. 2 passed; 0 failed; 0 skipped; 0 filtered out; finished in 0.02s
The standard library
206 modules, written in FutureBlitz
- Core 19 modules Print and Input, errors, iterators, formatting and parsing, events, logging, and tests.
- Collections 27 modules Map, Set, Stack, Queue, Deque, PriorityQueue, caches, and graph and grid algorithms.
- Text 14 modules Unicode, regular expressions, Markdown, templates, diffs, fuzzy matching, and encodings.
- Data formats 13 modules JSON, MessagePack, TOML, CSV, INI, XML, YAML, Protocol Buffers, and SQLite databases.
- Files and streams 15 modules Paths, files, folders, streams, memory-mapped files, a virtual file system, and file watching.
- Networking and HTTP 27 modules Addresses, DNS, TCP and UDP, TLS, an HTTP client and server, WebSockets, and ACME.
- Concurrency 8 modules Locks, concurrent maps and queues, lazy values, parallel algorithms, and cancellation.
- Math 22 modules Vectors, matrices, colors, geometry, random numbers, noise, statistics, units, and big numbers.
- Time 7 modules Durations, timestamps, dates and times of day, calendars, timers, and time zones.
- Crypto and compression 21 modules Hashes, ciphers, signatures, password hashing, UUIDs, and Deflate, Zstd, Zip, and tar.
- Images and the terminal 21 modules PNG, JPEG, GIF, WebP, and SVG images, drawing and fonts, and terminal styles, input, and widgets.
- OS and processes 12 modules Command-line arguments, the environment, standard folders, processes, signals, and C data.
Tools
One command for the whole job
fb new shop # a package: project.toml and main.fb
fb run # build it and run it
fb build --release # an optimized executable
fb test # every @Test, in parallel
fb fmt # format every file
fb doc # the package's API as JSON
fb add colors # a dependency from the registry
fb publish # the package, to the registry
VS Code
The FutureBlitz extension shows errors as you type, formats on save, completes names, and debugs with breakpoints, through fb's language server.
Install
Install it, then fb new
Windows
winget install FutureBlitz.FutureBlitz
winget installs fb for you alone, with its bin on your PATH.
macOS
brew install hlpdev/tap/futureblitz
Homebrew installs fb and keeps it up to date with the rest of your tools.
Linux
curl -fsSL https://futureblitz.dev/install.sh | sh
The script installs fb in ~/.futureblitz and puts its bin on your PATH.
fb new hello
cd hello
fb run
Hello, world!
Other ways to install, with updating, uninstalling, and checksums.