=========== Expressions =========== .. Modified: 2019-10-20/19:22-0400 btiffin .. Copyright 2016 Brian Tiffin .. This file is part of the Unicon Programming document .. GPL 3.0+ :ref:`license` .. image:: images/unicon.png :align: center .. only:: html :ref:`genindex` :floatright:`Unicon` .. index:: expressions .. _expression: Unicon expressions ================== Everything in Unicon is an expression. Well just about everything, *the source files are actually just text until processed*, for instance. Expressions can be chained in Unicon, and the overall *multiple expression* expression still counts as an expression in terms of the lexical syntax. For example: The :ref:`every ` reserved word is syntactically defined as .. sourcecode:: unicon every expr1 [do expr2] That can be .. sourcecode:: unicon every 1 to 5 do writes(".") Or it can be .. sourcecode:: unicon every i := 1 to 5 do write(i) The assignment expression, inserted in the ``every`` still counts as :math:`expr_1` for ``every``, from a compiler syntax point of view. This is a powerfully concise feature of Unicon and almost all programs take advantage of this grouped expressions within an expression paradigm. Expression blocks, contained within braces, also count as a single expression, in terms of the Unicon parser. Some operators, such as alternation and conjunction, and other syntax elements provide even more flexibility when forming expressions. .. index:: success, failure .. _success: .. _failure: Success and Failure ------------------- All Unicon expressions produce a value, or fail. This is a very powerful computational paradigm. Procedures can return a full range of values, and need not worry about reserving sentinel values for error codes or out-of-band results. For errors, or simple end-of-file status, the procedure can simply fail. *When error status codes are required, variables can be set.* Procedures always produce values, *unless they fail*. The default value for :ref:`return ` when no expression is given is :ref:`&null <&null>`. Falling off the end of a procedure without a ``return`` or ``suspend`` signals failure. .. literalinclude:: examples/default-return-value.icn :language: unicon :start-after: ##+ .. only:: html .. rst-class:: rightalign :download:`examples/default-return-value.icn` .. command-output:: unicon -s default-return-value.icn -x :cwd: examples There is no practical use for the concept of *void* in Unicon. *But fear not*, the foreign function interface layer :ref:`loadfunc `, can include wrappers that manage the C concept of void returns and transform things to usable Unicon values, when necessary. :ref:`&null <&null>` is not void. The closest thing to ``void`` in Unicon is ``failure``. Failure propagation ................... With goal-directed evaluation, Unicon expressions always strive to produce a result for surrounding expressions. Failure will propagate outwards when no result can be produced. When an inner expression fails, a surrounding expression will attempt any possible alternates, until it either succeeds or must also fail. This propagation will continue until a :ref:`bound expression ` marker terminates any goal-directed backtracking. -------- .. index:: null .. _null: null ---- The null value, represented by :ref:`&null <&null>` is the default value for unset variables or omitted arguments. The null value is treated specially inside most expressions. Many expressions will cause a runtime error when a null value is dereferenced as part of a computation, for instance. .. literalinclude:: examples/runtime-null.icn :language: unicon :start-after: ##+ .. only:: html .. rst-class:: rightalign :download:`examples/runtime-null.icn` The sample above abends with a runtime error when the null values of ``b`` and ``c`` are used in a calculation. See :ref:`&error <&error>` for ways of controlling how Unicon handles runtime errors. Runtime errors can be converted to expression failure, allowing programmer control of abend states. .. command-output:: unicon -s runtime-null.icn -x :cwd: examples :returncode: 1 Through this document, ``null``, and ``&null`` are used interchangeably, null is the value, represented by the keyword :ref:`&null <&null>`. -------- .. index:: precedence .. _precedence: Precedence ---------- It is very much worthwhile getting used to the precedence rules with Unicon, It is not as tricky as it may first seem, but the level of complexity of some Unicon expressions will be easier to read with a sound understanding of the order of precedence rules. When in doubt, use parentheses to control the evaluation order of complex expressions. .. include:: includes/precedence.inc .. index:: scope .. _scope: Variable scope -------------- Unicon supports variables with the following scope: - local - global - static - package All procedures are global in scope. Methods are local to the enclosing class. Parameters to a procedure are local to the body of the procedure. ``local`` can be used to create localized references within a procedure hiding any global variables. Static local variables retain their values between invocations of the enclosing procedure. Packages add another layer to the scoping rules of Unicon, and act as namespace containers for all procedures belonging to a package. .. todo:: add more details to package scoping -------- .. index:: semicolon; automatic insertion .. _automatic semicolon insertion: Semicolon insertion ------------------- Unicon expressions are separated by semicolons. .. sourcecode:: unicon i := 3 + 3; write(i); That code is the same as .. sourcecode:: unicon i := 3 + 3; write(i); Which, during ``unicon`` translation, is the same as .. sourcecode:: unicon i := 3 + 3 write(i) The lexer makes life easier, by automatically inserting semicolons at the end of a line if the last token could legally end an expression, and the first token of the next line is legal at the beginning of an expression. *This has implications*. Although automatic semicolon insertion is usually an invisible assistive feature, you need to be careful with expressions that span lines. They need to break at a point that avoids the automatic semicolon. .. literalinclude:: examples/semicolon.icn :language: unicon :start-after: ##+ .. only:: html .. rst-class:: rightalign :download:`examples/semicolon.icn` .. command-output:: unicon -s semicolon.icn -x :cwd: examples The second result is equivalent to .. sourcecode:: unicon i := 3; +3; write(i); Unicon will gladly accept ``+3`` as an expression, then discard the result, unused. In the sample, the first evaluation, ending with ``+``, which is not a legal expression ending token, avoided the automatic semicolon and set ``i`` to 6. .. sourcecode:: unicon i := 3+3; write(i); Discarding results is a feature of the Unicon implementation and happens all the time. All parameters to a function or procedure are evaluated, but only the required ones are dereferenced and passed. Conjugation evaluates :math:`expr_1`, and produces the value from :math:`expr_2` if :math:`expr_1` succeeds, but the value of :math:`expr_1` itself is discarded. *Side effects may happen, but the result is discarded in terms of the surrounding context*. Just a thing to be wary of when splitting expressions across lines. The Unicon lexical analyzer is very flexible and does the right thing in the vast majority of cases, but white space is not the only concern when splitting expressions across line breaks. The computer will always do what it is told, which may not always match what a human intended. Visible semicolon insertion ........................... To verify how the compiler treats multi-line expressions, the preprocessor output can always be used to see where semicolons are inserted: .. command-output:: unicon -E -s semicolon.icn :cwd: examples -------- .. index:: bound, bounded, expression; bound .. _bound expression: Bound Expressions ----------------- Along with the order of precedence, and goal directed evaluation, bounded expressions can be used to control the level of backtracking. A lot of bounded expressions are implicit. Intuitive, but nearly invisible with the automatic semicolon insertion that occurs at the end of each line (or multi line expression as explained in :ref:`automatic semicolon insertion `). Bound expressions block backtracking, a complex feature *(for the Unicon language designers and compiler authors)*. This features allows goal directed evaluation to work, without rewinding all the way back to the main entry point every time an alternative is required. .. literalinclude:: examples/backtrack-bound.icn :language: unicon :start-after: ##+ .. only:: html .. rst-class:: rightalign :download:`examples/backtrack-bound.icn` The first expressions is implicitly bound at the newline between the ``a`` assignment and the ``if find``, in the first code fragment. Unicon will not backtrack to reassign ``a`` to ``2`` when attempting to satisfy the ``find`` goal. *This is a good thing*. In the second fragment, backtracking is not bound as part of the ``a`` assignment, and ``find`` is allowed to try ``2`` when striving for the goal. .. program-output:: unicon -s backtrack-bound.icn -x :cwd: examples Curiousities ............ The available Unicon documentation, which includes the Icon document collection, is a vast treasure hoard of gems and jewels. The Unicon mailing list is also a source of learning and shared knowledge. Bruce Rennie asked about this one: .. sourcecode:: unicon # # suspended conjugation # procedure main() every write(subproc()) end procedure subproc() every (suspend 1 to 3) & 4 end That code produces:: 1 2 3 Normally conjugation (the ``&`` operator), returns :math:`expr_2` when :math:`expr_1` and :math:`expr_2` succeed. In the above instance, the parenthesized :ref:`suspend ` actually fails when resumed after the 3 is delivered. The conjugation then fails and the 4 is never used. The :ref:`write ` eventually fails, and the :ref:`every ` in main fails after the :ref:`to ` generator :ref:`write ` side effects. .. sourcecode:: unicon # # suspended conjugation # procedure main() every write(subproc()) end procedure subproc() every suspend 1 to 3 & 4 end That code will display the 4 three times, and only the 4s, the :math:`expr_2` result of the conjugation which succeeds three times given then the :ref:`to `. :: 4 4 4 The key expression here is grouped as .. sourcecode:: unicon every suspend ((1 to 3) & 4) ``1 to 3`` succeeds, and conjugation produces :math:`expr_2` (the 4), when :math:`expr_1` succeeds. .. index:: co-expression .. _co-expression: Unicon Co-Expressions ===================== Co-expressions are another *ahead of its time* feature of Icon/Unicon. They are usually used in the context of generators, allowing sequence results to be generated when needed. Co-expressions are also a key part of the multi-tasking features built into the Unicon virtual machine. See :ref:`tasks` for more information on this aspect of Unicon programming potentials. Multiple programs can be loaded into a single instance of a running Unicon machine and task co-expression activation can make for some very interesting possibilities. .. todo:: co-expression entries .. _user defined control structures: User defined control structures ------------------------------- .. todo:: control structure examples .. only:: html .. -------- :ref:`genindex` | Previous: :doc:`structures` | Next: :doc:`operators` |