Advanced features

Import statement

Hurdy includes a Python-like import statement, which can be used to quickly declare and assign local variables from the entries of a table:

from expr import x, y, test

is equivalent to

var x, y, test
{
  var _hurdytemp1 = expr
  x = _hurdytemp1.x
  y = _hurdytemp1.y
  test = _hurdytemp1.test
}

expr need not be a variable name, but can be more generally an expression (function call, table indexing, etc.). The following are all valid uses of the statement:

from x import x, y
from require("library") import x, y
from t.subtable import x, y
from a + b import x, y -- allowed, but needs methametods for it to make sense
from nil import x, y -- technically allowed, but will result in a runtime error

The variable names can optionally be changed with the extended version of the command

from expr import end, global, test as a, b, test

-- names must be provided for all entries

which is equivalent to

var a, b, test
{
  var _hurdytemp1 = expr
  a = _hurdytemp1["end"] -- bracket access because 'end' is a Lua keyword
  b = _hurdytemp1.global
  test = _hurdytemp1.test
}

Note

When using the as version of the import statement, the fields of the table are allowed to be any kind of identifier, including Hurdy and Lua keywords.

If statements with assignment

Hurdy allows the condition(s) inside an if statement to be assigned to a local variables that is in scope inside the statement branches. This allows, for example, to quickly check if an object obtained through a function call or table access is not nil, and if it does access it without having to call the function/access the table again. For example:

if var x = t:get_object() {
  do_stuff(x)
}
else {
  print("no object!")
}

is equivalent to

{
  var x = t:get_object()
  if x  {
    do_stuff(x)
  }
  else {
    print("no object!")
  }
}

The assignment syntax is also available for the elseif conditions, but when used in this case elseif is converted to else if, that is a nested if statement is used. For example

if false {
  -- do nothing
}
elseif y {
  print("y")
}
elseif var x = f() {
  do_stuff(x)
}
else {
  print("no object!")
}

is equivalent to

if false {
  -- do nothing
}
elseif y {
  print("y")
}
else {
  if var x = f() {
    do_stuff(x)
  }
  else {
    print("no object!")
  }
}

Table comprehensions

Hurdy has Python-like comprehensions to quickly create arrays/tables through for loops. Table comprehensions, like table constructors, are expressions. There are three kinds of comprehensions syntaxes that can be used, described below.

Warning

This is the one feature in Hurdy that incurs in a performance cost compared to building the table in the regular verbose way, because it wraps the table creation loops in an anonymous function that is called immediately. The advantage of the syntax is that it makes things faster to write and easier to understand when reading the code.

Array comprehension

Arrays can be built with table comprehensions using braces containing a single expression followed by a for clause (both numeric and generic for are allowed) and optionally an if clause. For example

var array1 = { expr for i = 1, 10 }
var array2 = { expr for k, v in pairs(t) if k != 3 }

is equivalent to

var array1 = (function() {
  var _hurdytemp1 = {}
  var _hurdytemp2 = 0
  for i = 1, 10 {
    _hurdytemp2 += 1
    _hurdytemp1[_hurdytemp2] = expr
  }
  return _hurdytemp1
})()

var array2 = (function() {
  var _hurdytemp1 = {}
  var _hurdytemp2 = 0
  for k, v in pairs(t) {
    if k != 3 {
      _hurdytemp2 += 1
      _hurdytemp1[_hurdytemp2] = expr
    }
  }
  return _hurdytemp1
})()

Hash table comprehension

Hash tables can be built with table comprehensions using braces containing a two comma-separated expressions (a key/value pair) followed by a for clause (both numeric and generic for are allowed) and optionally an if clause. For example

var hash1 = { key_expr, value_expr for i = 1, 10 }
var hash2 = { key_expr, value_expr for k, v in pairs(t) if k != 3 }

is equivalent to

var hash1 = (function() {
  var _hurdytemp1 = {}
  for i = 1, 10 {
    _hurdytemp1[key_expr] = value_expr
  }
  return _hurdytemp1
})()

var hash2 = (function() {
  var _hurdytemp1 = {}
  for k, v in pairs(t) {
    if k != 3 {
    _hurdytemp1[key_expr] = value_expr
    }
  }
  return _hurdytemp1
})()

Hash table comprehension with single expression

In same cases it may be desirable for the key/value pair for the Hash table comprehension to be obtained as the outputs of a single function call. A special syntax exists for this case, where the table is constructed using braces containing a question mark ? followed by a comma and a function/method call (returning a key/value pair) followed by a for clause (both numeric and generic for are allowed) and optionally an if clause. For example

var hash1 = { ?, f() for i = 1, 10 }
var hash2 = { ?, t:get() for k, v in pairs(s) if k != 3 }

is equivalent to

var hash1 = (function() {
  var _hurdytemp1 = {}
  for i = 1, 10 {
    var _hurdytemp2, _hurdytemp3 = f()
    _hurdytemp1[_hurdytemp2] = _hurdytemp3
  }
  return _hurdytemp1
})()

var hash2 = (function() {
  var _hurdytemp1 = {}
  for k, v in pairs(s) {
    if k != 3 {
      var _hurdytemp2, _hurdytemp3 = t:get()
      _hurdytemp1[_hurdytemp2] = _hurdytemp3
    }
  }
  return _hurdytemp1
})()

Multiple for loops

Table comprehensions allow for multiple for clauses to be used, each with its own optional if clause. This allows the creation of tables that would require nested for loops. For example

var array1 = { M[i][j][k] for i = 1, 10 if i != 2 for j = 1, 10 for k = 1, 10 if k != 3 }

is equivalent to

var array1 = (function() {
  var _hurdytemp1 = {}
  var _hurdytemp2 = 0
  for i = 1, 10 {
    if i != 2 {
      for j = 1, 10 {
        for k = 1, 10 {
          if k != 3 {
            _hurdytemp2 += 1
            _hurdytemp1[_hurdytemp2] = M[i][j][k]
          }
        }
      }
    }
  }
  return _hurdytemp1
})()

Note that the order in which the for loops and if clauses are nested is the same in which they are specified in the table comprehension.