Get early access and a say in shaping the future of Pandita

Complete our survey

The Indu Programming Language

The Indu programming language is what makes Pandita work. Whether you're creating exercises or apps, you're writing Indu programs. Fortunately, this language was designed just for the web, and to be easy to learn.

Why Indu?

There are lots of programming languages available. Why does Pandita include an entirely new one? It's a good question: programming languages are a lot of work to create and learn, there better be a good reason to create one.

Indu is for building simple web apps. Apps, not sites: it should be predominantly interactive, it should do things when a user interacts with it, it should probably save some data. It should not just display content. HTML is already a perfectly good language for that. Ideal web apps for Indu are quite simple. Simple is subjective. A short-hand way of describing that is that Indu is not for building the next Gmail or Instagram. It might be a good way to manage your own to do list, and post your own photos though.

But more than anything else, Indu is for non-programmers. People who have not studied programming or computing, who have no interest in studying programming and computing, but do want to have control over what their computing devices do.

Indu is new. It's still finding it's feet. As you can see there is a lot that it doesn't do yet. Feedback, suggestions and ideas are really valuable. But, the goal of Indu won't change: it'll just get better at being the ideal language for non-programmers to create simple web apps.

In the meantime, this guide is for two audiences. It would be great to have a non-programmer use this to write Indu programs. But until Pandita has better tools, a lot of the early users will be professional programmers, who are interested in new programming languages and creating simple web apps. This guide frequently speaks directly to them.

  1. Hello, world!
  2. Examples
  3. Styling & CSS
  4. Re-use & using
  5. Mixins
  6. Events
  7. Functions
  8. Operators: Maths, Comparisons and Concatenation
  9. Variables & Attributes
  10. Booleans
  11. Strings
  12. Converting Strings, Number and Booleans
  13. Lists
  14. Looping
  15. Objects
  16. Checking the type of a value
  17. Databases
  18. APIs
  19. Libraries & Modules
  20. The Indu Standard Library
  21. The Pandita Platform
  22. What's Missing?

Hello, world!

Everything on the web is made up of HTML. Indu programs are no different. Indu supports HTML directly.

Indu

<p>Hello, world!</p>

Output

Hello, world!

HTML can contain other pieces of HTML, and Indu is no different.

Indu

<header>
  <h1>Welcome to My Blog</h1>
  <p>This is my blog where I write about my food and holidays, as if it is still 2009.</p>
</header>

Output

Welcome to My Blog

This is my blog where I write about my food and holidays, as if it is still 2009.

But Indu is not just HTML. Indu is built around the idea of 'objects.' An object is a part of a program. It can hold data, and also do things: usually to that data. Many programming languages feature objects. Indu's objects are quite a bit simpler than other languages. For any programmers reading along, Indu has no class system and no inheritance. Instead, it uses a Ruby-style mixin system.

In an Indu program, the objects make up the structure of the app that users see and interact with. Objects contain HTML, and other objects.

Indu

begin header
  <header>
    <h1>Welcome to My Blog</h1>
    <p>This is my blog where I write about my food and holidays, as if it is still 2009.</p>
  </header>
end header

Output

Welcome to My Blog

This is my blog where I write about my food and holidays, as if it is still 2009.

That example doesn't seem to add much though, does it? The advantage with Indu objects, however, is that they can take arguments, and then be re-used.

Indu

begin header
  tag is "header"
  <h1>#{ title }</h1>
  <p>#{ subtitle }</p>
end header

begin site
  make using header(title: "My Blog",
                    subtitle: "This is my blog where I write about my food and holidays, as if it is still 2009")
end site

Output

My Blog

This is my blog where I write about my food and holidays, as if it is still 2009

This example shows how to create structured HTML: set the `tag` attribute of an object to a string, and that will be used. This is great for structured HTML like <ol>.

Making Objects

There are two ways to create objects in Indu: begin object and make object. These both appear in the examples above. begin is used when you want to put things inside the object. make is used when the object is already complete. There is no difference in the object created: make is just shorter.

But, just using make on its own will give you an empty object. It won't do anything. In practice, you'll use make when there is an object that you want to copy with using. More on this when we get to mixins.

Examples

Learning a language like Indu and a platform like Pandita is best done with examples. Right now there is a small number of examples available, but this will grow!

Indu Examples

Styling & CSS

So far we've created a header with a heading and a subtitle. But both look exactly the same. The web is styled with CSS, and like HTML, Indu has direct support for CSS.

Each object can contain a style block. Inside this block, set any styling attributes that you'd like to apply to the object.

Indu

begin header
  begin heading-title
    style
      font-size is "1.5em"
    end style
    <h1>#{ title }</h1>
  end heading-title
  begin heading-subtitle
    style
      font-size is "0.8em"
    end style
    <p>#{ subtitle }</p>
  end heading-subtitle
end header

begin site
  make using header(title: "My Blog",
                    subtitle: "This is my blog where I write about my food and holidays, as if it is still 2009")
end site

Output

My Blog

This is my blog where I write about my food and holidays, as if it is still 2009

Any CSS property can be set in a style block like this. You can also use maths and functions to calculate a value. More on those later. One of the most common things you'll do is parameterise the style.

Indu

begin heading-title
  style
    font-size is "1.5em"
  end style
  <h1>#{ text }</h1>
end heading-title

begin heading-subtitle
  style
    font-size is "0.8em"
  end style
  <p>#{ text }</p>
end heading-subtitle

begin header
  style
    font-family is font
  end style

  <header>
    #{ make using heading-title(text: title) }
    #{ make using heading-subtitle(text: subtitle) }
  </header>
end header

begin site
  make using header(title: "My Blog",
                    subtitle: "This is my blog where I write about my food and holidays, as if it is still 2009",
                    font: "Verdana")
  make using header(title: "Article",
                    subtitle: "An interesting post I have written.",
                    font: "Times New Roman")
end site

Output

My Blog

This is my blog where I write about my food and holidays, as if it is still 2009

Article

An interesting post I have written.

If you're looking to understand how to style your apps, we recommend reading the Mozilla Developer Network articles on learning CSS.

Re-use & using

By now you've seen the keyword using appear in a few samples of code. using is one of the main ways that Indu allows authors to re-use code. Anytime you make or begin an object, you can choose to prepare that object by using another object, with using.

-- Creates an object called child from an object called example
make child using example
-- Creates an object without a name from an object called example
make using example
-- Creates an object called child, from example and then adds extras
begin child using example
  make extras
end child
-- Creates an object without a name, from example and then adds extras
using example
  make extras
end example

using works by copying everything from the source object to the new object. If you're a programmer, you might be thinking this is inheritance: it's not. Once the new object has been created there is no reference to the source object in it, anywhere.

When using another object, you can provide arguments. These are values that will be used in the new object, after the used object has been copied in. There is an example above with setting title, subtitle and font.

-- Syntax
make using example(name: <value>, etc...)

The name is whatever the used object expects to call this value.

Mixins

Mixins have been mentioned a couple of times already. Indu has been inspired by Ruby here. Mixins are the general form of all code re-use in Indu. They're fundamental and are used in a number of places, as well as being directly available to authors. Like using a mixin is an object copied into another object, with optional parameters. In fact, using is just syntactical sugar for a mixin.

Indu

begin google-font
  <link rel="preconnect" href="https://fonts.googleapis.com"> 
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 
  <link href="https://fonts.googleapis.com/css2?family=" & font & "&display=swap" rel="stylesheet">
end google-font

begin site
  begin header
    with google-font(font: "Fuggles")

    style
      font-family is "Fuggles"
      font-size is "2em"
    end style
    <h1>Tomorrow and tomorrow and tomorrow</h1>
  end header
end site

Output

Tomorrow and tomorrow and tomorrow

There's a bit here, but the mixin part is the line with google-font(font: "Fuggles"). This uses the google-font object created at the top of the example to insert the HTML to connect to Google Fonts, and request the font name. The font is then used to set the font-family.

Any object can be used as a mixin. When using a mixin, it is merged as if the contents of the mixin were written inline in the target object, at that point. The style block is treated specially: anything in the mixins style block is merged into the target object's style block, as if it were defined there.

As the example shows, mixins can take arguments. Anything defined in the arguments is mixed into the target object, after the mixin itself is mixed in. That is, arguments don't change the mixin, they only effect this specific use of the mixin.

Events

So far we've used objects and HTML to create and style apps. But these apps don't do anything: you could hardly call them apps. Indu is for web apps, not web sites. To make a site into an app, you have to handle events.

Indu

message is "Ready?"
  
<p>#{ message }</p>
  
begin button
  <button>Click</button>

  style
    padding is "0.25em 0.75em"
    border is "1px solid black"
  end style
    
  when click
    set message to "Clicked!"
  end click
end button

Output

Ready?

Events can be handled by an object, when generated, with the syntax when <event-name>. There are a lot of events to reflect all the potentially interesting changes can happen in a web app. These are all supported. As always, the MDN is the best reference to the available events you might want to handle.

Functions

The when click event handler above is actually just an Indu function. If you're a programmer, you know what a function is. If not, a function is a way of naming some useful behaviour often because you want to use it in more than one place.

A function can have any name, and is always defined with when. Functions can be defined inside objects, like an event handler, or outside objects if that makes more sense. As event handlers, functions are called automatically by Indu. When using functions directly, they are called with call. Functions return the last value, automatically.

Indu

when greeting
  "Hello, world!"
end greeting

message is "Ready?"

<p>#{ message }</p>

begin button
  <button>Click</button>

  style
    padding is "0.25em 0.75em"
    border is "1px solid black"
  end style

  when click
    set message to call greeting
  end click
end button

Output

Ready?

Functions that always return the same value aren't as useful as they could be. Functions can take arguments.

Indu

when factorial(n)
  if n > 1
    n * call factorial with (n: n - 1)
  else
    1
  end if
end factorial

countdown is 5
<p>#{ call factorial with (n: countdown) }</p>

Output

120

Indu uses named arguments. When defining a function, list the arguments in parentheses after the function name: when add(left, right). When calling the function, provide named values for each: call add with (left: 4, right: 6). Because the arguments are named you don't need to worry about order: call add with (right: 6, left: 4). Though in this case, that's a little confusing. If there are no arguments, then the with ... part is optional.

If your function is especially short, there is a single-line version of the function syntax: when name(args) => a single expression.

The previous example starts to show some of other sorts of things possible in Indu. In general, functions are where more complex operations will end up.

Operators: Maths, Comparisons and Concatenation

Indu provides a wide range of built-in operators. Indu also has operator precedence: this is the idea that operators should be performed in a certain order, not just left-to-right. That is, Indu will multiply two numbers before it attempts to add them. Here is a full list of operators, in order of increasing precedence.

& and &&: string concatenation
Joins two strings together. & attaches the strings as written, && will insert a single space between. You can think of "hello" && "world" as "hello" & " " & "world".
and and or: logic
and checks that both sides are true, and or checks that at least one side is. and will return either false, or the right-most argument. or will return either false or the first value that is equivalent to true.
=, !=, >, >=, < and <=: comparisons
Only useful for comparing numbers. Behave largely as you'd imagine. Rule of thumb for remembering with way less than or equal to and greater than or equal to are written: the equal is last in the sentence and it's last in the operator.
+ and -: addition and subtraction
Traditional addition and subtraction. Do not work on strings, or lists, or objects: only on numbers.
* and /: multiplication and division
Again quite traditional. * is multiplication and / is division. These aren't technically the maths symbols (✖️ and ➗ are more correct) but these are both on your keyboard.
not: negation
Returns the logical opposite. This is a unary operator: not has-name.
is-set?: is a name set to a value?
Indu does not have a null value. This operator is how a program checks to see if something has already been set. Anything you can set, can be checked to see if it is-set?: attributes, variables, list indices, data store keys.
( ): parentheses
Groups expressions and operators, to change the precedence. The contents of the parentheses will be evaluated first.

Indu

<p>Simple concatenation: #{ "Hell" & "o" }</p>
<p>Space concatenation: #{ "Hello" && "world" }</p>
<p>and: #{ 6 and 8 }</p>
<p>or: #{ 6 or 9 }</p>
<p>=: #{ 6 = 6 }</p>
<p>!=: #{ 6 != 9 } (not equals)</p>
<p>#{ ">:" } #{ 9 > 6 }</p>
<p>#{ ">=:" } #{ 6 >= 6 }</p>
<p>#{ "<:" } #{ 6 < 9 }</p>
<p>#{ "<=:" } #{ 6 <= 6}</p>
<p>+: #{ 6 + 9 }</p>
<p>-: #{ 9 - 6 }</p>
<p>*: #{ 9 * 6 }</p>
<p>/: #{ 18 / 6 }</p>
<p>not: #{ not true }</p>
<p>is-set: #{ is-set? unset-variable }</p>
<p>(): #{ 4 * (5 + 3) }</p>

Output

Simple concatenation: Hello

Space concatenation: Hello world

and: 8

or: 6

=: true

!=: true (not equals)

>: true

>=: true

<: true

<=: true

+: 15

-: 3

*: 64

/: 3

not: false

is-set?: false

(): 32

Variables & Attributes

Once you're calculating things, it's nice to be able to store those things somewhere. Indu provides variables and attributes for storing stuff.

Variables are names for values inside a function, and attributes are names for values on an object. You've already seen attributes: countdown is 5 is declaring an attribute and assigning it the value 5.

To assign to a variable, set it to something: set countdown to 6

There is no need for any ceremony about either variables or attributes: just name it and assign it a value, and off you go. When assigning to a variable with set Indu will attempt to find an existing variable or attribute that the code can 'see', and assign to that. If no variable or attribute exists, then a new variable is created within the function. That new variable will not be visible outside the function.

When assigning to an attribute with is inside an object, that will always only assign to an attribute in that object. You can use multiple is assignments.

The visibility of a named variable or attribute is called its scope. The structure of an Indu program shows the scope. A variable is visible in the function that sets it. Arguments to a function are variables, visible in that function. Attributes of an object are visible anywhere in that object, including any functions defined in that object, or any objects defined within that object.

Indu

message is "highest level"

begin top-level-object
  message is "object level"

  begin nested-object
    message is "nested level"

    when set-message
      set message to "visible to the function"
    end set-message

    begin button
      <button>Update Message</button>

      style
        padding is "0.25em 0.75em"
        border is "1px solid black"
      end style
    
      when click
        call set-message
      end click
    end button

    <p>The nested message is #{ message }</p>
  end nested-object

  <p>The top-level message is #{ message }</p>
end top-level-object

<p>The highest level message is #{ message }</p>

Output

The nested message is nested level

The top-level message is object level

the highest level message is highest level

Names

By now you've seen quite a few names of things in Indu: objects, functions, attributes, named arguments and varialbes. The rules for each are the same. The words me, list, true and false are used by Indu and can't be used for your own names. Names can contain any character on your keyboard except for " / ( ) = < > # : ; , [ ]. Names can not start with a number, a - or an @.

Booleans

The operators above refer to values of true and false. These are called boolean values, from Boolean algebra. Indu supports these directly, most commonly in if expressions, as illustrated above in the definition of factorial

Anywhere a boolean value is expected, Indu will treat false or 0 as boolean false, and anything else as boolean true.

An if expression consists of a test expression (which is treated as a boolean value), a list of expressions to evaluate if the test is true, and a list of expressions to evaluate if it is not true.

-- Syntax
if test-expr
  true expressions
else
  false expressions
end if

-- Example
if count > 0
  call accumulate with (items: count)
  count
else
  "No items found"
end

The if expression returns the value of the last expression in which ever of the two branches was chosen by the test expression.

Boolean values can be converted into numbers with as number. This will convert true to 1, and false to 0.

Strings

'String' is the accepted term in programming for lists of letters and other characters. The words you are reading, right now, really. These are very common in programming and therefore are fully supported in Indu. In Indu, strings support the full range of Unicode characters. So feel free to stick emojis or flags or animals or non-Latin characters directly into your strings.

You've already seen strings in the above examples. Strings are created with " and ". For example, "Hello, world!" is a string of the characters Hello, world!. The " characters are not part of the string. Strings can be stored and returned anywhere other values are used.

Two strings can be joined together with the concatenation operators & or &&. See operators above for the difference.

Sometimes, probably because you've asked your user for something, you might end up with a string that should contain a number, possibly a number that you want to do maths with. Indu lets you convert a string to a nubmer with as number. This assumes that the string only contains digits, and is in decimal.

Converting Strings, Number and Booleans

Indu programs can convert between strings, numbers and booleans. Most often, you will have a number from a user in a string and want to get to the actual number. This might also happen with booleans.

Convert a string or a boolean to a number with as number. The boolean true will become 1 and the boolean false will become 0.

Indu

<p>#{ true as number }</p>
<p>#{ false as number }</p>
<p>#{ ("5" as number) + ("20" as number) }</p>
<p>#{ "14" as number + true as number + false as number }</p>

Output

1

0

25

15

Convert a string or a number to a boolean with as boolean. The number 0 becomes the boolean false. All other numbers become the boolean true. The string "false" becomes the boolean false. The conversion doesn't care about case. All other strings become the boolean true.

Indu

<p>#{ 1 as boolean }</p>
<p>#{ 0 as boolean }</p>
<p>#{ 42 as boolean }</p>
<p>#{ "true" as boolean }</p>
<p>#{ "false" as boolean }</p>
<p>#{ "FALSE" as boolean }</p>
<p>#{ "False" as boolean }</p>
<p>#{ "fAlSe" as boolean }</p>
<p>#{ "hello" as boolean }</p>
<p>#{ "world" as boolean }</p>

Output

true

false

true

true

false

false

false

false

true

true

Convert a number or a boolean to a string with as boolean. Numbers are converted in base-10 (otherwise known as the decimal numbers you use everyday — there's not yet a way to specify the base). The boolean true becomes the string "true"; the boolean false becomes the string "false". Numbers and booleans are automatically converted to strings when concatenating, and when inserting into HTML.

Indu

<p>#{ true as string }</p>
<p>#{ false as string }</p>
<p>#{ "fAlSe" as boolean as string }</p>
<p>#{ (10 * 10) as string }</p>

Output

true

false

false

100

Indu doesn't otherwise attempt to convert numbers to strings or in any other combination. If you attempt 6 > "5" you'll get a runtime error, because it doesn't make any sense. There have been languages that attempted to smooth over that. Experience has taught us that that was largely a mistake. It's possible that those languages just did it really badly, however.

Lists

Indu provides a native list. A list is simply a collection of values, in an order. Indu lists can contain anything: numbers, booleans, strings, objects, other lists. Each list can contain different types of value, at the same time.

To create a list: list with (1; 2; 3). To create an empty list: list with (). To get one specific item out of a list: item 2 of a-list. To change one specific item in a list: set item 2 of a-list to 4. To insert a new item into the middle of a list: insert 25 at item 3 of a-list. This will make the list longer. To add a new item to the end of a list append 4 to a-list. To find out how many items are in a list: length of a-list. To remove an item from a list: remove item 2 of a-list. Removing an item will make the list shorter.

Indu

begin button
  <button>#{ label }</button>

  style
    margin is "0 0.125em"
    padding is "0.25em 0.75em"
    border is "1px solid black"
  end style
end button

begin site
  a-list is list with (100; 150; 200)
  <p>first item: #{ item 1 of a-list }</p>
  <p>last item: #{ item (length of a-list) of a-list }</p>
  <p>length: #{ length of a-list }</p>

  using button(label: "Update First Item")
    when click
      set item 1 of a-list to 400
      set a-list to a-list -- See sidebar below
    end click
  end button

  using button(label: "Add an Item")
    when click
      append 500 to a-list
      set a-list to a-list -- See sidebar below
    end click
  end button

  using button(label: "Remove an Item")
    when click
      remove item 2 of a-list
      set a-list to a-list -- See sidebar below
    end click
  end button

  using button(label: "Insert an Item")
    when click
      insert 175 at item 3 of a-list
      set a-list to a-list -- See sidebar below
    end click
  end button
end site

Output

first item: 100

last item: 200

length: 3

Looping

Alongside conditional (if) expressions, loops are the other major way of controlling what your program does. The idea is that programs often want to do the same set of things a number of times. Indu has a number of loops. All use repeat.

-- Loop while a condition remains true
repeat while boolean-expression
  expression actions...
end repeat

-- Loop until a condition becomes true
repeat until boolean-expression
  expression actions...
end repeat

-- Loop a specific number of times
repeat number-expression times
  expression actions...
end repeat

-- Loop over all the items in a list
repeat with ident in a-list
  expression actions...
end repeat

repeat while and repeat until are opposites of each other. But boolean logic is surprisingly difficult to get right. Sometimes waiting for something to become false is clearer than waiting for something to become not true.

repeat ... times is shorthand for the standard loop where you want your code to count up. It's common enough to warrant its own syntax.

Indu

a-list is list with (100; 200; 300)
total is "--"

<p>Total: #{ total }</p>

begin button
  <button>Add it Up</button>

  style
    padding is "0.25em 0.75em"
    border is "1px solid black"
  end style
  
  when click
    set total to 0
    repeat with value in a-list
      set total to total + value
    end repeat
  end click
end button

Output

Total: --

Loop Helper Variables

Inside the body of repeat ... times and repeat with ... in ... loops there are three variables available to help processing.

is-first?: is this the first time through the loop?
On the first iteration through the loop this variable will be true, after that it becomes false and stays false. This is useful if your loop requires special handling on the first item.
is-last?: is this the last time through the loop?
On the very last iteration of the loop this variable will be true. On every previous iteration, this variable will be false. This is useful if special handling is required for the last item in a list, for example.
index: the iteration count of the loop
Set to 1 before the beginning of the loop. Increments before the beginning of each loop.

This variables are only available inside the loop. If you have a variable in the function with the same name, that variable will not be updated, but that other variable will no longer be visible inside the loop.

Indu

a-list is list with (100; 200; 300; 400; 500)
total is "--"

<p>Total: #{ total }</p>

<p>This button will only add half the first item, will skip the last item, and will add the index each time.</p>

begin button
  <button>Add it Up</button>

  style
    padding is "0.25em 0.75em"
    border is "1px solid black"
  end style

  when click
    set total to 0
    repeat with value in a-list
      set total to total + index
      if is-first?
        set total to total + (value / 2)
      else
        if not is-last?
          set total to total + value
        end if
      end if
    end repeat
  end click
end button

Output

Total: --

This button will only add half the first item, will skip the last item, and will add the index each time.

Objects

Indu programs are built up of objects, and we've already seen hwo to define objects. As well as giving programs structure, objects are also useful for holding data. Typically, you'd use objects when storing it as a list doesn't feel right. Exactly how and when to use lists or objects is the subject of a lot of study, and is left (for now) as an exercise for the reader.

To use Indu objects to store data, you can create objects inside functions, just like any other value such as numbers or lists. Objects can be created with the same syntax as you've already seen. If the object is simple, it can also be created using make syntax.

-- Root object
begin an-object
  data is ...
end an-object

-- Object using another object to get started
begin an-object using parent
  data is ...
end an-object

-- Object using another object, and overriding parts
begin an-object using parent(data: ...)
  other-attribute is ...
end an-object

-- Object without a name using another object to get started
using parent
  data is ...
end parent

-- Object without a name using another object, and overriding parts
using parent(data: ...)
  other-attribute is ...
end parent

-- Single line versions of those
make an-object
make an-object using parent
make an-object using parent(data: ...)
make using parent(data: ...)

Objects defined using make are defined in a single line, and can't have any attributes or event handlers defined inside. Those can always be added later using set name of object to ..., of course. When an object is defined with begin a-name or make a-name that object is automatically assigned to either a variable in the current function, or as an attribute of the current object called a-name.

Objects are also implicitly a list: a list of all the children (either chunks of HTML or other objects) embedded within that object. This list can be appended to, by appending to the object.

Indu

begin todo-item
  text is ""

  style
    display is "block"
    width is "100%"
    font-size is "1.1em"
  end style

  <article>
    <input type="checkbox" name=text />
    <label for=text>#{ text }</label>
  </article>
end todo-item

begin site
  begin title
    style
      font-size is "2em"
      margin is "0.5em 0em"
    end style
    <h1>Todo</h1>
  end title

  make todo-list

  begin item-form
    text is ""

    style
      display is "block"
      margin is "0.25em 0em"
      width is "100%"
      border-bottom is "dashed 1px black"
      font-size is "1.1em"
    end style

    <input type="text" value=text>

    when change(value) => set text to value
  end item-form
  
  begin button
    <button>Add</button>

    style
      padding is "0.25em 0.75em"
      border is "1px solid black"
    end style
    
    when click
      set new-item to text of item-form
      append make using todo-item(text: new-item) to todo-list
      set text of item-form to ""
    end click
  end button
end site

Output

Todo

Checking the type of a value

Indu is what's called a 'dynamically-typed' language. This means that Indu doesn't require the 'type' to be determined before a value is used: Indu will work out what the type is based on how it's used. It also means that the type of a name can change. If you assign a number to an attribute the type of that attribute will be number. If you then assign a boolean to the same attribute, the type will become boolean.

There are only a few types in Indu: numbers, booleans, functions, lists and objects. Strings are actually a special kind of list.

It's pretty common to want to do different processing based on the type. This is most common with attributes, and particularly in objects that have been created to be re-used. Indu has six operators to let you check the type: is-number?, is-boolean?, is-function?, is-list?, is-object? and is-string?. Even though strings are just lists, they're special enough to want to check.

Indu

begin an-object
  when greeting => "Hello!"
end an-object

<p>is-number? 42: #{ is-number? 42 }</p>
<p>is-boolean? true: #{ is-boolean? true }</p>
<p>is-function? greeting of an-object: #{ is-function? greeting of an-object }</p>
<p>is-object? an-object: #{ is-object? an-object }</p>
<p>is-list? list with (1; 2; 3): #{ is-list? list with (1; 2; 3) }</p>
<p>is-string? "hello": #{ is-string? "hello" }</p>

Output

is-number? 42: true

is-boolean? true: true

is-function? greeting of an-object: true

is-object? an-object: true

is-list? list with (1; 2; 3): true

is-string? "hello": true

Strings are special. Strings are lists, and they're lists of one letter long strings. But, Indu is smart enough to distinguish between a string (that is internally a list of one letter long strings) and a list of longer strings.

Indu

<p>is-list? "hello": #{ is-list? "hello" }</p>
<p>is-string? "hello": #{ is-string? "hello" }</p>
<p>item 1 of "hello": #{ item 1 of "hello" }</p>
<p>is-string? item 1 of "hello": #{ is-string? item 1 of "hello" }</p>
<p>is-list? list with ("hello"; "world"): #{ is-list? list with ("hello"; "world") }</p>
<p>is-string? list with ("hello"; "world"): #{ is-string? list with ("hello"; "world") }</p>

Output

is-list? "hello": true

is-string? "hello": true

item 1 of "hello": h

is-string? item 1 of "hello": true

is-list? list with ("hello"; "world"): true

is-string? list with ("hello"; "world"): false

Databases

Indu directly supports databases to store data, permanently. An Indu program can have one or more databases. Each database has a name, and can store items under 'keys'. A key is just a string. Each key can only have a single value, so if you set a key that already exists, then the previous value will be replaced. However, each key can store numbers, booleans, strings and lists: which is a way of storing multiple items under a single key.

A database is created with database. All that's required is a name, and therefore make database name will work. A database is a special kind of Indu object and can contain attributes and functions, like other objects. If you want to create a database with functions and attributes use database name ... end name

To read from an object use key key-val of database-name and to write to a database use set key key-val of database-name.

Indu

make database counter

begin site
  click-count is (key "click-count" of counter) or 0
  
  <p>Count: #{ click-count }</p>
  
  begin button
    <button>Count a Click!</button>

    style
      padding is "0.25em 0.75em"
      border is "1px solid black"
    end style
    
    when click
      set click-count to click-count + 1
      set key "click-count" of counter to click-count
    end click
  end button
end site

Output

Count: 0

The pattern (key ... of ...) or 0 is a standard Indu pattern for checking if a value has been set, and providing a default (in this case, 0) if it has not been set.

Try clicking the button a few times, and then reloading the page. The value will remain stored. This guide uses your browser's session store to simulate a database. If you close the tab, the database will be cleared.

Important! Attributes are entirely optional on databases. However, the Pandita platform understands a special scope attribute. While this attribute is optional, and is safe to leave it out, it is important and you should read about it. It's described in more detail as part of the Pandita Platform.

APIs

Indu also supports accessing JSON-based APIs over the web. To use an API, define an api in your program. This is another kind of object, similiar to a database that describes how Indu should make requests.

An api object contains up to three important attributes: url, path and body. An api object can also contain other api objects. These child APIs can selectively override parts of their parent. This allows you to define a single api with multiple 'endpoints'. Each api object can also accept arguments, like a function call.

Of course, just like all Indu objects, an api object can also contain other attributes and functions.

To consume an api Indu adds a get and post function to each api. Each function can be called as any other function, passing any arguments for that API as arguments to the function. post will include the body attribute as well, if available.

This code is a working example of an Indu api to work with TV shows described in the Open Movie Database. To use this example you will need to get hold of your own OMDb API key. To use a simple app built with this api, try Frasier.

-- The top-level API doesn't take any arguments
api omdb
  -- The URL is defined here as all endpoints share this part
  url is "http://www.omdbapi.com"
   -- Your API key would go here. This attribute is not special to Indu
  api-key is "xxx"

  -- The title API takes an IMDb id as an argument
  api title(imdb-id)
    -- And uses that argument and the api-key attribute to build the path
    -- Indu combines this path with the url defined above
    path is "/?apikey=" & api-key & "&i=" & imdb-id
  end title
  -- The season API is similar, but it now has two arguments
  api season(imdb-id, season)
    path is "/?apikey=" & api-key & "&i=" & imdb-id & "&season=" & season
  end season
  -- And the episode API has three
  api episode(imdb-id, season, episode) 
    path is "/?apikey=" & api-key & "&i=" & imdb-id & "&season=" & season & "&episode=" & episode
  end episode
end api

-- To use this API:
set show to call get of title of omdb with (imdb-id: "tt0106004")
set season to call get of season of omdb with (imdb-id: "tt0106004", season: 4)

Libraries & Modules

As you write Indu programs you will find other programs that you want to use to help. You will also probably write your own programs. To re-use code, Indu offers libraries. Libraries are sets of objects (including databases and apis) and functions that can be included into a program, and then used as if they were part of that program.

Libraries are included with include. The included library becomes an object (called a module) that is then used to get access to functions and objects.

include module from /author/library

call function of module

begin site using root of module
  ...
end site

Libraries are just another Indu program; there's nothing special that you need to do. Because the library is also made into a module object, you can include libraries that have objects or functions with the same name as your program. If you're writing an Indu program that is intended to be used as a library, you should add a site object that explains the interesting parts of the library, and how to use it. Libraries can include other libraries.

Libraries, as objects, can also take arguments when being included: include module from /author/library with (arg: new-val).

Library: buttons-lib

begin google-font
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=" & font & "&display=swap" rel="stylesheet">
end google-font

begin button
  with google-font
  
  <button>#{ label }</button>

  style
    padding is "0.25em 0.75em"
    border is "1px solid black"
    font-family is font
  end style
end button

begin heading
  with google-font
  
  <h1>#{ text }</h1>

  style
    font-size is "2em"
    font-family is font
  end style
end heading

begin site
  <p>
    This library includes three useful objects for creating sites:
    heading, button and google-font. When including this library
    specify the Google Font to use with font.
  </p>
end site

Indu

include button from buttons-lib

begin site
  click-count is 0
  
  make using heading of button(font: "Lora", text: "Counting")
  <p>#{ click-count }</p>
  using button of button(font: "Lora", label: "Update")
    when click
      set click-count to click-count + 1
    end click
  end button
end site

Output

The Indu Standard Library

The Indu Standard Library is a collection of objects and functions to be used in all Indu programs. There are typical maths functions, typical functions for programs that run in a browser, and re-usable objects. All for building your own programs.

The standard library is currently quite small. It will grow, however. We're particularly interested in areas that you find it lacking.

Like all good Indu libraries, the documentation for the contents of the library are part of the library, and can be read by browsing to it.

Indu Standard Library

The Pandita Platform

Indu programs don't run in isolation. Each program runs here, on the Pandita platform. This platform provides a set of features and behaviour that Indu authors need to be aware of.

The site object
You've already seen this in a bunch of programs in this guide. In fact, it's in all of them, but some examples skip that part to keep the example focused. After Pandita has started an Indu program, it looks for an object called site and renders that. The site object is responsible for providing the first UI. In many cases, it'll be the only UI. Other objects can provide the UI, see the standard library for how to move between objects.
Event binding and handling
Pandita binds handlers on the window object, for all events it declares. When an event is handled, Pandita searches for the nearest Indu object and sends the event to that. It passes attributes of the event object as arguments to the event function, except for any attributes that are vendor-specific (eg. webkit or moz), are entirely upper-case, null, don't have a defined type (which means they are native objects), are the window object, or are JavaScript objects or functions. It sounds like a lot are excluded, but actually it mostly just trims down to the event attributes defined in the standard. If the event has a target attribute, Pandita will inspect that object and if it has a value object it will pass that to the event handler. Because Indu uses named arguments, if you're not interested in an event attribute, just ignore it in your argument list. If you are interested, just name it. The event mapping process is very likely to change!.
Rendering
Rendering is how Pandita and Indu work together to turn your objects into HTML and CSS so a browser can display your program. Most of this happens within Indu. Every object contains a render function that returns an Indu representation of an HTML element. Pandita then converts that representation to actual HTML. As mentioned in the standard library, every element has an id. This id is set to the caddr of the object that generated the element. If an element does not have an id it is because it was generated by an HTML literal. A caddr is an Indu thing that allows constant-time look-up of the Indu object. It is not persistent! It will change! Do not rely on specific values! Pandita uses an Indu feature to know when to re-render an object because it has changed. Every time an object attribute is set, and Indu event is raised. Pandita handles these events for any objects that appear in the displayed HTML. When the handler is invoked it will call render on that object, and then re-display just that part of the UI. If your program is re-rendering at inopportune times, try using temporary local variables. This is a poor imitation of data-flow analysis. Indu will likely improve rendering and other behaviour with proper data-flow analysis in the future.
APIs
APIs work pretty much as described. With one caveat: the Indu program running in the browser does not make the network call directly to the defined API. Instead, it creates a description of the request and submits it to the Pandita server. The Pandita server then sends the request. This is to ensure that the browser doesn't 'helpfully' package up cookies along with the request.
Databases
The scope attribute of database objects was mentioned in passing above. This attribute controls who can read or write to keys in the database. There are four values Pandita understands.
  1. app For values that the app should use no matter which author is running the app. Can be read by anyone, can only be written by the author of the app. Users must be logged in to Pandita to write, but not to read.
  2. user For values that the app needs to make available only to the user of the app. Can be read and written by anyone, however each user gets their own value and can't see anyone elses. Users must be logged in to write and read. This is the default scope if none is supplied.
  3. private Like user but there are only values for the author of the app, not anyone else. Users must be logged in to write and read.
  4. anonymous Anyone can write, but only the author can read. Useful for analytics. Users must be logged in to read, but not to write.

What's Missing?

If you've been reading the sidebars throughout this guide, you'll have noticed that there are few things that are missing from Indu. In general, things on this list are things that will be added or fixed in the future. It'd be great to hear which missing feature really gets in your way, so we can prioritise fixing that. Most of the items in this list are features, but there are some bugs.

  1. Non-whole numbers. Indu only supports integers, ie. whole numbers. There is a surprising amount you can do with whole numbers, but fractions will need to be supported at some point. Indu is not a language intended for high-performance computation, and therefore we will not add floating point numbers. Instead, we're going to jump straight to arbitrary precision number. That is, 3.01 - 3 should equal 0.01, not 0.0000000000009.
  2. CSS units on numbers. Indu should understand, hold onto and allow legal calculations with numbers that also have a CSS unit attached.
  3. Dates and times. Again, just like non-whole numbers, pretty useful things to work with. Indu will also add these as a fundamental data type in the future.
  4. Data-flow analysis. Indu and Pandita use dirty detection of attributes to understand how a program is changing. This will handle the intrinsic children list for objects, but it doesn't understand other lists, or database keys. Data-flow analysis may be able to solve more of these areas.
  5. Navigating the object graph. The children element of an object gives all the objects and HTML that are children. However, you can't walk back up the graph. The object graph is such a fundamental part of an Indu program that it should be possible to work with it directly.
  6. Request headers. The API support in Indu is intended to allow programs to consume simple JSON APIs, and it mostly does that. However, more complete support is probably going to require allowing APIs to control HTTP headers. Syntax exists, but it isn't supported yet.
  7. Garbage collection. As Indu programs run, objects are generated and then not used anymore. These objects are never cleaned up. Fortunately, Indu programs are quite simple and therefore not that many objects are generated. But, it is going to be problem. Fortunately, the language was designed with garbage collection in mind, and therefore as a programmer you don't need to worry about this too much. At some point in the future, garbage collection will be turned on and the risk of a program being stopped and restarted by the browser will disappear.
  8. Objects in Databases. Indu doesn't currently allow you to persist objects. Instead, you'll have to persist each attribute of interest, and then re-construct the object from those individual attributes.
  9. Richness in the Standard Library. Indu has a standard library, but it doesn't contain much at this point. It needs a rich set of objects that work in predictable and useful ways.