Back to flin
flin

409 Built-in Functions: The Complete Standard Library

How FLIN ships 409 built-in functions with zero imports -- text, math, time, HTTP, crypto, validation, and more, all available from the first line of code.

Thales & Claude | March 25, 2026 13 min flin
flinstdlibfunctionsbuiltin

Most programming languages ship with a bare skeleton and tell you to install packages for everything else. Need to format a date? npm install moment. Need to hash a password? pip install bcrypt. Need to validate an email? Google "regex email validation" and pray.

FLIN takes the opposite approach. Every function you need for building a real web application is built into the language itself. No imports. No package manager. No dependency tree. Four hundred and nine functions, available from the first line of every program.

This is the story of how we designed, categorized, and implemented a standard library large enough to replace dozens of third-party packages -- and why that decision defines everything FLIN stands for.

The Philosophy: Everything You Need, Nothing You Do Not

When Thales and I sat down to define FLIN's standard library, we started with a question that most language designers never ask: what does a developer building a real web application actually need?

Not a toy. Not a script that prints "Hello, World!" and exits. A real application with user authentication, form validation, data transformation, HTTP requests, date formatting, and string manipulation. The kind of application that, in JavaScript, requires 400 packages in node_modules before you write your first line of business logic.

We catalogued every function call in three real-world projects -- an e-commerce platform, a SaaS dashboard, and a content management system. Then we asked: which of these functions should be built-in?

The answer was almost all of them.

// In JavaScript, this requires 3 packages:
// - moment (date formatting)
// - validator (email check)
// - lodash (string manipulation)

// In FLIN, it requires zero: name = " juste gnimavo ".trim.title email = "[email protected]" valid = email.is_email joined = now.format("MMMM D, YYYY")

print("{name} ({email}) - Valid: {valid} - Joined: {joined}") // "Juste Gnimavo ([email protected]) - Valid: true - Joined: March 26, 2026" ```

Four functions. Four different categories (text, validation, time, output). Zero imports.

The Numbers: 409 Functions Across 11 Categories

The complete standard library breaks down as follows:

CategoryFunctionsExamples
Text31upper, trim, split, replace, pad_start
Number28abs, round, sqrt, random, clamp
List34map, where, reduce, sort, group_by
Map16keys, values, merge, filter, invert
Time26now, format, is_before, start_of_month
File14read_file, write_file, file_exists
JSON3parse_json, to_json
HTTP5http_get, http_post, http_put, http_delete
Security18hash_password, verify_password, jwt_sign
Validation42is_email, is_url, is_numeric, sanitize_html
Utility22type_of, clone, env, print, assert
Math (advanced)48sin, cos, mean, median, std_dev
Introspection15fields_of, type_name, has_field
HOF12map, filter, reduce, flat_map, zip_with
Error/Debug18log_info, log_error, timer_start, measure
Geometry24distance, area_circle, rotate_point
Performance8track_error, measure_latency, memory_usage
Sanitization25sanitize_html, escape_sql, strip_tags
Total409

Every single one is available without an import statement. Every single one handles none values gracefully instead of crashing. Every single one follows the same naming convention: lowercase, underscores for multi-word names, method-style calls on values.

The Calling Convention: Methods and Functions

One of the earliest design decisions was supporting two calling styles for every function. You can call a function on a value using method syntax, or you can call it as a standalone function with the value as the first argument:

// Method style (preferred for readability)
name = "hello world"
result = name.upper
length = name.len
words = name.split(" ")

// Function style (same result) result = upper(name) length = len(name) words = split(name, " ") ```

Both styles compile to the same bytecode. The method style exists because it reads naturally -- name.upper flows better than upper(name) -- and because it enables chaining:

result = " Hello, World! "
    .trim
    .lower
    .replace(" ", "_")
    .slice(0, 20)
// "hello,_world!"

This chain compiles to a sequence of opcodes that operate on the stack without any intermediate allocations for the pipeline itself. The method syntax is not syntactic sugar over function calls -- it is a first-class feature of the bytecode emitter.

Null Safety: The Foundation

Every built-in function handles none gracefully. This is not optional. It is not a convention. It is enforced at the VM level.

name: text? = none
result = name.upper        // Returns none (does not crash)
length = name.len          // Returns none
contains = name.contains("x")  // Returns none

// Safe chaining formatted = user.name?.trim.title // If user.name is none, the entire chain returns none ```

In JavaScript, null.toUpperCase() throws a TypeError. In Python, None.upper() throws an AttributeError. In FLIN, calling any method on none returns none. Period. No exceptions. No special handling required.

This decision alone eliminates an entire class of runtime errors that plague every web application. The infamous "Cannot read properties of null" is the single most common JavaScript error in production. In FLIN, it does not exist.

Category Deep Dive: Text Functions

Text manipulation is the most heavily used category in any web application. FLIN ships 31 string methods, covering everything from basic operations to validation to encoding.

The text functions are organized into logical groups:

Basic operations -- the functions you call dozens of times per file:

text.len                   // Length in characters (not bytes)
text.upper                 // "hello" -> "HELLO"
text.lower                 // "HELLO" -> "hello"
text.trim                  // " hello " -> "hello"
text.trim_start            // " hello" -> "hello"
text.trim_end              // "hello " -> "hello"

Case transformations -- essential for generating slugs, CSS classes, and variable names:

text.capitalize            // "hello world" -> "Hello world"
text.title                 // "hello world" -> "Hello World"
text.snake_case            // "helloWorld" -> "hello_world"
text.camel_case            // "hello_world" -> "helloWorld"
text.pascal_case           // "hello_world" -> "HelloWorld"
text.kebab_case            // "hello_world" -> "hello-world"

Validation -- because checking input is something every application does:

text.is_empty              // true if ""
text.is_blank              // true if only whitespace
text.is_numeric            // true if all digits
text.is_alpha              // true if all letters
text.is_email              // Basic email validation
text.is_url                // Basic URL validation

These validation methods are not regular expressions that developers copy from Stack Overflow. They are compiled Rust functions that run at native speed. is_email does not just check for an @ sign -- it validates the structure according to RFC 5322 (with the pragmatic simplifications that every real email validator uses).

Category Deep Dive: List Functions

Lists are the second most used data structure in web applications (after strings). FLIN's list functions are designed for method chaining, enabling a functional programming style without the ceremony:

// Find the top 5 active users by score
top_users = users
    .where(u => u.is_active)
    .sort_by(u => u.score)
    .reverse
    .take(5)
    .map(u => u.name)

This reads like English. Filter active users. Sort by score. Reverse (highest first). Take five. Extract names. Each method returns a new list, so the chain is immutable -- the original users list is never modified.

The aggregation functions handle common mathematical operations:

numbers = [10, 20, 30, 40, 50]
numbers.sum                // 150
numbers.average            // 30.0
numbers.min                // 10
numbers.max                // 50
numbers.product            // 12000000

// Predicate counting active = users.count(u => u.is_active) ```

Category Deep Dive: Time Functions

Time handling is notoriously difficult. JavaScript's Date object is widely regarded as one of the worst APIs in the language. Python's datetime module requires importing three different classes. FLIN makes time simple.

// Current time
right_now = now
today_start = today
yesterday_start = yesterday

// Time components right_now.year // 2026 right_now.month // 3 right_now.day_of_week // 3 (Wednesday) right_now.is_weekend // false

// Time arithmetic with natural syntax next_week = now + 7.days two_hours_ago = now - 2.hours deadline = today + 3.months

// Formatting right_now.format("YYYY-MM-DD") // "2026-03-26" right_now.format("MMMM D, YYYY") // "March 26, 2026" right_now.from_now // "just now" ```

The duration constructors -- 7.days, 2.hours, 3.months -- are built into the number type. This is not method chaining on numbers; these are genuine duration literals that the type system understands. You cannot add 7.days to a string. You cannot subtract 2.hours from a boolean. The compiler catches these mistakes before the code runs.

Category Deep Dive: HTTP Client

Building web applications means making HTTP requests. In most languages, this requires a third-party library. In JavaScript, the built-in fetch API took years to standardize and still requires polyfills in some environments. In Python, you need requests or httpx.

FLIN includes an HTTP client as a built-in:

// GET request
response = http_get("https://api.example.com/users")

// POST with body and headers response = http_post("https://api.example.com/users", { body: { name: "Juste", email: "[email protected]" }, headers: { "Authorization": "Bearer {token}" }, timeout: 30.seconds, retry: 3 })

// Response handling {if response.ok} users = response.json print("Got {users.len} users") {else} print("Error: {response.status}") {/if} ```

The HTTP client supports GET, POST, PUT, PATCH, and DELETE. It handles JSON serialization automatically (if the body is a map or entity, it serializes to JSON and sets the Content-Type header). It supports timeouts, retries, and custom headers. All built-in. All zero-import.

Why Not a Package Manager?

The obvious question: why build 409 functions into the language instead of shipping a package manager and letting the community create libraries?

Three reasons.

First, dependency hell is real. The average JavaScript project has 1,200 transitive dependencies. The average Python project has 40. Every dependency is a potential security vulnerability, a potential breaking change, and a potential licensing issue. When we built Deblo.ai, the backend's requirements.txt had 89 entries. The frontend's node_modules contained 1,847 packages. For an educational platform. FLIN eliminates this entirely.

Second, consistency matters. When every developer uses the same is_email function, every FLIN application validates emails the same way. When every developer uses the same format function for dates, every application formats dates consistently. There is no debate about which validation library to use. There is no blog post titled "Top 10 Date Libraries for FLIN." There is one way to do it, and it works.

Third, FLIN targets developers who do not want to manage infrastructure. The same developer who writes

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles