Skip to content

Varargs in Rel

connected-dots

We are excited to announce the support of varargs in Rel.

You can use varargs to write more general code that works for multiple arities. A vararg is written by appending three dots to a variable name, for instance, x..., which matches zero or more variables.

Varargs can be useful when writing generic relations for common utilities.

For instance, say you want to define a relation that contains tuples of differing arities. Instead of overloading its declaration several times, you can simply use varargs.

When using varargs, keep in mind that the system needs to compute the arity (opens in a new tab) of the passed arguments. For an overloaded relation, this should be a finite number of arities.

The Rel Standard Library (opens in a new tab) includes the relation first that returns the first argument of R. It is defined using varargs as:

@inline
def first[R](x) = (y... : R(x, y...))

In this way, the argument R can have any arity:

// read query
 
def R = {(1, 2, 3); (4, 5, 6)}
def output = first[R]

Output:

This works even if R contains tuples of various lengths and data types:

// read query
 
def R = {(1, 2, 3, 4); ("foo", "bar")}
def output = first[R]

Output:

Varargs work for point-wise definitions.

For instance, say you want to check whether two relations are the same. You can do that in a point-free manner by using equal from the Rel Standard Library as:

// read query
 
def foo = {(1, 2); (3, 4)}
def bar = {(1, 3); (3, 4)}
 
def output = equal(bar, foo)

The output returns false, which is equivalent to a zero-arity relation.

Now, let’s check whether there is a tuple that is contained in both relations. For that, you can use varargs using point-wise syntax as follows:

// read query
 
def foo = {(1, 2); (3, 4)}
def bar = {(1, 3); (3, 4)}
 
def output = foo(x...) and bar(x...) from x...

In this case, the second tuples from both relations are equal and therefore the output is true.

The constant true is equivalent to {()}, which is the zero-arity relation that contains the empty tuple.

Finally, say you want to find tuples and their arities that occur both in foo and bar relations, without determining in advance what those arities might be. Again, you can do this with varargs:

// read query
 
def foo = {("Tom", 25); ("Alice", 34, 175); ("Bob", 20, 180)}
def bar = {("John", 19, 185); ("Bob", 20, 180); ("Tom", 25)}
 
def output(n, x... in foo) {
       arity[(x...)] = n and bar(x...)
}

Output:

While varargs are very useful for generalizing your code, relations with small arities that are normalized in Graph Normal Form (opens in a new tab) are preferred. This helps with performance, readability, and correctness.

Get Started!

Start your journey with RelationalAI today! Sign up to receive our newsletter, invitations to exclusive events, and customer case studies.

The information you provide will be used in accordance with the terms of our Privacy Policy. By submitting this form, you consent to allow RelationalAI to store and process the personal information submitted above to provide you the content requested.