Introduction to formulas


Formulas are a special language used on Conjointly to perform tasks such as:

The language is inspired by R. While knowledge of R is not required, those familiar with R will find it easy to use formulas on Conjointly. One key difference is a much more relaxed approach to data types. For example, 1 + "2" is not allowed in R, but it is allowed on Conjointly and returns 3.

You can test and debug your formulas using Interactive debugger in the preview mode. The debugger can also be accessed by adding ?debugger=on to your survey URL (see example).

There are only four data types in formulas:

  • Numbers (e.g. 1, 2.5, -3.14), which are always treated as double-precision floating point numbers (“numeric” type in R). However, for comparisons, precision is limited to six decimal places.
  • Strings (e.g. "hello", "world"). Some operations and functions are case-sensitive (e.g. string comparison), while others are not (e.g. substring search).
  • Booleans (i.e. TRUE or FALSE, which can be spelt in any case like TrUe or true).
  • Undefined, which is a special value that is returned when a variable is not defined. When formulas are used in piping inside the survey, an undefined value will be shown as 🤷 (which makes it easy to spot an error).

Like in R, scalars (i.e. single values) and vectors (i.e. lists of values) are not distinguished as separate data types. If a vector is supplied where a scalar is expected, the first element of the vector is used.

Algebraic functions

Algebraic functions perform basic mathematical operations. They always expect numbers as operands and return a number.

OperationSyntaxExample usageResult
Additionx+y20+1535
Subtractionx-y10-37
Multiplicationx*y7*321
Divisionx/y10/25
Exponentialx^y4^216
Modulox%%y10%%31

Max and min functions

The max and min functions return the minimum or maximum value from a set of arguments. They always return a number. All arguments are taken to be numbers or vectors of numbers.

FunctionDescriptionExample usageResult
max(item1, item2, [item3], ...)Returns the highest value among the provided argumentsmax(3, -9, 7.5)7.5
min(item1, item2, [item3], ...)Returns the lowest value among the provided argumentsmin(3, -9, 7.5)-9

These functions require at least 1 argument and at maximum 500 arguments. If more are provided, only the first 500 are considered.

Example usages of min and max functions are provided below:

SituationFormulaResultComment
Arguments are numbers and stringmax(3, -9, "25", 8)25because string "25" is converted into number 25
Arguments are Boolean valuesmin(TRUE, FALSE)0because TRUE is forced into 1, FALSE is forced into 0
Arguments are non-numeric stringsmax("cat", "", "4")4because "cat" and "" are forced into 0, "4" is converted into 4
Arguments include vectormax([1, 2, 30, -5], "10", 7)30
Arguments are vector with Booleanmin([FALSE, 2, 3], 10, TRUE)0because the first element of vector FALSE is forced into 0
Argument includes functionmax(badFunction(234), -5)undefinedbecause badFunction returns undefined
Only one argumentmax(-5)-5
Only one string argumentmax("male")0

Rounding functions

Rounding functions are used to adjust numerical values to a desired precision. All arguments are taken to be numbers.

FunctionReturnsDescriptionExample usageResult
round(value)NumberReturns the value of a number rounded to the nearest integer.round(1.2345)1 (number)
ceil(value)NumberReturns the smallest integer greater than or equal to a given number.ceil(1.2345)2 (number)
floor(value)NumberReturns the largest integer less than or equal to a given number.floor(1.2345)1 (number)
toFixed(value, fractionDigits)StringConverts a number to a string, retaining the specified number of decimals indicated by the optional parameter fractionDigits, which must be an integer from 0 to 20. If fractionDigits is not given or is misspecified, it is assumed to be 0.toFixed(1.2345, 2)1.23 (string)

Example usages are provided below.

SituationFormulaResultComment
The GET variable gender is maleround(GETvariable("gender"))0because GETvariable("gender") is forced into 0
round("female")0because "female" is forced into 0
The GET variable age is 20.02323212424toFixed(GETvariable("age"))"20"because age is converted into the number 20.02323212424
The GET variable age is 20.02323212424toFixed(GETvariable("age"),40)"20"because fractionDigits is misspecified and therefore assumed to be 0
The GET variable age is 20.02323212424toFixed(GETvariable("age"),-1.33)"20"because fractionDigits is misspecified and therefore assumed to be 0
The GET variable freq is -23.31ceil(GETvariable("freq"))-23because ceil rounds up

Comparison operators

Comparison operators are used to compare two variables. Comparisons operators always return TRUE or FALSE.

OperationSyntaxExample usageResult
Equalsx==y5==10FALSE
Not equalsx!=y10!=3TRUE
Greater thanx>y5>19FALSE
Equal to or greater thanx>=y4>=4TRUE
Less thanx<y6<10TRUE
Equal to or less thanx<=y5<=1FALSE

Precision of numbers for the purposes of comparisons is limited to six decimal places. It is achieved by checking if the absolute value of differences is greater than one millionth.

Comparison operators expect numbers as arguments, with one exception: the == and != operators can also be used to compare strings case-sensitively alphabetically if both arguments are strings. In all other cases, strings are converted to numbers according to the rules described above.

Example usages of comparison operators are provided below.

SituationFormulaResultComment
The GET variable gender is maleGETvariable("gender") < 5TRUEbecause "male" is forced into 0
The GET variable gender was not recordedGETvariable("gender") < 5TRUEbecause the empty string is forced into 0
The GET variable gender was not recordedGETvariable("gender") == 0TRUEbecause the empty string is forced into 0
The GET variable gender was not recordedGETvariable("gender") != 0FALSEbecause the empty string is forced into 0
The GET variable age is 20GETvariable("age") < 5FALSEbecause GETvariable("age") is converted into the number 20
"3" < 5TRUEbecause 3 is forced into the number 3
"5" < 4FALSEbecause 5 is forced into the number 5
"5" == 5TRUEbecause 5 is forced into the number 5
"a"=="b"FALSEbecause both strings are compared alphabetically
"a"=="a"TRUEbecause both strings are compared alphabetically
"male" < " bird"FALSEbecause both strings are forced into the number 0
"male" == "Male"FALSEbecause comparison is case-sensitive
"male" == "male"TRUE
"0" == ""FALSEbecause both values are strings and compared as such
0 == ""TRUEbecause the empty string is forced into 0
1.0000001 == 1.0000002TRUEbecause the absolute value of the difference is 0.0000001 < 0.000001
1.0000001 == 1.0000005TRUEbecause the absolute value of the difference is 0.0000004 < 0.000001
1.0000001 == 1.0000012FALSEbecause the absolute value of the difference is 0.0000011 > 0.000001
"" == FALSETRUEbecause both FALSE is forced into 0 and "" is forced into 0
undefined == 0undefinedbecause undefined is contagious
undefined == "cat"undefinedbecause undefined is contagious
undefined > TRUEundefinedbecause undefined is contagious
undefined == undefinedundefinedbecause comparison operators expect numbers as arguments (unless both are strings) and undefined is contagious
"undefined" == undefinedundefined

Boolean operators

Boolean operators are used to combine or exclude comparison operations. The operands are taken to be Booleans. The Boolean operators always return TRUE or FALSE.

OperationSyntaxExample usageResult
Not!x!(10==5)TRUE
Andx&yTRUE&(10==5)FALSE
Orx|y(10<4)|(10>2)TRUE

If a vector of numbers is supplied, operation is done on the first element of the vector only.

if and ifs functions

These functions return values depending on whether a condition is true or not:

  • if('condition', 'then', ['else']) checks condition and returns a value if it is TRUE or a different value if it is FALSE.
  • ifs('condition1', 'then1', ['condition2'], ['then2'], ..., ['else']) returns a value that corresponds to the first true condition, or the “else” value if all specified conditions are false.

The conditions are taken to be Booleans. Conditions can be specified using comparison operators.

If the “else” value is not specified, it is taken to be undefined.

Example usages of if are provided below:

FormulaResultComment
if(3,3,5)3 (number)because 3!=0 is TRUE
if(0,3,5)5 (number)because 0!=0 is FALSE
if(FALSE,4,"male")male (string)
if(FALSE,4)undefined
if(TRUE,4,"male")4 (number)
if(answer(234),4,"male") (but question 234 is not part of this experiment)undefinedbecause undefined values are contagious
if(undefined,4,"male")undefinedbecause undefined is contagious
if(badFunction(234),4,"male")undefinedbecause the function badFunction does not exist

Example usages of ifs are provided below:

FormulaResultComment
ifs(3,3,5,3,0)3 (number)because 3!=0 is TRUE
ifs(0,3,5,4,-1)4 (number)because 0!=0 is FALSE, but 5!=0 is TRUE
ifs(FALSE,4,TRUE,"male")"male" (string)
ifs(FALSE,4)undefinedbecause the “else” condition is empty here
ifs(TRUE,4)4 (number)
ifs(TRUE,4,"male")4 (number)
ifs(answer(234),4,"male") (but question 234 is not part of this experiment)undefinedbecause undefined values are contagious
ifs(badFunction(234),4,"male")undefinedbecause the function badFunction does not exist