# Constants

These are variables that are assigned an initial value that can never change e.g.

        constant MAX = 100
        constant Upper = MAX - 10, Lower = 5
        constant name_list = {"Fred", "George", "Larry"}

The result of any expression can be assigned to a constant, even one involving function calls, but once the assignment is made, the value of the constant variable is "locked in".
Constant declaration also supports multiple assignment syntax (this may make more sense after reading that section) e.g.

        constant {x, y, z} = {{},5,1.5}
    --  constant x = {}, y = 5, z = 1.5 -- equivalent

Typically such desequencing makes much more sense when the rhs is dynamically generated, for instance a function call.
Phix also allows nested constant declarations via the ':=' operator, within a (nested) rhs1 sequence constant declaration, so instead of

        constant WSAEINTR  = 10004,
                 WSAEACCES = 10013
        constant {ERROR_NO, ERROR_NAME, ERROR_SHORT} = columnize(
                {{WSAEINTR,  "WSAEINTR",  "Interrupted function call."},
                 {WSAEACCES, "WSAEACCES", "Permission denied."}}

which gets more and more error prone and tedious as the table grows in size, you can define them like this:

        constant {ERROR_NO, ERROR_NAME, ERROR_SHORT} = columnize(
                {{WSAEINTR  := 10004, "WSAEINTR",  "Interrupted function call."},
                 {WSAEACCES := 10013, "WSAEACCES", "Permission denied."}})

ie on the second line before the first ',' we see both a definition of WSAEINTR and a reference to it (the spaces around := are optional).
If with nested_globals is in force, WSAEINTR and WSAEACCES (ie anything declared via the ':=' operator) would be global, even when ERROR_XX are local. There is also a direct converse, in the form of "with nested_locals".
You can also, with some caution, use ":=$" syntax to declare basic-enum-style nested constants, for example

        constant ABCD = {A:=$, B:=$, C:=$, D:=$}
    --  constant ABCD = {A:=1, B:=2, C:=3, D:=4} -- equivalent

Note however that pmain.e/ncdollar is reset to 1 by the `constant` keyword and incremented on use in this fashion only, and cannot be overidden mid-declaration, so if you tried for instance "1,$,3,$" (iyswim) you would get "1,1,3,2" rather than "1,2,3,4". Also note $ has a completely different meaning within an enum (previous item), and within subscripts (such that s[$] means s[-1] aka s[length(s)]), plus of course this must all be supported by both the normal desktop/Phix and by pwa/p2js, hence: the implementation of ":=$" within constant definitions is deliberately kept as trivial as possible, and constructs such as `s[NXT:=$]` are not supported and may give unpredictable results (usu -1), in which case you will need to resort to a preceding enum or explicit values (such as `s[NXT:=7]`), and likewise you cannot use `A:=100+$` or `A:=$+100`, since that’s not (a plain and simple) ":=$". On the plus side it should be perfectly possible to use ":=$" in as deeply nested sequences as you like.
It may help to know that constants are really just variables which must be assigned on declaration, and for which subsequent assignment or other modification is prohibited. The actual constant values, both named and unnamed, are "pooled" so that only a single copy ever gets written out to a compiled executable file.
Several builtin constants are automatically defined in psym.e/syminit(), such as C_CHAR, C_BYTE, C_PTR, NULL, WINDOWS, LINUX, PI, LOCK_SHARED, LOCK_EXCLUSIVE, BLACK, GREEN, BLUE, DB_OK, DB_OPEN_FAIL, DB_EXISTS_ALREADY, MB_OK, MB_OKCANCEL, IDOK, IDCANCEL, IDYES, IDNO, SEEK_OK, and many more besides.
Constants can also be declared as global (application-wide), local (file-level), or private (routine-specific), see scope.
WARNING: except for literal integer constants, a pure forward call may result in constants being unassigned.
This should not be an issue if you have already invoked, for instance, a top-level main() after all points of call/declaration.
Several files in the builtins/ directory use local variables instead of constants, and hoist their assignment to an xinit/initx()
construct, with xinit set false at load-time, and initx() setting it true and assigning any non-integers, for example:

    integer xinit = false
    string x

    procedure initx()
        xinit = true
        x = "x" -- (usually something more involved)
    end procedure

    global procedure p() -- (possibly forward called)
        if not xinit then initx() end if -- (* many)
        ...
    end procedure

While the above might lose some benefits of "constant", it keeps the "once" aspect and is a completely safe way to deal with forward calls.
Types are optional on constant declarations, whether global, file-level, or local.
While a type check can occur on a constant declaration, it is more likely there just for clarification.
**DEV** everything below is currently being reconsidered.

Update:
  As of version 1.0.2 local constants are limited to literal values only. A statement/declaration inside a routine such as `constant x = split("one two three")` would not only suffer the same unassigned issues just described on forward calls, and raise some questions over precisely when/where that split() call should occur, but also try to pull in the autoinclude for split(), effectively when part-way through defining another routine, and that way trigger some very strange errors [it probably would be reasonably straightforward to stop it autoincluding things at the wrong time]. However, the recommended solution to those kind of issues would or might be to call split() inside an `if not init then` construct as just explained, which means the result isn’t being stored in a constant anyway... the whole concept of constants is much more useful at a higher/more visible level and in reality local constants gain very little over local variables... plus it seems JavaScript recomputes all local constants are every time, unless of course like above, you explicitly manage all that side of things..., so, literals-only it is.

Aside:
  Version 0.8.2 introduced an ill-conceived and pooly implemented static routine-level declaration, which only ever worked for integers and bools assigned to a literal or pre-existing file-level constant (not a parameter), and proved incompatible with p2js, hence the whole sad and sorry mess was removed in the 1.0.1 release. Given the sheer number of problems found when re-examined, I very much doubt that "static" saw any significant active service at all, and in fact, over 12 months later, not one single comment was ever made about "static" going awol.

Constant declarations must be grouped together at the start of any routine.
The reason for this is that the [implicit] return decrefs a range of the symtab, so either
the run-time must start checking every symtab entry (slowing everything down) or
DoRoutineDef() has to perform a potentially messy re-numbering operation (slowing everything down).
The compiler already defers parameter creation, for similar prior concerns, so probably best not to make it even more convoluted, eh?
Logically I suppose there is an argument that you ought be able to do something like this:

    constant c1 = "a"
    procedure p1()
        constant c1 = "p1a"
    end procedure

However the compiler issues duplicate errors over c1.
After some consideration I decided to leave it like that, mainly because the debugger does not posess the same concept of scope as the compiler proper, and hence would probably display the "wrong" c1 if/when asked (by whatever definition of wrong that might be).
You can however do this:

    procedure p1()
        constant c = "p1a"
        ?c
    end procedure

    procedure p2()
        constant c = "p2a"
        ?c
    end procedure

    p1()
    p2()

Since the c drop out of scope at the end procedure (ditto function/type) there is no name clash.

See Also: | multiple assignment, columnize
Technicalia | 1 (nested constant declarations) Specifically when pmain.e/DoSequence() with asConst!=-1, as set and reset by DoConstant(), encounters the aforementioned ":=" operator. Obviously nested constants cannot clash with an existing name or overwrite an existing value. aside: When first planning nested constant declarations, I (bizarrely) assumed it would be changes to GetMultiAssignSet(), but of course `constant {C1:=1,...} = <expr>` would (ill-)logically define C1 as 1 and them immediately try to re-assign something to it. In other words there are strict limitations on nested declarations that are not always immediately obvious. They are specifically only permitted within rhs sequences, so for instance `constant X = f({Y:=1})` is fine but `constant X = f(Y:=1)` is not, and besides the latter would encroach on named parameter syntax, and obviously the {} in the former prevents that kind of misinterpretation. Any error messages should however be crystal clear, and their absence taken as a clear indication that everything is fine. Prior to the introduction of with nested_globals I said this: It is not possible to micro-manage global status of nested declarations: ERROR_NO, ERROR_NAME, ERROR_SHORT, WSAEINTR, and WSAEACCES are either all global, or none of them are. However you can of course split the above definition as follows
        constant ERRORS = {{WSAEINTR  := 10004, "WSAEINTR",  "Interrupted function call."},
                           {WSAEACCES := 10013, "WSAEACCES", "Permission denied."}}
        global constant {ERROR_NO, ERROR_NAME, ERROR_SHORT} = columnize(ERRORS)
and that way make ERROR_NO, ERROR_NAME, and ERROR_SHORT global, but keep WSAEINTR and WSAEACCES (and ERRORS) private. In effect the opposite is now (a bit more) possible, although it would be quite fair to say that (the new) option is a little blunt and "all-or-nothing". Let me know if you want or have a bright idea for something a little better, but I would rather avoid making anything in this regard overly fiddly, repetitive, or downright tedious.