Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions content/reference/functions/_index.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,45 @@ Before 3.10, the same call would have resulted in running the `format()`
function **before** the list is traversed, which is almost never what the user
wants.

### Short-circuit evaluation

Some functions that return `boolean` stop evaluating as soon as the result is
known, without looking at the rest of their arguments or list elements. This is
called short-circuit evaluation.

`and()` and `or()` evaluate their arguments strictly from left to right and
stop at the first argument that decides the result: the first false argument
for `and()`, the first true argument for `or()`. Function calls in the remaining
arguments are not called. This works like `&&` and `||` in C or shell, so you
can put cheap checks first, or use an earlier argument to guard a later one:

```cf3
bundle agent main
{
classes:
# filestat() is only called if the file exists.
"big_config"
if => and(
fileexists("/etc/myapp.conf"),
isgreaterthan(filestat("/etc/myapp.conf", "size"), "1024")
);
}
```

As described in [Function skipping][Functions#function skipping], `and()` and
`or()` are still skipped while any argument contains an unresolved variable,
even an argument after the one that decides the result. That check expands
variables, it does not call functions.

Functions that go through a list, or the lines of a file, stop at the first
element that decides the result:

- `some()`, `none()`, `reglist()`, and `regarray()` stop at the first matching
element.
- `every()` stops at the first element that doesn't match.
- `filesexist()` stops at the first file that can't be accessed.
- `regline()` stops at the first matching line.

## List of all functions

There are a large number of functions built into CFEngine. The following
Expand Down
7 changes: 6 additions & 1 deletion content/reference/functions/and.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ any argument evaluates to false.
**Arguments**: A list of classes, class expressions, or functions that return
classes.

`and()` evaluates its arguments left to right and will return as soon as one is
false. See [short-circuit evaluation][Functions#short-circuit evaluation].

**Example:**

```cf3 {skip TODO}
Expand All @@ -25,9 +28,11 @@ commands:

**Notes:** Introduced primarily for use with `if` and `unless` promise attributes.

**See also:** `or()`, `not()`
**See also:** `or()`, `not()`, [short-circuit evaluation][Functions#short-circuit evaluation]

**History:**

- Introduced in 3.2.0, Nova 2.1.0 (2011)
- Return type changed from `string` to `boolean` in 3.17.0 (2020) (CFE-3470)
- Stops evaluating arguments at the first false one in 3.29.0 (CFE-4272).
Previously all arguments, including function calls in them, were evaluated.
4 changes: 3 additions & 1 deletion content/reference/functions/every.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ the [unanchored][unanchored] `regex`.
`[a-zA-Z0-9_$(){}\[\].:]+`. It can be a data container or a regular
list.

`every()` will return as soon as an element doesn't match.

**Example:**

{{< CFEngine_include_snippet(every.cf, #\+begin_src cfengine3, .*end_src) >}}
Expand All @@ -30,4 +32,4 @@ Output:

**History:** The [collecting function][Functions#collecting functions] behavior was added in 3.9.

**See also:** [About collecting functions][Functions#collecting functions], `filter()`, `some()`, and `none()`.
**See also:** [About collecting functions][Functions#collecting functions], [short-circuit evaluation][Functions#short-circuit evaluation], `filter()`, `some()`, and `none()`.
4 changes: 3 additions & 1 deletion content/reference/functions/filesexist.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ this function to return true.
- list : The name of the list variable or data container to check, in the range
`[a-zA-Z0-9_$(){}\[\].:]+`

`filesexist()` will return as soon as a file can't be accessed.

**Example:**

{{< CFEngine_include_snippet(filesexist.cf, #\+begin_src cfengine3, .*end_src) >}}
Expand All @@ -29,4 +31,4 @@ Output:

**History:** The [collecting function][Functions#collecting functions] behavior was added in 3.12.

**See also:** [About collecting functions][Functions#collecting functions], `grep()`, `every()`, `some()`, and `none()`.
**See also:** [About collecting functions][Functions#collecting functions], [short-circuit evaluation][Functions#short-circuit evaluation], `grep()`, `every()`, `some()`, and `none()`.
9 changes: 7 additions & 2 deletions content/reference/functions/none.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ expression `regex`.

The regular expression is [unanchored][unanchored].

`none()` will return as soon as any element matches.

**Example:**

{{< CFEngine_include_snippet(none.cf, #\+begin_src cfengine3, .*end_src) >}}
Expand All @@ -24,6 +26,9 @@ Output:

{{< CFEngine_include_snippet(none.cf, #\+begin_src\s+example_output\s*, .*end_src) >}}

**History:** The [collecting function][Functions#collecting functions] behavior was added in 3.9.
**History:**

- The [collecting function][Functions#collecting functions] behavior was added in 3.9.
- Returns as soon as an element matches in 3.29.0 (CFE-4272).

**See also:** [About collecting functions][Functions#collecting functions], `filter()`, `every()`, and `some()`.
**See also:** [About collecting functions][Functions#collecting functions], [short-circuit evaluation][Functions#short-circuit evaluation], `filter()`, `every()`, and `some()`.
4 changes: 2 additions & 2 deletions content/reference/functions/not.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ aliases:

{{< CFEngine_function_prototype(expression) >}}

**Description:** Returns `any` if all arguments evaluate to false and `!any` if
any argument evaluates to true.
**Description:** Returns `any` if the argument evaluates to false and `!any` if
it evaluates to true.

{{< CFEngine_function_attributes(expression) >}}

Expand Down
9 changes: 7 additions & 2 deletions content/reference/functions/or.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ aliases:
{{< CFEngine_function_prototype(...) >}}

**Description:** Returns `any` if any argument evaluates to true and `!any` if
any argument evaluates to false.
all arguments evaluate to false.

**Arguments**: A list of classes, class expressions, or functions that return
classes.

`or()` evaluates its arguments left to right and will return as soon as one is
true. See [short-circuit evaluation][Functions#short-circuit evaluation].

**Example:**

```cf3 {skip TODO}
Expand All @@ -25,9 +28,11 @@ commands:

**Notes:** Introduced primarily for use with `if` and `unless` promise attributes.

**See also:** `and()`, `not()`
**See also:** `and()`, `not()`, [short-circuit evaluation][Functions#short-circuit evaluation]

**History:**

- Introduced in 3.2.0, Nova 2.1.0 (2011)
- Return type changed from `string` to `boolean` in 3.17.0 (2020) (CFE-3470)
- Stops evaluating arguments at the first true one in 3.29.0 (CFE-4272).
Previously all arguments, including function calls in them, were evaluated.
4 changes: 4 additions & 0 deletions content/reference/functions/regarray.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ aliases:

{{< CFEngine_function_attributes(array, regex) >}}

`regarray()` will return as soon as any element matches.

**Example:**

{{< CFEngine_include_snippet(regarray.cf, #\+begin_src cfengine3, .*end_src) >}}

Output:

{{< CFEngine_include_snippet(regarray.cf, #\+begin_src\s+example_output\s*, .*end_src) >}}

**See also:** [short-circuit evaluation][Functions#short-circuit evaluation]
4 changes: 3 additions & 1 deletion content/reference/functions/regline.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ true result.

{{< CFEngine_function_attributes(regex, filename) >}}

`regline()` will return as soon as a line matches.

**Examples:**

This example shows a way to determine if IPV4 forwarding is enabled or not.
Expand Down Expand Up @@ -53,4 +55,4 @@ bundle edit_line upgrade_cfexecd
}
```

**See also:** `regcmp()`, `strcmp()`
**See also:** `regcmp()`, `strcmp()`, [short-circuit evaluation][Functions#short-circuit evaluation]
9 changes: 7 additions & 2 deletions content/reference/functions/reglist.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ aliases:

{{< CFEngine_function_attributes(list, regex) >}}

`reglist()` will return as soon as any item matches.

**Example:**

{{< CFEngine_include_snippet(reglist.cf, #\+begin_src cfengine3, .*end_src) >}}
Expand All @@ -26,6 +28,9 @@ In the example above, the IP address in `$(sys.ipv4[eth0])` must be `escape`d,
so that the (.) characters in the IP address are not interpreted as the
regular expression "match any" characters.

**History:** The [collecting function][Functions#collecting functions] behavior was added in 3.9.
**History:**

- The [collecting function][Functions#collecting functions] behavior was added in 3.9.
- Returns as soon as an item matches in 3.29.0 (CFE-4272).

**See also:** `getindices()`, `getvalues()`, [about collecting functions][Functions#collecting functions], and `data` documentation.
**See also:** [short-circuit evaluation][Functions#short-circuit evaluation], `getindices()`, `getvalues()`, [about collecting functions][Functions#collecting functions], and `data` documentation.
6 changes: 3 additions & 3 deletions content/reference/functions/some.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ aliases:

It's convenient to set a class to `not => some(".*", mylist)` in order
to check if `mylist` is empty. Since `some()` returns as soon as
possible, that is better than using `length()` or `every()` or
`none()` which must traverse the entire list.
possible, that is better than using `length()`, which must traverse the
entire list.

**Example:**

Expand All @@ -31,4 +31,4 @@ Output:

**History:** The [collecting function][Functions#collecting functions] behavior was added in 3.9.

**See also:** [About collecting functions][Functions#collecting functions], `filter()`, `every()`, and `none()`.
**See also:** [About collecting functions][Functions#collecting functions], [short-circuit evaluation][Functions#short-circuit evaluation], `filter()`, `every()`, and `none()`.
2 changes: 2 additions & 0 deletions generator/_references.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
[mpf-services-autorun]: /reference/masterfiles-policy-framework/services-autorun
[package-modules-the-api]: /reference/language-concepts/modules/package-module-api#the-api
[Functions#collecting functions]: /reference/functions#collecting-functions
[Functions#short-circuit evaluation]: /reference/functions#short-circuit-evaluation
[Functions#function skipping]: /reference/functions#function-skipping
[guest_environments]: /reference/promise-types/guest_environments
[defaults]: /reference/promise-types/defaults
[getgrgid()]: https://linux.die.net/man/3/getgrgid
Expand Down
Loading