SCUA

Manual

Values and types

Every value in SCUA is one of a handful of kinds. This page names them, shows how to ask a value what it is, and covers the two things newcomers trip on most: integers and floats are separate, and only two values count as false.

You write SCUA without type annotations and it behaves like a dynamic language. The kinds below are what values are at runtime, whether or not you annotate anything. Annotations add compile-time checks on top; see Records and gradual types.

#The kinds

There are eight value kinds you'll meet right away. The type() builtin returns the kind of a value as a string:

print(type(nil))
print(type(true))
print(type(42))
print(type(3.14))
print(type("hi"))
print(type([1, 2, 3]))
print(type({ x = 1 }))
print(type(fn(n) return n end))

Run it:

$ scua kinds.scua
nil
bool
int
float
string
array
table
fn

So the kinds are nil, bool, int, float, string, array, table, and fn. A few notes:

  • nil is the absence of a value. A missing table field reads as nil, and a function with no return gives back nil.
  • bool is true or false.
  • int and float are both 64-bit numbers, and they are not the same kind. More on that below.
  • string is text. See Strings and interpolation.
  • array is an ordered, 0-based sequence written with square brackets. table is a string-keyed map written with braces. Both are covered in Collections.
  • fn is a function value. See Functions and closures.

There are a few more kinds you'll meet later: decimal for exact base-10 numbers like money and big for huge-magnitude idle-game numbers (both on the Numbers page), vectors, matrices, and quaternions for math (see Math), and the Ok/Error values that represent results of operations that can fail (see Errors and faults).

#Numbers in depth

int and float are different kinds and never mix silently — / always gives a float, // stays an int — and SCUA adds two specialist number kinds: decimal (exact base-10, for money) and big (unbounded magnitude, for idle games). How each is stored, the rules for mixing them, and when to use which are their own page: Numbers.

#Truthiness

In a condition, only nil and false are false. Everything else is true, including 0, the empty string, and an empty array.

fn check(v)
  if v then return "truthy" else return "falsy" end
end
print(check(nil))
print(check(false))
print(check(0))
print(check(""))
print(check([]))

Run it:

$ scua truthy.scua
falsy
falsy
truthy
truthy
truthy

If you're used to languages where 0 or an empty collection is false, watch this one. To test for an empty array, compare its length: if len(xs) == 0 then ....

#Equality

== compares values, and != is its negation. Numbers compare by value across int and float, so 1 == 1.0 is true. Strings compare by their contents.

print(1 == 1.0)
print("ed" == "ed")
print("ed" == "Ed")
print(1 == "1")
print([1, 2] == [1, 2])
let a = [1, 2]
let b = a
print(a == b)
print(3 != 4)

Run it:

$ scua equality.scua
true
true
false
false
true
true
true

Two things to know:

  • Values of different kinds are never equal. 1 == "1" is false; the int and the string are not compared after any conversion. (A key is its own kind too, so $"hp" == "hp" is false.)
  • Arrays, tables, and records compare by value — their contents, compared element by element (and recursively for nested ones). Two separately built arrays with the same elements are equal: [1, 2] == [1, 2] is true, and { x = 1 } == { x = 1 } is true. Two names for the same value are equal too. (Comparing two different kinds, or two records with different fields, is false.)