Types and constants

How jaala reads a constant against the type of the argument it stands in, and how numbers and text compare and sort.

Every value in jaala is a number or text (or absent, which the host-facing pages cover). A relation’s arguments can have types, and when they do, jaala reads a constant as the type of the argument it stands in.

Declared types

A rule head can declare an argument’s type with ?n: number. That turns a constant written in the query into a value of that type, so "800" in a number argument means the number 800:

size(?p, ?n: number) :- loc(?p, ?n);
size(?p, "800") => ?p
?p
auth
Facts: the deps dataset

And a constant that can’t be read that way is refused, rather than answering nothing:

size(?p, ?n: number) :- loc(?p, ?n);
size(?p, "big") => ?p

query: size's "n" argument cannot be "big" (it holds a number)

Facts: the deps dataset

The difference matters most when a question comes from a person or a form, where "big" is a mistake you’d want reported. Without the declaration, jaala has no type to check against, and the same question matches no rows without saying why:

size(?p, ?n) :- loc(?p, ?n);
size(?p, "big") => ?p

No rows.

Facts: the deps dataset

A host can declare types on the relations it serves too, which mostly saves you writing them in rules, and a rule’s undeclared arguments pick up types from what its body reads. The facts on this site declare none, which is why the rule here has to.

Numbers and text

Numbers compare by value and text compares as text, which is the usual order for strings:

owner(?p, ?t), ?t < "p" => ?p, ?t
?p?t
cachedata
dbdata
Facts: the deps dataset

A number never equals text, so "1" and 1 are different values, and quotes are what make a constant text (#162). That only bites in a column with no declared type. In a typed one, jaala reads both sides as the column’s type: the query’s constants before evaluating, and the source’s facts as it reads them, so a pin a source stored as the number 3 reads as "3" in a pin column, and a count stored as the text "0010" reads as 10 in a number column. Keeping kinds apart is what makes equality consistent: if two values both equal a third, they equal each other, whichever order a join meets them in.

A number and a piece of text have no order between them, so a comparison of one with the other never holds, whichever way round it’s written:

loc(?p, ?n), ?n < "a" => ?p

No rows.

Facts: the deps dataset

When a column holds both, the answer still has to come back in one order, so jaala puts every number before every piece of text, numbers by value and text as text:

value(?x) :- loc(_, ?x);
value(?x) :- owner(_, ?x);
value(?x) => ?x
?x
100
150
200
250
300
400
800
900
1200
1500
data
platform
security
web
Facts: the deps dataset

That order is the same every time, for the same facts and the same query, which is what lets a host compare two answers line by line. The ordering page has the rest of it.

An answer writes a plain number one way, the way Go’s %g would, however the query or the source spelled it. So 1.50 comes back as 1.5, 01 as 1, and 1.0 and 1 are the same row (#148):

limit(?team, 1.50) :- owner(_, ?team);
limit(?team, ?l) => ?team, ?l
?team?l
data1.5
platform1.5
security1.5
web1.5
Facts: the deps dataset

Text that says more than the number is kept as the source wrote it. A host storing a voltage as 3.3V with the number 3.3 gets 3.3V back, and so does a query that asked about 3.3, since where two spellings of one number meet, the one saying more wins. A value the host bound with Bind comes back exactly as bound.