Idio Functions

This is not a comprehensive list but rather a flavour.

Some functions are closely tied to certain value types and others are a bit more generic.

Values

Constants

We can test for some kinds of constants with boolean?, null?, void?, eof-object?.

Numbers

Numbers are implemented as either fixnums or bignums. Fixnums are fairly lightweight, bignums less so.

Test generically with number? and integer? and more specifically with fixnum? and bignum?.

Use read-number to turn a string into a number.

Basic arithmetic with +, -, * and /.

Arithmetic comparisons with lt, le, eq, ne, ge and gt.

All of the above four arithmetic and five comparison functions have binary infix operators such that x op y becomes binary-op x y with corresponding functions binary-+, etc..

Further arithmetic with abs, quotient, expt (x to the power y), sqrt and exp (Euler’s number to the power x) with the complementary log (natural logarithm).

Trig with cos, sin, tan and atan, acos and asin.

For bignums you can test for real? (not an integer!) and exactness with exact? and inexact?. You can extract the mantissa and exponent.

Unicode

Test with unicode? and compare with unicode=?.

If your module has imported the unicode module (the default Idio module does) then you’ll have a few more useful Unicode Category and Property predicates available: Alphabetic?, Decimal_Number?, Lowercase?, Uppercase?, Titlecase_Letter?, Punctuation?, Symbol?, White_Space? and so on.

There are a couple of transformer functions: , ->Uppercase, ->Lowercase, ->Titlecase.

Strings

Test with string? and pathname?.

The number of code points in the string is given by string-length and you can get individual code points with string-ref.

You can change a code point with string-set! or all of them with string-fill! but you can’t put a “wider” code point into a “narrower” string.

Use append-string (or concatenate-string) to join strings (or a list of strings) together and join-string to use a delimiter.

Get the index of a code point with string-index or string-rindex.

You can explicitly get a substring of another with substring noting that the second index is up to but not including – for example, the string up to where string-index said some code point was.

Split strings up with fields (using IFS) or split-string (using IFS by default) or split-string-exactly which is more exacting than the traditional shell “splitting on whitespace”, say.

You can do some string comparisons though it is worth noting that, for consistency, these rather inefficiently convert the string into UTF-8 and then call either strncmp(3) or strncasecmp(3) (as appropriate). See string<?, string<=?, string=?, string>=?, string>? and their case-insensitive variants string-ci<?, etc..

Symbols and Keywords

You can test with symbol? and keyword?.

Handles

Test a handle with handle?, input-handle?, output-handle?, eof? and closed-handle?, the result of close-handle.

Handle attributes include handle-line, handle-pos and handle-name.

Access the contents with read-line, read-lines and read-char.

Output can be broadly two flavours: the printed representation of an object, something the reader might read back in; and a display representation, something the user might want to experience. This broadly only affects strings and characters:

printed

displayed

"hello\tworld"

hello   world

#U+0127

ħ

Writing to (output!) handles has some basic methods:

  • for printing, write any value and puts a string, in particular

  • for displaying, display and edisplay to the current error handle

For general formatted Printing, hprintf (handle-printf) is the function underlying printf, eprintf to the current error handle and sprintf to get a string.

You can change the position of a handle, like a file position, with seek-handle and rewind-handle.

File Handles

Test a file handle with file-handle?, input-file-handle? and output-file-handle?.

Create a file handle with open-input-file and open-output-file or the more general open-file which accepts an fopen(3)-style mode string.

Get the underlying file descriptor with file-handle-fd.

String Handles

Test a string handle with string-handle?, input-string-handle? and output-string-handle?.

Create a string handle with open-input-string and open-output-string.

Get the accumulated string from an output string handle with get-output-string.

General Functions

Conditional Expressions

The canonical conditional expression is if with cond being the if .. elif .. elif .. else .. variant. cond has an extremely powerful => operator implementing an anaphoric if.

if breaks a few conventions in that it doesn’t use then or else, it is simply:

if condition consequent alternative.

If either of consequent or alternative are simple values then, together with the one line per expression, it can look awkward.

Here, the consequent, #n, feels lost in front of the opening brace of the alternative.

if (pair? a) #n {
  eprintf "not a pair!\n"
}

Not great.

when is syntactic sugar for if where there is no alternate clause. It might scan better for maintainers.

Use not to invert the boolean result with unless implicitly doing it for you.

Selecting between known cases (think: explicit values) is done with case. regex-case and pattern-case, in particular, offer something closer to the shell’s case statement.

Looping Expressions

The do expression loops over a body of code, initialising then incrementing some loop variables in a near identical fashion for C’s for (init; test; step) body statement.

The only meaningful difference is that in addition to the test for end of loop you can specify some code to determine the value to return from do. Remember, everything returns a value.

Iteration Over Collections

You can either map over a list, array or keys of a hash table or loop with for-each depending on whether you want to collect the results of each iteration.

You can iterate over lists with fold-left and fold-right.

Equality

Things can be:

  • eq? – the same in memory (at least, indistinguishable)

  • eqv? – the same value (numbers and strings)

  • equal? – the same collections of values (lists, arrays and hash tables)

(File) Predicates

You can ask the usual file predicate questions with f?, d?, l? etc. with r?, w? and x? available.

Printing

Through printf etc. you can control how values are printed. Primarily numbers with the usual %d/%x variants. Fixnums and some integer C types can use a %b binary output format.

If you define a structure you can control how it is printed.

Most of the libc structures are similarly controlled – albeit, changing that format requires a recompile!

Sorting

Sorting revolves around the sort function which takes an optional accessor argument which allows indirect sorting.

Hence there are sort-mtime, sort-size etc. functions which take a list of filenames and sort them by some stat(2) attribute.

Loading Code

loading is based on the load function.

load will always run through the file it loads. You can effect a load-once system with a combination of require’ing a file which provide’s some feature.

You can import a module of code – which uses the require/provide mechanism as an aside – and updates the set of names you can use in your code.

Matching

Use regex-case and the simplified pattern-case for POSIX regex pattern matching.

The underlying standard library regcomp and regexec functions are available for more direct use.

Path Manipulation

It’s not quite as easy to manipulate PATHs in Idio as in the shell but there is a port of some Bash functions to manipulate PATHs that might be quite useful.

Only append /usr/local/bin if it is a directory:

path-append 'PATH "/usr/local/bin" :test d?

d?, here, is the file predicate d? and is just a regular function meaning you can write your own with more bespoke considerations.

Globbing

File name globbing can’t work in Idio in the same way it works in a shell because Idio allows (most of) the globbing meta-characters (*, ?, [) to be valid code points in symbols/variable names.

You can workaround this if you quote the glob expression (or at least ensure that it is a symbol – periods in filenames, .’s, are inconvenient):

ls -l '*.c

Otherwise, you’ll need to call the glob function directly which will return a list of matches.

glob can return no matches, the empty list, #n, so you will need to test before passing the list onto an external command:

files := glob "*.c"

if (null? files) {
  eprintf "WARNING: no files matched *.c\n"
} {
  ls -l files
}

Here, files, a list of file names, will have been expanded out as one of the arguments to the external command ls.

Note

You might be tempted to cut to the chase with:

ls -l (glob "*.c")

which is fine until it breaks. If glob returns no matches, ie. #n then you will get an ^rt-command-argv-type-error as there is no sensible stringified representation of #n for external commands. ls will not be run.

Indexing

Causing plenty of annoyance is the . value-index operator.

The goal is a Templates::Toolkit / Jinja2-style accessor method which does something sensible for lists, arrays, hash tables, strings, appropriately tagged C structures and so on.:

arr := #[ 1 2 3 ]
arr.0                ; 1
arr.2 = 99           ; #[ 1 2 99 ]

str := "hello"
str.0                ; #\h

sb := libc/stat "."
sb.st_ino            ; 69256525

Note

In this particular case trying to set an element of the string will fail as it is flagged as a const string (because it was constructed by the reader). You would need to copy-string first.

str := copy-string "hello"
str.1 = #\E                       ; "hEllo"

Not all C structures have a setter.

Without any form of Type Inference then this must query the value type before continuing but it is considerably more readable.

The indexing element can be a variable so that arr.i does the right thing. Of course, if st_ino is a variable in your code then the previous expression sb.st_ino might have unintended consequences. You can force a name/symbol with quote: sb.'st_ino.

The indexing element can also be a function in which case the function is applied to the value, that is v.f becomes an invocation of f v.

This is useful for splitting a line into fields:

Idio> (read-line).fields
hello        world
#[ "hello        world" "hello" "world" ]

Here, fields has returned an array of the original string and the IFS-separated words in the string.

Note

The reason . is annoying is that we are all prone to writing shell-like statements such as

ls *.txt

which value-index can’t figure out.

Last built at 2026-01-04T22:40:02Z+0000 from da47fd3 (dev)