Skip to content

Commit

Permalink
Add documentation for volatility. (#8005)
Browse files Browse the repository at this point in the history
  • Loading branch information
dnwpark authored Nov 21, 2024
1 parent 8e7397b commit 371236c
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 21 deletions.
6 changes: 3 additions & 3 deletions docs/reference/ddl/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Create function

# and <subcommand> is one of

set volatility := {'Immutable' | 'Stable' | 'Volatile'} ;
set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ;
create annotation <annotation-name> := <value> ;
using ( <expr> ) ;
using <language> <functionbody> ;
Expand All @@ -75,7 +75,7 @@ Most sub-commands and options of this command are identical to the
:ref:`SDL function declaration <ref_eql_sdl_functions_syntax>`, with
some additional features listed below:

:eql:synopsis:`set volatility := {'Immutable' | 'Stable' | 'Volatile'}`
:eql:synopsis:`set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'}`
Function volatility determines how aggressively the compiler can
optimize its invocations. Other than a slight syntactical
difference this is the same as the corresponding SDL declaration.
Expand Down Expand Up @@ -141,7 +141,7 @@ Change the definition of a function.

# and <subcommand> is one of

set volatility := {'Immutable' | 'Stable' | 'Volatile'} ;
set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ;
reset volatility ;
rename to <newname> ;
create annotation <annotation-name> := <value> ;
Expand Down
1 change: 1 addition & 0 deletions docs/reference/edgeql/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Introspection command:
casts
functions
cardinality
volatility

select
insert
Expand Down
134 changes: 134 additions & 0 deletions docs/reference/edgeql/volatility.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
.. _ref_reference_volatility:


Volatility
==========

The **volatility** of an expression refers to how its value may change across
successive evaluations.

Expressions may have one of the following volatilities, in order of increasing
volatility:

* ``Immutable``: The expression cannot modify the database and is
guaranteed to have the same value *in all statements*.

* ``Stable``: The expression cannot modify the database and is
guaranteed to have the same value *within a single statement*.

* ``Volatile``: The expression cannot modify the database and can have
different values on successive evaluations.

* ``Modifying``: The expression can modify the database and can have
different values on successive evaluations.


Expressions
-----------

All :ref:`primitives <ref_datamodel_primitives>`,
:ref:`ranges <ref_std_range>`, and
:ref:`multiranges <ref_std_multirange>` are ``Immutable``.

:ref:`Arrays <ref_std_array>`, :ref:`tuples <ref_std_tuple>`, and
:ref:`sets <ref_eql_sets>` have the volatility of their most volatile
component.

:ref:`Globals <ref_datamodel_globals>` are always ``Stable``, even computed
globals with an immutable expression.


Objects and shapes
^^^^^^^^^^^^^^^^^^

:ref:`Objects <ref_datamodel_object_types>` are generally ``Stable`` except:

* Objects with a :ref:`shape <ref_eql_shapes>` containing a more volatile
computed pointer will have the volatility of its most volatile component.

* :ref:`Free objects <ref_eql_select_free_objects>` have the volatility of
their most volatile component. They may be ``Immutable``.

An object's non-computed pointers are ``Stable``. Its computed pointers have
the volatility of their expressions.

Any DML (i.e., :ref:`insert <ref_eql_insert>`, :ref:`update <ref_eql_update>`,
:ref:`delete <ref_eql_delete>`) is ``Modifying``.


Functions and operators
^^^^^^^^^^^^^^^^^^^^^^^

Unless explicitly specified, a :ref:`function's <ref_eql_sdl_functions>`
volatility will be inferred from its body expression.

A function call's volatility is highest of its body expression and its call
arguments.

Given:

.. code-block:: sdl
# Immutable
function plus_primitive(x: float64) -> float64
using (x + 1);
# Stable
global one := 1;
function plus_global(x: float64) -> float64
using (x + one);
# Volatile
function plus_random(x: float64) -> float64
using (x + random());
# Modifying
type One {
val := 1;
};
function plus_insert(x: float64) -> float64
using (x + (insert One).val);
Some example operator and function calls:

.. code-block::
1 + 1: Immutable
1 + global one: Stable
global one + random(): Volatile
(insert One).val: Modifying
plus_primitive(1): Immutable
plus_stable(1): Stable
plus_random(global one): Volatile
plus_insert(random()): Immutable
Restrictions
------------

Some features restrict the volatility of expressions. A lower volatility
can be used.

:ref:`Indexes <ref_datamodel_indexes>` expressions must be ``Immutable``.
Within the index, pointers to the indexed object are treated as immutable

:ref:`constraints <ref_datamodel_constraints>` expressions must be
``Immutable``. Within the constraint, the ``__subject__`` and its pointers are
treated as immutable.

:ref:`Access policies <ref_datamodel_access_policies>` must be ``Stable``.

:ref:`Aliases <ref_eql_ddl_aliases>`, :ref:`globals <ref_datamodel_globals>`,
and :ref:`computed pointers <ref_datamodel_computed>` in the schema must be
``Stable``.

The :ref:`cartesian product <ref_reference_cardinality_cartesian>` of a
``Volatile`` or ``Modifying`` expression is not allowed.

.. code-block:: edgeql-repl
db> SELECT {1, 2} + random()
QueryError: can not take cross product of volatile operation
``Modifying`` expressions are not allowed in a non-scalar argument to a
function, except for :ref:`standard set functions <ref_std_set>`.
2 changes: 2 additions & 0 deletions docs/reference/sdl/access_policies.rst
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ The access policy declaration options are as follows:
depends on whether this policy flavor is :eql:synopsis:`allow` or
:eql:synopsis:`deny`.

The expression must be :ref:`Stable <ref_reference_volatility>`.

When omitted, it is assumed that this policy applies to all eligible
objects of a given type.

Expand Down
3 changes: 2 additions & 1 deletion docs/reference/sdl/aliases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ This declaration defines a new alias with the following options:
The name (optionally module-qualified) of an alias to be created.

:eql:synopsis:`<alias-expr>`
The aliased expression. Can be any valid EdgeQL expression.
The aliased expression. Must be a :ref:`Stable <ref_reference_volatility>`
EdgeQL expression.

The valid SDL sub-declarations are listed below:

Expand Down
11 changes: 8 additions & 3 deletions docs/reference/sdl/constraints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,14 @@ This declaration defines a new constraint with the following options:
:eql:synopsis:`on ( <subject-expr> )`
An optional expression defining the *subject* of the constraint.
If not specified, the subject is the value of the schema item on
which the concrete constraint is defined. The expression must
refer to the original subject of the constraint as
``__subject__``. Note also that ``<subject-expr>`` itself has to
which the concrete constraint is defined.

The expression must refer to the original subject of the constraint as
``__subject__``. The expression must be
:ref:`Immutable <ref_reference_volatility>`, but may refer to
``__subject__`` and its properties and links.

Note also that ``<subject-expr>`` itself has to
be parenthesized.

:eql:synopsis:`except ( <exception-expr> )`
Expand Down
21 changes: 12 additions & 9 deletions docs/reference/sdl/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ commands <ref_eql_ddl_functions>`.
function <name> ([ <argspec> ] [, ... ]) -> <returnspec>
"{"
[ <annotation-declarations> ]
[ volatility := {'Immutable' | 'Stable' | 'Volatile'} ]
[ volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ]
[ using ( <expr> ) ; ]
[ using <language> <functionbody> ; ]
[ ... ]
Expand Down Expand Up @@ -127,23 +127,26 @@ This declaration defines a new constraint with the following options:

The valid SDL sub-declarations are listed below:

:eql:synopsis:`volatility := {'Immutable' | 'Stable' | 'Volatile'}`
:eql:synopsis:`volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'}`
Function volatility determines how aggressively the compiler can
optimize its invocations.

If not explicitly specified the function volatility is set to
``Volatile`` by default.
If not explicitly specified the function volatility is
:ref:`inferred <ref_reference_volatility>` from the function body.

* A ``Volatile`` function can modify the database and can return
different results on successive calls with the same arguments.
* An ``Immutable`` function cannot modify the database and is
guaranteed to return the same results given the same arguments
*in all statements*.

* A ``Stable`` function cannot modify the database and is
guaranteed to return the same results given the same
arguments *within a single statement*.

* An ``Immutable`` function cannot modify the database and is
guaranteed to return the same results given the same arguments
*forever*.
* A ``Volatile`` function cannot modify the database and can return
different results on successive calls with the same arguments.

* A ``Modifying`` function can modify the database and can return
different results on successive calls with the same arguments.

:eql:synopsis:`using ( <expr> )`
Specified the body of the function. :eql:synopsis:`<expr>` is an
Expand Down
9 changes: 6 additions & 3 deletions docs/reference/sdl/globals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,12 @@ The following options are available:
denoting a non-abstract scalar or a container type.

:eql:synopsis:`<name> := <expression>`
Defines a *computed* global variable. The provided expression can be any
valid EdgeQL expression, including one referring to other global
variables. The type of a *computed* global variable is not limited to
Defines a *computed* global variable.

The provided expression must be a :ref:`Stable <ref_reference_volatility>`
EdgeQL expression. It can refer to other global variables.

The type of a *computed* global variable is not limited to
scalar and container types, but also includes object types. So it is
possible to use that to define a global object variable based on an
another global scalar variable.
Expand Down
8 changes: 6 additions & 2 deletions docs/reference/sdl/indexes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,12 @@ Description
This declaration defines a new index with the following options:

:sdl:synopsis:`on ( <index-expr> )`
The specific expression for which the index is made. Note also
that ``<index-expr>`` itself has to be parenthesized.
The specific expression for which the index is made.

The expression must be :ref:`Immutable <ref_reference_volatility>` but may
refer to the indexed object's properties and links.

Note also that ``<index-expr>`` itself has to be parenthesized.

:eql:synopsis:`except ( <exception-expr> )`
An optional expression defining a condition to create exceptions
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/sdl/links.rst
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ The valid SDL sub-declarations are listed below:
The default value is used in an ``insert`` statement if an explicit
value for this link is not specified.

The expression must be :ref:`Stable <ref_reference_volatility>`.

:eql:synopsis:`readonly := {true | false}`
If ``true``, the link is considered *read-only*. Modifications
of this link are prohibited once an object is created. All of the
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/sdl/properties.rst
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ The valid SDL sub-declarations are listed below:
The default value is used in an ``insert`` statement if an explicit
value for this property is not specified.

The expression must be :ref:`Stable <ref_reference_volatility>`.

:eql:synopsis:`readonly := {true | false}`
If ``true``, the property is considered *read-only*.
Modifications of this property are prohibited once an object is
Expand Down

0 comments on commit 371236c

Please sign in to comment.