diff --git a/%5BDRAFT%5D AerScript Specification - AER%2326 standard.-.md b/%5BDRAFT%5D AerScript Specification - AER%2326 standard.-.md new file mode 100644 index 0000000..c794021 --- /dev/null +++ b/%5BDRAFT%5D AerScript Specification - AER%2326 standard.-.md @@ -0,0 +1,1991 @@ +## 1. Introduction + +The __AerScript__ language specification describes the language syntax and usage. This draft establishes the base for the __AER#26__ standard, using AER#19 and the supplied __Aer Interpreter__, based on the PH7 Engine. AerScript has its roots in the C family of languages and will be immediately familiar to C, C++, C#, Java and PHP programmers. AerScript is standardized by CodingWorkshop. + +AerScript is a general-purpose, object-oriented scripting language. Managed values and objects, typed declarations, built-in functions, callbacks and exception handling aid in the construction of scripts and embedded applications. + +The supplied interpreter is the baseline for this specification. Explicitly agreed AER#26 requirements take precedence over that baseline, including NULL coalescing, inheritance, loading, diagnostics and the corrections identified in chapter 13. A stated requirement does not mean that the supplied executable already implements it. Chapter 15 separately identifies future facilities whose implementation or detailed design is not yet complete. Other behavior follows the supplied interpreter unless a later decision explicitly changes it. + +The implementation baseline is the supplied aer.tar archive, SHA-256 d947c9203893cf5747388114a070ccd5b7d9c43c339a1d5fccb4836574ab933b. The accompanying interpreter/documentation audit records the source review, original tests and additional execution probes. This draft does not certify every library function or every possible program. + +## 2. Scope + +This specification describes the form and interpretation of programs written in the AerScript language. It describes: + + * The representation of AerScript programs; + * The syntax and constraints of the AerScript language; + * The observed semantic rules for executing programs; + * The restrictions and limits of the current implementation; + * The agreed AER#26 rules, with implementation gaps and future facilities explicitly identified. + +Examples containing statements are assumed to occur inside a method unless a complete program is shown. Method fragments are assumed to occur inside a class. Error examples describe rejected or limited operations. Examples using an agreed correction describe AER#26 requirements; chapter 13 identifies the supplied executable's remaining differences. Chapter 15 describes future facilities and is not evidence that they are already available. + +The words shall and must state requirements of the agreed rules. The source review establishes what is implemented; chapter 13 identifies where the executable still differs. Questions explicitly left open are not settled merely by the presence of a token, a prototype or an older example. The separate decision register distinguishes accepted changes, future work and unresolved proposals. + +## 3. Terms and Definitions + +* __Argument:__ an expression in the comma-separated list bounded by the parentheses in a method, anonymous function or constructor call. It is also known as an actual argument. +* __Base class:__ a class named after extends, or an ancestor reached through such a class. +* __Behavior:__ external appearance or action. +* __Constraint:__ a restriction, either syntactic or semantic, on how language elements can be used. +* __Declaring class:__ the class in which a member was originally declared. +* __Deprecated:__ an informational message intended to identify the use of a deprecated language construct or feature. +* __Effective method:__ in the agreed model, the declaration selected for a particular input signature after applying method resolution order. +* __Empty value:__ a value treated as empty by the NULL rules described in section 6.11. Emptiness is not a separate declared type. +* __Error:__ a condition in which the engine cannot continue executing the script and must terminate. +* __Exception:__ a condition represented by an exception object which can be caught by a user-defined handler. +* __Input signature:__ in the agreed model, a method name together with the ordered parameter types and their passing modes. The return type, parameter names and default values are not part of an input signature. +* __Method resolution order (MRO):__ in the agreed model, the ordered sequence of a class and its ancestors, calculated using C3 linearization. +* __Notice:__ an informational message informing the user of code that may not work as intended. +* __Parameter:__ a variable declared as part of a method, anonymous function or constructor definition, which acquires a value or reference on entry to that body. It is also known as a formal parameter. +* __PH7 Engine:__ the software, including its compiler and Virtual Machine, that executes an AerScript program. +* __Script:__ one or more source files presented to the interpreter. Essentially, a script is the input to the interpreter. +* __Value:__ a unit of data operated on by the Engine, having a type and content appropriate to that type. +* __Warning:__ an informational message intended to identify a potentially questionable usage of a program element. + +## 4. Notational Conventions + +Lexical and syntactic grammars for AerScript are interspersed throughout this specification. The lexical grammar defines how characters can be combined to form tokens, that is, the minimal lexical elements of the language. The syntactic grammar defines how tokens can be combined to make valid AerScript programs. + +### 4.1. Scripts + +A script is a sequence of bytes encoded using UTF-8. Typically, a script has a one-to-one correspondence with a file in a file system, but this correspondence is not required. AerScript source is processed as a series of 8-bit bytes. The ASCII characters used for syntax retain their usual byte values, while UTF-8 byte sequences may occur in identifiers, comments and string literals. + +Conceptually speaking, a script is translated using the following steps: + + * Lexical analysis, which translates the input into a stream of tokens; + * Syntactic analysis and compilation, which translate the stream of tokens into executable code; + * Execution of the resulting code by the interpreter. + +The interpreter accepts UTF-8 byte sequences in identifiers and text, including natural languages such as Japanese, Chinese or Arabic. This does not establish Unicode normalization or validation of identifier categories. Accepting UTF-8 source does not make ordinary string indexing operate on Unicode code points. The current character representation and byte-based string operations are described in chapter 6 and are retained in AER#26. + +### 4.2. Lexical Analysis + +The input production defines the lexical structure of an AerScript source file. Each source file in an AerScript application must conform to this lexical grammar production. + +Four basic elements make up the lexical structure of an AerScript source file: Line terminators, white space, comments, and tokens. Of these basic elements, only tokens are significant in the syntactic grammar of an AerScript program. + +#### 4.2.1. Comments + +Two forms of comments are supported: + + * delimited comments, + * single-line comments. + +Single-line comments start with the characters __//__ or __#__ and extend to the end of the source line. The trailing new line can be omitted. Delimited comments start with the characters __/*__ and end with the characters __*/__. Delimited comments may span multiple lines. Example: + + # This is a single line comment + // This is another single line comment + /* This is a + multi-line comment block */ + +A delimited comment can occur in any place in a script in which white space can occur. During tokenizing, an implementation can treat a delimited comment as though it was a white space. + +#### 4.2.2. White Space + +ASCII space, horizontal tab, vertical tab, form feed, carriage return and line feed separate tokens. White space improves the readability of source code. Its amount is irrelevant outside literals and other token content. + +The lexer operates on bytes. Two statements can be put on one line, or one statement on several lines, while retaining the required punctuation. + +#### 4.2.3. Tokens + +There are several kinds of tokens: identifiers, keywords, literals, operators, and punctuators. White space and comments are not tokens, though they act as separators for tokens. + + token + : identifier + | keyword + | NULL_literal + | boolean_literal + | integer_literal + | real_literal + | string_literal + | interpolated_string_literal + | operator_or_punctuator + ; + + +##### 4.2.3.1. Literals + +A literal represents a value within Aer source code. Aer supports Boolean values TRUE and FALSE, NULL, integer values in decimal, hexadecimal, octal and binary notation, floating-point values, and quoted strings. + + int $decimal = 5; + int $hexadecimal = 0x10; + int $octal = 0o10; + int $binary = 0b101; + float $ratio = 1e2; + string $name = 'AerScript'; + char $letter = 'A'; + +Both 'A' and "A" are string expressions. Assigning a one-byte string to char performs an allowed conversion; it does not establish a separate character-literal token. The prefixes 0b, 0o and 0x select binary, octal and hexadecimal notation respectively. Decimal notation has no base prefix. For example, 65, 0b1000001, 0o101 and 0x41 denote the same integer. The old implicit-octal spelling is replaced by the explicit 0o prefix in AER#26; the supplied lexer requires adaptation. + +##### 4.2.3.2. Operators and Punctuators + +Operators describe operations on operands. Punctuators group and separate declarations and expressions. + + + - * / % ** ++ -- + = += -= *= /= %= **= + == != > < >= <= + && || ^^ ! & ^ | ~ + &= ^= |= << >> <<= >>= + , :: ( ) [ ] { } + -> : ? ?? => ; $ + +The words new, clone and is also act as operators. The addition operator performs string concatenation. A comma may separate arguments, declarations or array elements, or form the comma expression described in section 7.12. The supplied comma-expression implementation requires correction. + +Chapter 7 describes precedence and evaluation. + +##### 4.2.3.3. Identifiers + +An identifier is a name used for a variable, constant, class, interface or method. An identifier begins with a letter or an underscore and may be followed by letters, digits or underscores. Non-ASCII names may be written as UTF-8. + + int $count; + string $概要 = 'AerScript Interpreter'; + +The dollar sign is part of variable notation, but not part of a class, method or constant name. A numeric first character is not permitted in an ordinary identifier. Exact Unicode identifier categories, normalization and case rules for all declaration kinds remain to be completed in this draft. + +##### 4.2.3.4. Keywords + +The lexer recognizes the following words: + + auto bool break callback case catch char class clone const continue + default define do else eval exit extends final finally float for + foreach goto if implements import in include int interface is mixed + namespace new object private protected public require resource return + static string switch throw try using virtual void while + +Keyword recognition is case-sensitive. Recognition alone does not establish a working feature. Namespaces are a future facility described in chapter 15; the supplied parser currently reports that they are disabled. + +Use else if as two words, is for type tests and virtual for unimplemented class methods. Names following a variable's $ may coincide with keyword spellings. + +print(), eval() and exit() have callable implementations. AER#26 uses include(string) as a contextual built-in function within a method or anonymous function. require, import and define are statements at script declaration scope. The supplied include parser requires adaptation to this function syntax. empty, isset, list, func_num_args and func_get_args are planned facilities described in chapter 15, not currently registered implementations. + +##### 4.2.3.5. Semicolon + +A semicolon is used to mark the end of a simple statement in Aer. It is mandatory after declarations of local variables, assignments, calls used as statements and return statements. Compound statements and class or method definitions are delimited by braces and do not require an additional semicolon. + +An anonymous function assigned to a variable is part of a declaration or assignment, so the statement requires a trailing semicolon. + +##### 4.2.3.6. Aer Variables + +A variable is an identifier which holds a value. In programming we say that we assign a value to a variable. Variables can be assigned different values over time, subject to their declared type. + +Variables in Aer consist of the $ character, called a sigil, and an identifier. A variable must be declared before it is used. The declaration specifies a type, or uses auto to infer a type from its initializer. + + int $count = 7; + string $message = 'Hello'; + auto $ratio = 5.0; + +The special variable $this refers to the current object. The special variable $parent continues lookup through the actual object's MRO after the class declaring the executing method, as specified in chapter 12. Their meaning is described in chapter 11. + +##### 4.2.3.7. Aer Constants + +A constant is a named value or expression that cannot be assigned to like a variable. Aer provides a global define statement, local const declarations, and class constants. + + define APPLICATION_NAME 'AerScript example'; + +This define statement occurs at script scope. It is not a call to define(). Class constants and local constants have different evaluation behavior, described in section 11.13 and chapter 10. + +## 5. Basic Concepts + +### 5.1. Script Startup + +The interpreter compiles and executes a script. The script provides a concrete class named Program and a method named main, whose declared return type is void or int. + + class Program { + public void main(string[] $args) { + print('Hello world from Aer'); + } + } + +Startup creates Program and invokes its constructor, when present, without arguments. It then invokes the single public main with the command-line array. main may have no formal parameters or one string[] parameter, and its declared return type must be void or int. Startup does not select among overloaded main methods. A non-public main is invalid even though the supplied startup path currently permits it. + +Program constructors should require no arguments. A constructor parameter is not automatically supplied with the command-line array. Normal method-call assumptions must not be applied to this special startup sequence. + +### 5.2. Script Termination + +If the return type of the script's entry point is int, the returned value serves as the script's termination status code. The purpose of this code is to allow communication of success or failure to the execution environment. + +If the return type is void, reaching the closing brace or executing return without an expression results in a termination status code of 0. General handling of methods which end without a return value is described in section 11.3.1. Host-specific representation of termination status codes is outside the language's integer type rules. + +### 5.3. Console Output + +Output from scripts is sent to the console by the supplied CLI SAPI. The embedding API allows a host application to select an output consumer. The supplied source archive does not provide a CGI or FastCGI SAPI. + + print('Hello world from Aer'); + +The print function does not add a new line. The script author puts it in the string when required. + + print("Hello world from Aer\n"); + +### 5.4. Command-line Arguments + +The CLI accepts arguments following the script name. A string[] parameter of main receives the resulting array. + + class Program { + public void main(string[] $args) { + foreach (string $arg in $args) { + print($arg + "\n"); + } + } + } + +The CLI must preserve the host argument boundaries. The two host arguments "a b" and "c" arrive as two array elements, not three. Empty arguments remain empty elements. No joining and splitting on spaces is permitted. The Program constructor does not receive the array. The supplied CLI requires a correction to conform to this rule. + +### 5.5. Declarations + +Declarations introduce classes, interfaces, class members and local variables. Classes contain fields, constants and methods, including constructors and destructors. Local variables require a predefined type, an array type or auto with an initializer. + +Namespaces are reserved for future implementation as described in chapter 15. The supplied namespace directive is ignored with a notice and does not yet isolate identically named classes. + +Methods may share a name when they have distinct input signatures. The agreed selection rules are summarized in section 11.5 and specified in chapter 12. The supplied selector still requires the changes listed in chapter 13. + +Braces introduce a lexical block scope. A local declaration is visible in its applicable block and nested code, subject to the declaration point; it does not remain visible after that block ends. A declaration in a for initializer belongs to the loop scope and is not visible after the loop. Foreach declarations likewise belong to their loop rather than the whole method. Entering a loop body again creates a new body-block activation and new non-static variable bindings. Local constants follow the separate initialization rule in chapter 10. Duplicate declarations in one scope are errors; disjoint sequential blocks may reuse a local name. Precise rules for shadowing an outer local by an inner declaration remain to be specified separately. Persistent static storage does not make its local name visible outside the declaring block. The supplied method-wide local-variable implementation and its tests require adaptation to these rules. + +### 5.6. Aer Types + +Aer provides a set of predefined types identified through keywords: + + * bool + * callback + * char + * float + * int + * mixed + * object + * resource + * string + * void + +Appending [] declares an ordered map whose values are governed by the corresponding element-type rules. Class and interface names are not type annotations in AER#26. Use object, or the corresponding supported array form, for object-valued declarations and parameters. This restriction does not remove class/interface declarations, inheritance, new ClassName() or nominal tests such as $value is ClassName. + + int $count; + string[] $names; + mixed $value; + +The auto keyword infers the type of a variable from its initializer. It is not a type which can hold arbitrary values after initialization. Default values, NULL and implicit conversions are described in chapter 6. + +### 5.7. Variable Interpolation + +Variable interpolation is replacing variables with their values inside string literals. Other names for variable interpolation are variable substitution and variable expansion. + + int $age = 20; + print("I'm $age years old."); + +In the above example, the $age variable is replaced with the value 20 in the string enclosed by double quotes. However, this does not work if single quotes are used. Single-quoted strings also have more limited escape processing, as described in section 6.9. + +Braces may be used to delimit an interpolated member access. + + print("Hello {$this->name}\n"); + +### 5.8. Including Files + +Aer code can be split into multiple files. require loads files of script-level declarations; include(string) evaluates a fragment of method-body code. + +require is a statement written outside classes and methods, in the script declaration block. It is not a function and does not return a Boolean value. + + require 'classes.aer'; + +The required source is compiled in the script declaration context. It may provide classes and other declarations accepted there. Code valid only inside a method is not made valid at script scope by placing it in a required file. A file that cannot be opened produces an error and terminates execution. A required file containing invalid code also produces an error. + +A successful require registers the normalized file identity. Requiring that same file again emits a duplicate-require warning and skips loading and compilation; it does not declare its classes again. A failed load is not a successful require. + +include is a contextual built-in function called inside a method or anonymous function. The path is supplied using ordinary function-call syntax. + + class Program { + public void main() { + include('actions.aer'); + } + } + +The included file is compiled as a fragment of executable statements in the caller's method context. It can access the caller's available local variables and $this where applicable. It does not introduce an independent ordinary function scope. Class declarations are not accepted as method-body statements. Each successful call compiles and executes the fragment again; it is not an include-once operation. + +If the file cannot be opened, include emits a warning and execution continues after the call. This does not turn invalid syntax in an existing file or an execution error in its code into an ignored missing-file condition. The fragment has inline control-flow semantics, as if its statements occurred at the include call site. A return in that fragment returns from the enclosing method or anonymous function, using its return-type rules; it does not merely end a separate evaluation frame. The return must execute applicable finally blocks. Other control-flow operations must be resolved in the corresponding enclosing lexical context. Declarations belong to the caller's applicable block scope. Normal completion continues after the include call. The function-call spelling does not create an independent method scope or make include a function for returning source text. The success-result contract of include remains to be specified; no string-reading behavior is implied. The supplied statement implementation currently swallows fragment return and therefore requires a control-flow correction as well as the syntax change. + +Absolute paths and the configured include path keep their present resolution rules. The lookup algorithm is not changed by the distinction between require and include. There is no additional implicit caller-directory fallback. get_included_files() reports registered included paths. + +The supplied parser currently accepts require inside methods, parses include as a statement and treats a missing include file as fatal. These are implementation differences requiring the changes above. + +### 5.9. Loading Modules + +Aer modules add native functions and constants. import is a keyword introducing a statement in the script declaration block, outside classes and methods. It is not an import(string) function. + + import 'math'; + + class Program { + public void main() { + if (module_loaded('math')) { + print(sqrt(9)); + } else { + print('The math module is unavailable.'); + } + } + } + +The placement resembles a Java import declaration, but an Aer import loads a native module rather than merely introducing a shorter type name. Module search paths and platform library suffixes retain the supplied loader's resolution rules. This specification does not introduce another search path or package-discovery algorithm. + +A module is registered as loaded only after successful loading and initialization. Importing the same loaded module again emits a warning and skips initialization. It does not register its exports twice. A failed attempt does not mark the module as loaded. + +Failure to find or load a module emits a warning and execution continues. The module is not marked as successfully loaded. Code may query module_loaded() and take a fallback path; an unguarded later use of an unavailable export still produces the normal undefined-function or missing-name error. Duplicate imports also emit a warning and skip initialization. The supplied interpreter currently terminates on a missing module and requires correction. + +The planned built-in bool module_loaded(string $name) reports whether the module has completed successful initialization in the current VM. It does not load the module or invoke its exports. It returns FALSE for an unknown module or an unsuccessful load. The same module identity rules are used for import, duplicate detection and this query. + +The supplied modules include dummy, math, ctype, json and xml. Presence of a module or a registered function is not proof of correctness for every operation it exposes. + +## 6. Data Types & Pseudo Types + +### 6.1. Boolean Values + +The bool type represents TRUE and FALSE. Numeric zero converts to FALSE and non-zero numeric values convert to TRUE. An empty array is false; a non-empty array is true. An object without an instance is false; object conversion may use __toBool(). + +For strings, the empty string, strings consisting entirely of zero digits, and the word 'false' regardless of ASCII letter case convert to FALSE. Other tested strings, including 'off', 'no' and '0.0', convert to TRUE. + + var_dump((bool) '000'); // FALSE + var_dump((bool) 'FALSE'); // FALSE + var_dump((bool) 'off'); // TRUE + +The Boolean conversion is different from the emptiness test used by ??; 'false' is not empty for that operator. + +### 6.2. Callback Values + +Callbacks can be denoted in Aer using the callback type. It is used for anonymous functions and other callable values. + + callback $callme = int() { + return 7; + }; + int $var = $callme(); // value is 7 + +A string naming a callable built-in function may be assigned to a callback variable. + + callback $echo = 'print'; + $echo('Hello world'); + +The existence and accessibility of the target must be checked when it is invoked. Callback values may also be stored in callback[] arrays. Capture of an enclosing environment is described in section 9.2. + +### 6.3. Character Values + +A char value uses the supplied interpreter's integer-backed representation. The default value is zero. An integer can be assigned to char; this does not establish Unicode decoding or a restriction to a single-byte integer range. + +An empty string or a string containing one byte may be assigned to char. Assigning 'A' is accepted. Assigning the UTF-8 string 'ą' is rejected because it contains two bytes. Integer values such as 256 are retained internally, while conversion to text and character output are byte-oriented. A char is not a complete UTF-8 character, a UTF-16 code unit or a Unicode scalar-value type. + +AER#26 retains this behavior. It does not introduce wchar_t storage, UTF-16 strings or automatic UTF-8 character decoding. Ordinary string indexing and strlen() continue to operate on bytes. + +### 6.4. Floating-point Values + +Aer supports one floating-point type. The float type uses 64-bit double-precision representation, with approximately 15-16 significant decimal digits. The largest finite positive value is approximately 1.7976931348623157 × 10^308; the smallest positive subnormal value is approximately 4.9406564584124654 × 10^-324. Negative values are also supported. + + float $value = 5.0; + +An integer may be converted implicitly to float. This conversion does not guarantee preservation of every 64-bit integer: sufficiently large integers cannot be represented exactly in double precision. Rules for exceptional arithmetic values remain to be completed. + +### 6.5. Integer Values + +Aer has standardized integers, stored in 8 bytes (64 bits) regardless of the host environment. The int type can store values between -9223372036854775808 and +9223372036854775807 inclusive. + + int $value = 5; + +An integer literal such as 5 has type int. A real literal such as 5.0 has type float. This distinction is used when selecting an overloaded method. Integer arithmetic whose result type is int wraps to 64 bits. The result retains its least significant 64 bits and is interpreted as a signed two's-complement value. For example, incrementing 9223372036854775807 produces -9223372036854775808. Overflow does not by itself produce an error, a warning or an implicit float value. This rule must be implemented explicitly and consistently; it must not rely on undefined signed overflow in the interpreter's host language. Division-by-zero and other invalid operations are separate conditions. The supplied formatter has an independent minimum-int64 defect listed in chapter 13. + +### 6.6. Mixed Values + +The mixed type indicates that a variable may hold values of different non-array types. It can be used in variable declarations, parameters and return declarations. + + mixed $var; + $var = NULL; + $var = 'Test'; + var_dump($var); + $var = 7; + var_dump($var); + +A mixed variable may hold an object or callback as well as scalar values. An array is not assigned directly to scalar mixed; mixed[] is used for a collection with heterogeneous values. + +The type of the currently stored value is used when a mixed value participates in an overloaded call. Declaring mixed does not disable the type requirements of the method which is selected. + +### 6.7. Object Values + +An object value holds a managed reference to an object instance. + + object $system; + $system = new System(); + +The default object value does not refer to an instance. Accessing an instance member requires an instantiated object. Assigning an object value to another object variable shares the instance; it does not create a second independent object. + +Use object for object-valued locals, fields, parameters and method results. Class and interface identifiers are not accepted as type annotations in AER#26. The supplied compiler currently accepts some named parameter annotations, but that partial legacy behavior is not an AER#26 feature and must be rejected consistently. The is operator continues to test the actual object against class and interface relationships; removing named annotations does not remove nominal ancestry. + +### 6.8. Resource Values + +A resource is a special value holding a handle to an external resource, such as an opened file or database connection. Resources are created and used by built-in or module functions. + +The default resource value is an empty handle. A resource is not a C pointer exposed for arithmetic. The functions providing a resource define how it is explicitly closed and what operations are valid after closing. + +### 6.9. String Values + +A string is a sequence of bytes, which may contain UTF-8 text. The simplest way to specify a string is to enclose it in single quotes. To specify a literal single quote, escape it with a backslash. To specify a literal backslash, double it. All other instances of backslash will be treated as a literal backslash: this means that the other escape sequences you might be used to, such as \r or \n, will be output literally as specified rather than having any special meaning. +If the string is enclosed in double-quotes, Aer will interpret the following escape sequences for special characters: + + * `\'` - single quote + * `\"` - double quote + * `\\` - backslash + * `\$` - dollar sign + * `\0` - the zero byte when not followed by further octal digits + * `\a` - alert + * `\b` - backspace + * `\e` - escape, byte 0x1B + * `\f` - form feed + * `\n` - new line + * `\r` - carriage return + * `\t` - horizontal tab + * `\v` - vertical tab + * `\x` followed by one or two hexadecimal digits - a byte in hexadecimal notation; "\x4" produces byte 0x04 and "\x41" produces A + * `\` followed by one to three octal digits - a byte in classic octal notation; "\101" produces A + * `\d{65}` - a byte in decimal notation; this example produces A + * `\b{1000001}` - a byte in binary notation; this example produces A + * `\o{101}` - a byte in octal notation; this example produces A + * `\x{41}` - a byte in hexadecimal notation; this example produces A + +When a string is specified in double quotes, variables are also parsed within it. Unknown escapes drop the backslash in the supplied decoder. AER#26 restores \e as ESC and accepts one or two hexadecimal digits after an unbraced \x. No hexadecimal digit after \x produces a diagnostic. The supplied decoder instead emits e for \e and byte 0x40 for \x4; it requires correction. + +The braced forms use one or more digits in their stated base and require a closing brace. Empty contents and digits outside that base produce a diagnostic. Braces distinguish binary \b{...} from the backspace escape \b. Classic \x41 and \101 are retained alongside the uniform braced forms. The supplied unbraced \o101 spelling is replaced by \101 or \o{101}. These forms describe byte values, not Unicode code points. Their agreed examples lie in the byte range. The handling of numeric escape values outside 0 through 255 remains an undecided decoder detail; no wider character encoding is introduced by this syntax. + +Ordinary string indexing and strlen() operate on bytes. For example, the UTF-8 text "ą" occupies two bytes. A script which needs to count Unicode code points must use an appropriate text operation rather than assume that strlen() counts written characters. + +### 6.10. Void Values + +Void is an empty data type. It is used as the return type of functions and methods which return no value. It is also possible to declare a variable of void type. + + void $empty; + +A void variable can hold only its empty value. It cannot later become an integer, string or another non-empty type. A void method or anonymous function must not execute return with a value. + +### 6.11. Null Values + +NULL denotes the absence of a supplied value. When assigned to a typed variable, it establishes that type's default value rather than introducing a second stored type. + + int $count = 7; + string $name = 'Aer'; + $count = NULL; // int value 0 + $name = NULL; // string value '' + +Variables declared without an initializer also receive their type's default value. + +| Declared type | Default value | +|---------------|---------------| +| bool | FALSE | +| char | Zero character value | +| float | 0.0 | +| int | 0 | +| string | Empty string | +| object | No instance | +| resource | Empty handle | +| callback | No callable target | +| void | Empty void value | +| mixed | Empty value, represented as void | +| T[] | Empty ordered map with the declared element type | + +For the NULL coalescing operator, the following values are empty: + + * NULL and void values; + * FALSE; + * Zero int, char and float values; + * Empty strings and strings consisting entirely of the digit 0; + * Empty arrays; + * Objects with no instance and resources with an empty handle; + * Callback values with no target. A callback containing a target, including an anonymous function, is not empty. The test does not invoke the callback or execute target validation; ordinary target checks still apply when it is called. + +The string 'false' is not empty under these rules. This empty-value test must not be replaced by a general Boolean conversion. + + int $value = 0 ?? 7; // value is 7 + string $text = '000' ?? 'Aer'; // text is 'Aer' + +unset() is available for removing values or array entries. It does not establish a dynamic type-changing declaration rule. + +### 6.12. Arrays + +Array is a complex data type which handles a collection of elements. Each element can be accessed by a key. An array in Aer is an ordered map, associating keys with values and preserving an iteration order. It may be used as a list, dictionary, collection, stack or queue. + +The notation T[] describes the type of the non-array values stored in the map. It does not restrict the map to one dimension. Nested maps are permitted when their non-array values satisfy the same element-type rules. + + int[] $arr1; + int[] $arr2 = {0, 0}; + $arr1 = {1, 2, 3, 4, 5}; + $arr1[] = 6; + $arr1[] = {7}; + $arr1[] = {'test' => 8}; + $arr1[] = $arr2; + +Above example creates nine outer elements. The elements at keys 6, 7 and 8 are nested arrays. Appending an array does not flatten it or merge its keys into the outer array. + + $arr1[6][0] // int value 7 + $arr1[7]['test'] // int value 8 + $arr1[8][0] // int value 0 + +A recursive array remains governed by its element type: + + int[] $tree = {1, {2, {3}}}; + // $tree[] = {'text'}; // Error: incompatible non-array value + +The element type does not specify the key type. Integer and string keys may be used. When compatible integers are stored in float[], conversion to float applies to the non-array values, including values in nested maps. + + float[] $values = {1, {2, 3.5}}; + mixed[] $items = {1, 'Aer', TRUE}; + +Ordinary array assignment provides value behavior: modifying an element in an assigned array does not by itself modify the source array. This does not imply deep cloning of objects held inside arrays. + +Integer key 1, string key '1' and Boolean TRUE address the same entry in tested maps; the string '01' remains distinct. An automatic appended numeric key advances beyond the numeric high-water mark: deleting the former largest entry does not force its key to be reused. Reading a missing element produces an error rather than an implicit NULL. Mutation during traversal has not been exhaustively verified. + +### 6.13. Type Casting + +Type casting in Aer uses the name of the desired type in parentheses before an expression: + + * (bool) - casts to Boolean; + * (char) - casts to Character; + * (float) - casts to Float; + * (int) - casts to Integer; + * (object) - casts to Object; + * (string) - casts to String; + * (callback) - casts to Callback; + * (resource) - casts to Resource; + * (void) - casts to the empty void value. + + string $str = "45"; + int $integer = 7 + (int) $str; // contains value 52 + +An explicit cast requests a conversion which ordinary assignment may reject. It does not change the declared type of an existing variable. Complete conversion results for malformed strings, out-of-range values and complex objects remain to be specified. + +### 6.14. References + +References in Aer are a means to access the same variable content by different names. They are not like C pointers: they do not provide pointer arithmetic or expose actual memory addresses. A reference aliases an existing storage location and remains subject to the type rules of that location. + +#### 6.14.1. Pass By Reference + +A parameter declared with & refers to the caller's storage rather than a separate local value. + + class Program { + private void add(int &$value) { + $value += 7; + } + + public void main() { + int $number = 7; + $this->add($number); + print($number); // outputs 14 + } + } + +Passing by reference does not permit storing an incompatible value in the caller's variable. The agreed signature rules include the passing mode. The supplied selector still requires the corresponding compatibility checks. + +### 6.15. Implicitly Typed Variables + +The auto keyword declares a variable whose type is inferred from its initializer. After initialization, that type is fixed. + + auto $count = 5; // int + auto $ratio = 5.0; // float + auto $name = 'Aer'; // string + auto $empty = NULL; // void + +It is an error to assign 'text' to $count merely because it was declared using auto. It is also an error to assign 7 to $empty. Inferring void from NULL is a deliberate language rule, not an inference failure and not an implicit declaration of int. + +### 6.16. Assignment Compatibility + +A value must satisfy the declared type of its destination. Exact type matches are accepted. The following implicit scalar conversions are also supported: + + * int to float; + * int to char; + * char to string; + * An empty or one-byte string to char; + * A string to callback. + +NULL establishes the destination's default value. Array assignment applies the corresponding element compatibility recursively. The mixed and object types have the behavior described in their own sections. + + float $ratio = 5; // accepted, value becomes float + // int $count = '5'; // Error + // int $count = 5.0; // Error + // string $text = 5; // Error + +An int-to-float conversion may lose precision for a sufficiently large integer. Compatibility does not mean every allowed conversion is exact. Overload selection prefers an exact compatible type match to an implicit conversion, as required by chapter 12. The supplied selector does not yet implement the complete rule. + +## 7. Operators + +Expressions are constructed from operands and operators. The operators of an expression indicate which operations to apply to the operands. There are three kinds of operators: + + * Unary operators - the unary operators take one operand and use either prefix notation (such as -$x) or +postfix notation (such as $x++), + + * Binary operators - the binary operators take two operands and all use infix notation (such as $x + $y), + * Ternary operator. Only one ternary operator, ?:, exists; it takes three operands and uses infix notation +(c ? x : y). +Precedence and associativity determine how operands and operators form an expression. They do not, by themselves, establish the execution order of operands or require an unused operand to be evaluated. + +### 7.1. Operator Precedence + +When an expression contains multiple operators, the precedence of the operators controls how its operands and subexpressions are grouped. The precedence of an operator is established by the definition of its associated grammar production. The following list shows common AerScript operators ordered by precedence (highest precedence first): + +| Precedence | Description | Operator | Associativity | +|------------|-----------------------|------------------|-------------------| +| 1 | object-related | clone new | non-associative | +| 2 | postfix operators | -> :: [ ( | left-associative | +| 3 | increment / decrement | ++ -- | non-associative | +| 4 | unary operators | - + ~ ! | right-associative | +| 4 | cast operators | (type) | right-associative | +| 5 | object-related | is | non-associative | +| 6 | arithmetic operators | ** | right-associative | +| 7 | arithmetic operators | * / % | left-associative | +| 8 | arithmetic operators | + - | left-associative | +| 9 | bitwise operators | << >> | left-associative | +| 10 | comparison | < <= > >= | non-associative | +| 11 | comparison | == != | non-associative | +| 12 | bitwise and | & | left-associative | +| 13 | bitwise xor | ^ | left-associative | +| 14 | bitwise or | \| | left-associative | +| 15 | logical and | && | left-associative | +| 16 | logical xor | ^^ | left-associative | +| 17 | logical or | \|\| | left-associative | +| 18 | NULL coalescing | ?? | right-associative | +| 19 | ternary operator | ? : | right-associative | +| 20 | assignment operators | = += -= *= /= %= **= | right-associative | +| 20 | assignment operators | &= \|= ^= <<= >>= | right-associative | +| 23 | comma expression | , | left-associative | + +### 7.2. Associativity Rule + +Sometimes precedence is not sufficient to determine how an expression is grouped. Associativity determines the grouping of operators with the same precedence. + + 9 / 3 * 3 + +The multiplication, division and modulo operators associate left-to-right. Above expression is grouped as (9 / 3) * 3, and its result is 9. + +Exponentiation, assignment, NULL coalescing and the ternary operator associate right-to-left. For example: + + $a ?? $b ?? $c + +is grouped as: + + $a ?? ($b ?? $c) + +Grouping is separate from execution. NULL coalescing evaluates its left operand first and evaluates its right operand only when the left value is empty, as specified in section 7.11. + +### 7.3. Assignment Operator + +The assignment operator = assigns a value to an existing variable or another writable location. The value must satisfy the destination's type. + + int $x; + $x = 1; + +Assignment associates right-to-left. Assigning an object shares its instance; assigning an array has the value behavior described in section 6.12. + +### 7.4. Arithmetic Operators + +Aer offers the following arithmetic operators: + + * Addition: + + * Subtraction: - + * Multiplication: * + * Division: / + * Modulo: % + * Exponentiation: ** + +Division produces float even when the division is exact: 4 / 2 is float 2.0. The tested -5 % 2 is int -1. Division by zero produces an error. Unary minus binds more tightly than exponentiation, so -2 ** 2 evaluates to 4. Exponentiation groups right-to-left, so 2 ** 3 ** 2 evaluates to 512. + +### 7.5. Concatenating Strings + +In Aer, concatenating strings uses the addition operator. + + string $str = "Hello" + ' ' + 'World!'; + +If either operand of binary + is a string, the operation concatenates string representations rather than interpreting that string as a number. + + mixed $value = 5 + '10'; + print($value); // outputs 510 + +Explicit casts should be used when numeric addition is intended for text containing a number. Conversion of a result to its destination remains subject to assignment compatibility. + +### 7.6. Boolean Operators + +Aer provides logical and (&&), or (||), xor (^^) and negation (!). Operands are interpreted according to Boolean conversion. + +The && and || operators use short-circuit evaluation. The left operand is evaluated first. For &&, a false left operand determines the result without evaluating the right operand. For ||, a true left operand determines the result without evaluating the right operand. + + FALSE && print('not called'); + TRUE || print('not called'); + +Logical xor needs both operand values. The Boolean operators produce Boolean results. + +### 7.7. Relational Operators + +Aer provides <, <=, >, >=, == and !=. Comparisons produce Boolean values. Equality is coercive; it does not require identical operand types. + + var_dump(1 == '1'); // TRUE + var_dump(1 == 1.0); // TRUE + var_dump(0 == NULL); // TRUE + var_dump('0' == NULL); // TRUE + +Type tests use is, described in section 11.16. + +### 7.8. Bitwise Operators + +Decimal numbers are natural to humans. Binary numbers are native to computers. Binary, octal, decimal or hexadecimal symbols are only notations of a number. Bitwise operators work with bits of a binary number. Aer also have binary logical operators and shift operators: + + * bitwise negation: ~ + * bitwise exclusive or (xor): ^ + * bitwise and: & + * bitwise or: | + * left shift: << + * right shift: >> + +### 7.9. Compound Assignment Operators + +Compound assignment operators combine an operation and assignment: + + += -= *= /= %= **= &= |= ^= <<= >>= + +The resulting value must remain compatible with the destination's declared type. A compound operation does not turn a typed variable into mixed. + +### 7.10. Ternary Operator + +The ternary operator selects one of two expressions according to a Boolean condition: + + condition ? first : second + +The condition is evaluated first. Only the selected expression is evaluated. The operator associates right-to-left. + + string $value = TRUE ? 'true' : FALSE ? 't' : 'f'; + print($value); // outputs true + +The expression is grouped as TRUE ? 'true' : (FALSE ? 't' : 'f'). Parentheses may still be used to improve readability. + +### 7.11. NULL Coalescing Operator + +The ?? operator selects a replacement for an empty value, using the emptiness rules in section 6.11. It uses short-circuit evaluation. + + int $count = 0 ?? 7; // 7 + string $code = '000' ?? 'fallback'; // fallback + string $word = 'false' ?? 'fallback'; // false + +The left operand is evaluated exactly once. If its value is not empty, that value is the result and the right operand is not evaluated. Otherwise, the right operand is evaluated exactly once and supplies the result. The selected value keeps its type; assignment compatibility is checked afterwards. + + int $value = 1 ?? $this->loadFallback(); + +In this example, loadFallback() is not called. Its side effects, errors and exceptions do not occur. If the left value were 0, the fallback would be evaluated. + +The operator associates right-to-left. Thus $a ?? $b ?? $c is grouped as $a ?? ($b ?? $c), but begins by evaluating $a. If $a is non-empty, neither $b nor $c is evaluated. If $a is empty and $b is non-empty, $c is not evaluated. If both are empty, $c supplies the result, even if it is itself empty. + +This is an agreed AER#26 requirement. The supplied interpreter evaluates both operands and requires a code change to conform. Its treatment of all callbacks as empty must also be corrected to the agreed callback rule in section 6.11. + +### 7.12. Comma Operator + +The comma operator evaluates its left operand and then its right operand, exactly once each. The left value is discarded. The right value supplies the result of the expression, retaining its type. A chain groups left-to-right, and its operands are evaluated in written order. Comma has lower precedence than assignment. + + int $number = (1, 2); // 2 + + int $i = 0; + int $j = 9; + for ($i = 0, $j = 9; $i < $j; $i++, $j--) { + print($i + ':' + $j + "\n"); + } + +The operator is supported in expression contexts, including for initialization and update. Parentheses distinguish one comma expression from a list of arguments or elements: $this->f(($a, $b)) passes one result, whereas $this->f($a, $b) passes two arguments. Commas separating variable declarations or array entries keep their grammatical separator role. + +This requirement does not independently make a comma result a writable reference or an assignment destination. The supplied executable crashes on tested comma expressions and requires a compiler/VM repair; these examples describe the corrected language behavior. + +## 8. Flow Control + +### 8.1. If Statement + +The if statement has the following general form: + + if (expression) + statement + +The if keyword is used to check if an expression is true. If it is true, a statement is then executed. The statement can be a single statement or a compound statement. A compound statement consists of multiple statements enclosed by curly brackets. + +Often there is a need to execute a statement if a certain condition is met, and a different statement if the condition is not met. This is what else is for. Else extends an if statement to execute a statement in case the expression in the if statement evaluates to FALSE. For example, the following code would display a is greater than b if $a is greater than $b, and a is NOT greater than b otherwise: + + if ($a > $b) { + print("a is greater than b"); + } else { + print("a is NOT greater than b"); + } + +### 8.2. Switch Statement + +The switch statement is a selection control flow statement. It allows the value of a variable or expression to control the flow of program execution via a multiway branch. It creates multiple branches in a simpler way than using the if and else if statements. The switch statement works with two other keywords: case and break. The case keyword is used to test a label against a value from the round brackets. If the label equals to the value, the statement following the case is executed. The break keyword is used to jump out of the switch statement. There is an optional default statement. If none of the labels equals the value, the default statement is executed. + + string $domain = 'de'; + switch ($domain) { + case 'us': + print("United States\n"); + break; + case 'de': + print("Germany\n"); + break; + case 'sk': + print("Slovakia\n"); + break; + case 'pl': + print("Poland\n"); + break; + default: + print("Other\n"); + break; + } + +### 8.3. While Loop + +The while is a control flow statement that allows code to be executed repeatedly based on a given boolean condition. This is the general form of the while loop: + + while (expression) + statement + +The while loop executes the statement when the expression is evaluated to true. The statement is a simple statement terminated by a semicolon or a compound statement enclosed in curly brackets. + + int $i = 0; + while ($i < 5) { + print("Aer Language\n"); + $i++; + } + +### 8.4. Do-While Loop + +The do while loop is a version of the while loop. The difference is that this version is guaranteed to run at least once. + + int $count = 0; + do { + print("$count\n"); + } while ($count != 0); + +In the above example, first the iteration is executed and then the truth expression is evaluated. + +### 8.5. For Loop + +The for loop does the same thing as the while loop. Only it puts all three phases, initialization, testing and updating into one place, between the round brackets. It is mainly used when the number of iterations is known before entering the loop. + + string[] $days = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", + "Saturday", "Sunday" }; + int $len = sizeof($days); + + for (int $i = 0; $i < $len; $i++) { + print("$days[$i]\n"); + } + +The three phases are divided by semicolons. First, the $i counter is initiated. The initiation part takes place only once. Next, the test is conducted. If the result of the test is true, the statement is executed. Finally, the counter is incremented. This is one cycle. The for loop iterates until the test expression is false. + +### 8.6. Foreach Loop + +The foreach construct simplifies traversing over collections of data. It has no explicit counter. The foreach statement goes through the array one by one and the current value is copied to a variable defined in the construct. In Aer, it can be used to traverse over an array. + + string[] $days = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", + "Saturday", "Sunday" }; + string $day; + foreach ($day in $days) { + print("$day\n"); + } + +The usage of the foreach statement is straightforward. The $days is the array that gets iterated through. The $day is the temporary variable that has the current value from the array. The foreach statement goes through all the days and prints them to the console. + +The iteration variables may also be declared in the loop, for example foreach (int $key => int $value in $items). These declarations belong to the loop scope. A later separate loop may declare the same names again. Non-static declarations in the body have a fresh binding on each body entry. + +There is another syntax of the foreach statement. Below form will additionally assign the current element's key to the $key variable on each iteration. + + string[] $benelux = { 'be' => 'Belgium', 'lu' => 'Luxembourg', 'nl' => 'Netherlands' }; + string $key, $value; + foreach ($key => $value in $benelux) { + print("$key is $value\n"); + } + +### 8.7. Break & Continue Statements + +The break statement is used to terminate the loop. The continue statement is used to skip a part of the loop and continue with the next iteration of the loop. + + int $val; + while (true) { + $val = rand(1, 30); + print("$val "); + if ($val == 22) { + break; + } + } + +In the above example, an endless loop has been defined. The break statement exits it when the chosen value is reached. Above code assigns a random value from 1 to 30 and prints it. If the value equals to 22, script finishes the endless while loop. + + int $num = 0; + while ($num < 1000) { + $num++; + if (($num % 2) == 0) + continue; + print("$num "); + } + +Above example prints a list of numbers that cannot be divided by 2 without a remainder, during a while loop, which iterates through numbers from 1 to 1000. The value 1000 is skipped because it is even. + +### 8.8. Goto Statement + +The goto statement transfers control to a named label in the same method or anonymous function. + + int $count = 0; + repeat: + print($count + "\n"); + $count++; + if ($count < 3) { + goto repeat; + } + +Above example prints 0, 1 and 2. A label is an identifier followed by a colon. A jump cannot transfer execution to another method. The compiler rejects goto inside a try/catch region. No cross-method jump is provided. + +## 9. Functions + +Aer organizes user-defined named methods inside classes. It also provides built-in functions and anonymous functions. Built-in functions may provide operations such as output, string handling and array processing. + +### 9.1. Anonymous Functions + +Anonymous functions allow the creation of functions which have no specified name. Their arguments have declared types and may take default values, just like method arguments. A default value may be a complex expression, including a function or method call. + + callback $anon = void(string $message = 'Hello' + ' ' + 'World!') { + print($message + "\n"); + }; + $anon(); // outputs Hello World! + $anon('Welcome guest!'); // outputs Welcome guest! + +The semicolon is required because the function is part of a variable declaration. Explicit returned values are checked against the declared return type whether or not variables are captured. Capture must not disable normal result compatibility. The supplied capturing-closure instantiation loses the type information and needs correction. The separate missing-return warning/NULL rule remains applicable. + +As in AER#19, anonymous return declarations use the supported predefined type forms. Use object for an object result. Class/interface names are not annotation types in AER#26. Array-result syntax for anonymous functions is not added by this decision; it remains outside the supported anonymous-result forms. + +### 9.2. Closures + +A closure is an anonymous function which captures values or storage from its enclosing scope. Captures are listed after using. A name without & captures its value; a name prefixed with & captures a reference to the enclosing variable's storage. + + int $value = 1; + callback $copy = int() using ($value) { + return $value; + }; + callback $reference = int() using (&$value) { + return ++$value; + }; + + $value = 9; + var_dump($copy()); // 1 + var_dump($reference()); // 10 + var_dump($value); // 10 + +A value capture takes its snapshot when the closure is created. For scalar captures, modifications in an invocation do not write back to the enclosing variable. A later invocation again starts from that captured scalar value. Capturing an object by value copies its object reference, not a deep clone of its instance. + +A reference capture aliases the original storage. Changes through the capture are visible through the outer variable, and changes through the outer variable are visible to the closure. Several closures capturing the same binding by reference share it. Assignments through that alias remain subject to the binding's declared type. A capture remains associated with that binding rather than a later, unrelated declaration that happens to reuse its name. + +A closure may be returned and invoked after the enclosing call or block has ended. Captured storage must therefore remain alive for as long as an escaping closure needs it; an implementation must not leave a pointer to released stack storage. This is consistent with lexical block scope: ending visibility of a name does not invalidate a retained captured binding. + +A closure created in an instance method may use the enclosing $this. Value capture, reference capture and invocation all preserve the appropriate object and access context. Capturing variables does not change the closure's declared return contract. The supplied implementation requires new reference-capture support and correction of result-type propagation. + +## 10. Static Variables & Constants + +Aer permits local static variables and local constants with expression initializers. The declarations use different evaluation rules. + + class Program { + private void test() { + static int $salt = rand() & 0x3FF; + print($salt++ + "\n"); + } + + public void main() { + const MY_CONST = rand(); + $this->test(); + $this->test(); + var_dump(MY_CONST, MY_CONST); + } + } + +The static local is initialized on its first use and retained for subsequent calls. A local const has no explicit type keyword. Its initializer is evaluated when the declaration is first executed, and every read of that constant uses the established value. A second execution of the same constant declaration during the same enclosing method or anonymous-function invocation is an attempt to reinitialize a constant. It produces a fatal diagnostic and terminates script execution. This also applies when a loop enters the declaring block again. A new method invocation has its own local constants. The constant name remains visible only in its lexical scope; this initialization rule does not extend its visibility outside that scope. + +For example, the following code prints 1 and 1 during the first iteration, then terminates with a constant-reinitialization error during the second iteration: + + int $counter = 0; + for (int $i = 0; $i < 2; $i++) { + const VALUE = ++$counter; + var_dump(VALUE, VALUE); + } + +VALUE is not visible after the loop body. Repeated reads must not reevaluate its initializer. The supplied executable reevaluates some local initializers on read and does not reliably resolve constants inside loops; both issues require correction to implement this rule. + +At script scope, define NAME value; declares a global constant using a simple constant value. It is not define(NAME, value). A call such as rand() is not accepted as a global define value. A script-level const declaration is rejected. + +Class constants use untyped const syntax and are described in section 11.13. A static local has persistent storage associated with its declaration, while its name follows the declaring block's scope. A static class field belongs to its class. No broader guarantee about recursive initialization, failed initialization or shutdown ordering has been verified. + +## 11. Object-Oriented Programming + +Aer organizes named user-defined operations in classes. Classes provide fields, methods, constructors, destructors, visibility and inheritance. This chapter uses the agreed AER#26 inheritance rules detailed in chapter 12. The corresponding implementation changes are pending; chapter 13 records the supplied executable's deviations. + +### 11.1. Objects in AerScript + +An object is created using new and a class name. Assigning an object shares the instance. clone creates another instance and invokes __clone() when provided; it does not imply a recursive clone of all referenced objects. + + class Item { + public int $value = 1; + } + + object $first = new Item(); + object $second = clone $first; + $second->value = 2; + print($first->value); // 1 + +### 11.2. Object Attributes + +Fields are declared with a predefined type or array type and a variable name. A field may have an initializer and an access modifier. Instance fields are accessed using ->; static fields use :: followed by $ and the name. + + class Item { + public int $value = 0; + private string $name = 'Aer'; + public static int $count = 0; + } + +An inherited field retains its declaring identity. A shared ancestor reached through a diamond supplies one field per object. Independent public or protected fields with the same name are conflicts; private fields of different classes remain separate. The same declaration-identity and conflict rules apply to static fields and constants, as detailed in chapter 12. + +### 11.3. Methods + +Methods are functions declared inside a class. Their parameters and return values use declared types. $this accesses the current object. + + class Circle { + private float $radius; + + public void setRadius(float $radius) { + $this->radius = $radius; + } + + public float area() { + return $this->radius * $this->radius * 3.14; + } + } + +#### 11.3.1. Return Keyword + +return transfers control to the caller. An explicit returned expression is checked against the method's declared type, allowing normal assignment conversions. A void method cannot return a value. A non-void method that reaches its end without return emits a warning and produces NULL. It does not turn the missing result into a hard error. Subsequent assignment applies the normal NULL/default rules; assigning the result to int therefore establishes 0. The supplied interpreter already returns NULL but needs the missing warning. This exception for an absent result does not permit an explicitly returned incompatible non-NULL value. + +#### 11.3.2. Method Arguments + +Parameters require supported predefined or array types. Object-valued parameters use object; class and interface names are not annotation types in AER#26. The actual object may still be inspected using is. Extra positional arguments are rejected by ordinary method calls. Reference parameters are described in section 6.14. + +#### 11.3.3. Default Argument Values + +Parameters may have defaults, including expressions and calls. A default expression is evaluated only when its argument is omitted. An explicitly supplied NULL is an argument and must not evaluate the parameter's declared default. It is handled by the normal NULL/default-of-type compatibility rules; for an int parameter it establishes 0, not the declared optional argument value. + + public int next(int $value = rand()) { + return $value; + } + +An applicable overload must accept every supplied argument and provide defaults for every omitted parameter. Explicit NULL counts as supplied and is checked using the normal compatibility rules; selection does not turn it into an omitted argument. Candidate selection does not evaluate defaults. Full selection rules are given in chapter 12. + +### 11.4. Access Modifiers + +Aer provides public, protected and private. Public members may be used by external callers. Protected members are available in the applicable class and derived context. Private members are restricted by the interpreter's class access checks. A class member without an explicit access modifier defaults to private. + + class Item { + public int $value; + protected string $text; + private int $identifier; + } + +A method retains its declaring-class access context while $this remains the actual object. Private declarations in unrelated classes remain distinct. An override must not reduce required public or protected visibility; MRO does not grant access to an otherwise inaccessible member. These are requirements of chapter 12, awaiting the inheritance implementation change. + +### 11.5. Method Overloading + +Methods with distinct input signatures form an overload set. The input signature contains the name, ordered parameter types and passing modes. The return type, parameter names and default values do not create additional overloads. Two implementations with the same input signature cannot be declared directly in one class. + + public int count(int $a, int $b) { + return $a + $b; + } + + public float count(float $a, float $b) { + return $a + $b; + } + +An int call prefers the int overload to an int-to-float conversion; a float call selects the float overload. All supplied arguments are considered. An expected destination type does not participate in selection. + +Distinct signatures inherited from different bases remain available. For the same signature, MRO chooses the effective declaration without examining its return type. The selected result is then subject to ordinary return and assignment checks. Interface and final constraints still apply. + +Chapter 12 defines applicability, parameter specificity, optional arguments and ambiguity. Its complete selection rules replace the supplied prefix-based selector; they are agreed requirements, not a claim that the current executable already implements them. + +### 11.6. Constructors & Destructors + +A constructor named __construct is called when an instance is created. A destructor named __destruct is used when an instance is released. Both normally declare void. A constructor with restricted visibility can be called through an accessible class factory. + + class Item { + private void __construct() { + } + + public static object create() { + return new Item(); + } + } + +A derived constructor can explicitly call $parent->__construct(). Base constructor chaining is not an automatic traversal of every base. Exact object-release order, reference cycles and exceptional destructor behavior are not specified as verified guarantees in this draft. + +### 11.7. Constructor Overloading + +Several __construct declarations may accept different parameter lists. Ordinary construction uses the agreed method overload rules. The supplied machinery requires the same selector corrections as other method calls. Program startup is special and passes no arguments to its constructor. + +### 11.8. Scope Resolution Operator + +The operator :: accesses a class context, including class constants and static fields and methods. self denotes the relevant declaring class context. + + class Utility { + public static void show() { + print('Aer'); + } + } + + Utility::show(); + +A class-name call without an instance requires a static method. A non-static method is called on an object using ->; class-call syntax must not create an implicit instance or silently invoke an instance method without one. The supplied interpreter currently accepts such calls and requires correction. + +$this refers to the object during instance execution. $parent continues lookup after the executing method's declaring class in the actual object's MRO, as detailed in chapter 12. + +### 11.9. Inheritance + +A class inherits using extends. A class cannot extend a final class, and extends cannot name an interface. Interfaces are attached using implements. + + class Base { + public void show() { + print('Base'); + } + } + + class Derived extends Base {} + +AER#26 uses C3 linearization. The actual class of $this remains the derived class while a base method executes. Access and self retain their declaring context. Class and interface relationships are transitive, including secondary bases. Chapter 12 specifies the complete rules. + +### 11.10. Multiple Inheritance + +Several bases may be named in order after extends. + + class First { + public void first() { + print('First'); + } + } + + class Second { + public void second() { + print('Second'); + } + } + + class Combined extends First, Second {} + +The order after extends is significant. C3 produces one consistent MRO with each ancestor appearing once; an inconsistent hierarchy is an error. Methods are collected by input signature, shared ancestor declarations keep one identity, and independent visible field or constant conflicts are rejected. $parent follows the remaining MRO rather than always selecting the first direct base. Chapter 12 provides the algorithm, constraints and examples. + +### 11.11. Virtual Classes & Methods + +virtual marks a class that cannot be instantiated, or a method declared without a body. + + virtual class Drawing { + public virtual float area(); + } + + class Square extends Drawing { + public float area() { + return 4.0; + } + } + +A virtual derived class may leave compatible virtual or interface obligations for a later class. Every concrete class must provide effective implementations for all remaining obligations. An inherited implementation may satisfy a requirement. These agreed rules replace the current loader's immediate-child restriction. The word abstract is not accepted as an alternative keyword. + +### 11.12. Magic Methods + +The supplied interpreter implements conversion hooks __toInt(), __toFloat(), __toBool() and __toString(), and invokes __clone() when cloning. __construct() and __destruct() provide the lifecycle hooks described above. + +An object may define __invoke() and be called using function-call notation. Supplied arguments are passed to the selected method using normal overload, default, reference and type rules. Its return value is the result of the object-call expression. + + class CallableValue { + public int __invoke(int $value = 7) { + return $value; + } + } + + object $callable = new CallableValue(); + var_dump($callable(42)); // 42 + var_dump($callable()); // 7 + +The supplied object-call path currently drops arguments and results and must be corrected. No separate weaker type or argument rules apply to an object invocation. + +### 11.13. Class Constants + +Class constants belong to a class rather than an instance. They have untyped const syntax. + + class Math { + public const PI = 3.14159265359; + + public float getPI() { + return self::PI; + } + } + +The typed declaration public const float PI is rejected. Class constant values are initialized and reused; a random initializer is not reevaluated on every read as a local const is. Access uses ClassName::NAME or self::NAME. Attempting assignment produces a warning and does not provide a writable field. + +Interfaces may also declare untyped constants, accessed through the interface name. The tested implementation does not make an interface's constant available as a class constant merely because the class implements that interface. Conflicts and declaration identity for inherited class constants follow the agreed rules in chapter 12. + +### 11.14. Static Keyword + +static is used for class fields and methods and for persistent local variables. A static class field is shared by instances of its class. + + class Counter { + public static int $value = 0; + + public static int next() { + return ++self::$value; + } + } + + int $number = Counter::next(); + +Static fields follow the same declaration identity and conflict rules as instance fields. A shared ancestor's static field is not duplicated through a diamond. Independent public or protected static fields with the same name conflict; private fields in different declaring classes remain distinct. See chapter 12. + +### 11.15. Final Keyword + +A final class cannot be extended. A final method cannot be displaced by a declaration with the same input signature, whether declared in a child or encountered through another base earlier in MRO. Distinct input signatures remain separate overloads. MRO cannot bypass final constraints. + +The supplied loader checks final methods by name and requires the signature-aware inheritance change described in chapter 12. final virtual class is accepted as a non-instantiable class; operations called through the class name must be declared static. + +### 11.16. The is Operator + +is tests values against predefined types, array types and class or interface names recognized by the current ancestry machinery. + + int[] $values = {1, 2, 3}; + var_dump($values is int[]); // TRUE + var_dump($values is int); // FALSE + +A right operand that is a value rather than a type invokes value comparison. For example, both 5 is 5 and 5 is '5' return TRUE. + +Class and interface type tests use the full transitive ancestry, including secondary bases and extended interfaces. If A implements Y and Y extends X, an A instance satisfies both is Y and is X. This agreed requirement still needs the interpreter correction recorded in chapter 13. + +### 11.17. Interfaces + +Interfaces declare methods without implementations. A class attaches interfaces using implements. + + interface MyInterface { + public void myFunction(); + } + + class MyClass implements MyInterface { + public void myFunction() { + } + } + +Interface methods must be public instance contracts; a non-public contract declaration is invalid under the agreed interface rules. Constructors may be declared as interface methods. The supplied parser currently warns about a private interface method instead of rejecting it and needs the corresponding validation correction. + +Interface validation checks the complete required input signature, public visibility, method category and declared return type against the effective implementation selected by MRO. A different return type does not create an overload and cannot satisfy the contract. Additional overloads with different parameter signatures remain valid. + +An inherited compatible public method can satisfy implements X. Therefore A extends B implements X is valid when B supplies the required method, even if B does not itself implement X. B does not acquire that interface relationship merely by providing the method. + +A class must continue to satisfy interface contracts inherited through all its bases and interfaces. Replacing a selected method must not invalidate those contracts. Complete validation and transitive parameter checks are part of the agreed implementation change in chapter 12. + +### 11.18. Exceptions + +throw raises an exception object. try and catch provide handlers; finally supplies a completion block on supported paths. Exception and ErrorException are supplied classes. + + try { + throw new Exception('Example', 7); + } catch (Exception $e) { + print($e->getMessage()); + } finally { + print('Finished'); + } + +#### 11.18.1. Catch Block + +Catch clauses select a handler by exception class. Several catch clauses may be provided. A thrown object must be an Exception or derived instance. Not every engine diagnostic is a catchable language exception. + +#### 11.18.2. Finally Block + +A finally block runs when control leaves the protected try/catch region by normal completion, return, exception propagation or a supported loop transfer that exits that region. It runs before the pending completion continues. + +A return expression is evaluated before executing finally, and its result is retained while finally runs. If finally completes normally, the earlier return or exception continues. If finally executes another return or throws an exception, that new completion replaces the earlier one. Nested regions perform their corresponding finally blocks while unwinding. + + public int result() { + try { + return 7; + } finally { + print('Finished'); + } + } + +The call prints Finished and returns 7. Returning another value from finally would replace 7. The supplied interpreter currently skips finally on this return path and requires correction. These guarantees concern language-controlled execution, not a process crash or forced host termination. + +## 12. Agreed Inheritance Model for AER#26 + +This chapter specifies the accepted AER#26 inheritance model and supplies the detailed rules used by chapter 11. The design is agreed; implementation is pending. These requirements take precedence over the supplied interpreter's inheritance mechanism. Examples must be validated after that mechanism is changed. Short-circuit NULL coalescing is a separate agreed change specified in section 7.11. + +The syntax of extends and implements, and the order of bases written after extends, are retained. The changes cover inheritance, the effective overload set, member identity, $parent and interface validation. They do not introduce changes to import, file inclusion, character storage, closure capture or NULL coalescing. + +### 12.1. Object Attributes + +Object attributes are the data bundled in an instance of a class. The object attributes are called instance variables or member fields. An instance variable is a variable defined in a class, for which each object in the class has a separate copy. + + class Person { + public string $name = ''; + } + + class Program { + public void main() { + object $person1, $person2; + + $person1 = new Person(); + $person2 = new Person(); + $person1->name = "John"; + $person2->name = "Olivier"; + + print("Hello $person1->name and $person2->name"); + } + } + +In the example above, Person contains one attribute, $name. The class has been instantiated twice and the objects contain different data. + +An inherited field retains the identity of its original declaration. If a common base is reached through several inheritance paths, its field occurs once in each instance and its initializer runs once for that instance. + +Independent public or protected field declarations with the same name are a conflict, even when their types and initializers are equal. Redeclaring an inherited public or protected field is also a conflict. Private fields declared by different classes may share a name and remain separate storage locations. + + class First { + private int $value = 1; + + public int firstValue() { + return $this->value; + } + } + + class Second { + private string $value = 'second'; + + public string secondValue() { + return $this->value; + } + } + + class Combined extends First, Second {} + +The methods firstValue() and secondValue() use the private fields of their own declaring classes. A private declaration must not conceal an otherwise accessible field merely because its name is encountered earlier. + +### 12.2. Access Modifiers + +Access modifiers set the visibility of methods, fields and class constants. Aer implements public, protected and private. + + * Public members can be accessed wherever their class is available. + * Protected members can be accessed from their declaring class and derived-class contexts. + * Private members can be accessed from their declaring class. + + class DemoClass { + public float $real; + protected string $text; + private int $age; + } + + class Demo extends DemoClass {} + +If no access modifier is specified for an ordinary class member, private is assumed. Interface methods are public. + +The declaring context is not the same as the actual class of $this. A method declared in DemoClass retains access to its private members when invoked on an instance of Demo, while $this still refers to that Demo instance. + +Private methods of unrelated classes remain separate declarations rather than public override contracts. Inherited calls to a class's private helper continue to address that helper. A replacement of a public or protected method must not reduce its visibility. An inaccessible member does not become callable merely because it is found during MRO lookup. + +### 12.3. Method Overloading + +Method overloading allows several methods with the same name to accept different inputs. Aer distinguishes input signatures by the method name, the ordered parameter types and their passing modes. + + class Counter { + public int count(int $a, int $b) { + return $a + $b; + } + + public float count(float $a, float $b) { + return $a + $b; + } + } + +For count(6, 4), the int method is selected. For count(6.0, 4.0), the float method is selected. + +#### 12.3.1. Input Signatures + +The return type, parameter names, default expressions and visibility do not create different overloads. Two implementations with the same input signature cannot be declared directly in one class, even if they return different types. + + // Invalid declarations inside one class: + // public int render(int $value) { ... } + // public string render(int $other) { ... } + +Static and instance methods with the same input signature cannot be combined as competing categories of that signature. + +#### 12.3.2. Selecting an Overload + +The effective overload set is formed according to section 12.6. Candidate methods must accept the number of supplied arguments. Every omitted parameter must have a default. + +All supplied arguments are checked. Exact type matches are preferred to implicit conversions, using the supported predefined and array annotation types. A compatible specific predefined type is preferred to a general mixed match when applicable. Class and interface names do not form annotation types or class-specific overloads in AER#26; object-valued overload parameters use object. + + // Signatures inherited from different bases: + // First: public void process(float $value) + // Second: public void process(int $value) + +An int argument selects process(int), even when First precedes Second in MRO. A float argument selects process(float). An expected destination type is not used to choose the method. + +A candidate is better on parameter matching when it is no worse for every supplied argument and better for at least one. Incomparable matches are not resolved by counting a matching prefix. If parameter matches are equally good, prefer the candidate using fewer omitted default parameters. If no unique best candidate remains, the call is ambiguous and is an error. + +Only existing permitted conversions are considered. Explicit NULL remains a supplied argument and uses the ordinary NULL compatibility rules; it never requests an optional parameter expression. Candidate selection must not modify arguments, call conversion methods or evaluate default expressions. Such operations belong to the chosen call. Empty object values must be examined without dereferencing a missing instance. + +#### 12.3.3. Return Types and Inherited Methods + +Different input signatures may have different return types. Identical input signatures inherited from different classes are resolved by MRO, without using their return types to select a winner. + + class First { + public int render(int $value) { + return $value; + } + } + + class Second { + public string render(int $value) { + return 'second'; + } + } + + class Combined extends First, Second {} + +Combined uses First::render(int). Assigning its result to int is permitted; assigning it directly to string is an error. The interpreter does not retry Second::render(int) after an incompatible assignment. The reverse base order selects Second's implementation. + +Interface contracts are validated separately. A method selected by MRO must still satisfy every applicable interface requirement. + +### 12.4. Constructors & Destructors + +A constructor and destructor are special kinds of methods. A constructor is automatically called when an object is created. Its purpose is to initialize the state of the object. A destructor is called when the object is destroyed and may release resources owned by it. + + class Demo { + public void __construct() { + } + + public void __destruct() { + } + } + +Both methods have return type void and cannot return a value. A private or protected constructor restricts the contexts from which an object can be created. A static factory method can provide controlled creation. + + class Demo { + private void __construct() { + } + + public static object instance() { + return new Demo(); + } + } + +With inheritance, the selected constructor or destructor may explicitly continue through $parent. The engine must not also call every base implementation automatically and thereby duplicate that chain. A complete cooperative chain through a diamond reaches its common ancestor once. + +Instance fields retain their declaration identity independently of constructor chaining. A field from a shared ancestor is initialized once for each instance; calling a constructor does not create another copy of that field. + +Memory management automatically reclaims unused values and objects. Complete guarantees involving reference cycles, resurrection, shutdown and exceptions in destructors remain to be specified. A destructor's purpose includes releasing resources; applications may also close resources explicitly when required by the relevant library contract. + +### 12.5. Inheritance + +Inheritance forms new classes using classes which have already been defined. The new classes are called derived classes; the classes from which they inherit are called base classes. Important benefits are code reuse and the extension or replacement of behavior. + + class Base { + public void __construct() { + print('World!'); + } + } + + class Derived extends Base { + public void __construct() { + print('Hello '); + $parent->__construct(); + } + } + +Creating Derived prints Hello World!. With a single base chain, MRO follows the class and its ancestors in order. + +The actual class of a Derived instance remains Derived while a Base method executes. Calls through $this use the actual object's effective methods, including implementations in Derived. Access checks and self retain the declaring context of the executing method. + +A class also inherits the interface obligations of its bases. Replacing a method must not invalidate an interface contract which remains applicable to the object. + +### 12.6. Multiple Inheritance + +When a class extends more than one class, this is called multiple inheritance. + + class Base1 {} + class Base2 {} + class Derived extends Base1, Base2 {} + +Aer uses C3 method resolution order to establish one consistent sequence for a class and all of its base classes. The order after extends is significant, but a common ancestor is not treated as a new declaration each time it is reached. + +#### 12.6.1. Method Resolution Order + +For a class with no explicit base classes, its MRO contains the class itself. For C extending B1 through Bn, its linearization is: + + L(C) = [C] + merge(L(B1), ..., L(Bn), [B1, ..., Bn]) + +The merge operation selects the first available list head which does not occur in the tail of any remaining list. It appends that class and removes it from every list in which it is the head. Empty lists are discarded. If lists remain and no head can be selected, the hierarchy is inconsistent and the class is invalid. + + class Root {} + class Left extends Root {} + class Right extends Root {} + class Combined extends Left, Right {} + +The MRO of Combined is Combined, Left, Right, Root. Root appears once and follows both of its descendants. A simple depth-first search is not an equivalent algorithm. + +A direct base cannot occur twice, a class cannot inherit from itself directly or indirectly, and contradictory ordering requirements are errors. + + class X {} + class Y {} + class First extends X, Y {} + class Second extends Y, X {} + // class Invalid extends First, Second {} // Error: inconsistent MRO + +#### 12.6.2. Effective Methods + +For each method name, collect the distinct input signatures available through MRO. For each repeated signature, the first applicable declaration supplies the effective method. Different signatures remain available as overloads. + + class First { + public string render(int $value) { + return 'integer'; + } + } + + class Second { + public string render(string $value) { + return 'string'; + } + } + + class Combined extends First, Second {} + +Combined provides both render(int) and render(string). A better match from Second is not discarded merely because First appears earlier. + +When First and Second instead provide the same signature, base order selects its effective declaration. This is method precedence, not overloading by return type. Final, access and interface constraints remain requirements even when MRO establishes a first declaration. + +#### 12.6.3. Shared and Independent Declarations + +A field, static field or constant inherited from a common ancestor retains its original declaration identity. It is not duplicated by the diamond. + + class Root { + public int $value = 0; + } + + class Left extends Root { + public void increase() { + $this->value++; + } + } + + class Right extends Root { + public int read() { + return $this->value; + } + } + + class Combined extends Left, Right {} + +For one Combined instance, increase() and read() operate on the same Root::$value. A second instance has its own value. + +Independent public or protected fields or constants with the same name are conflicts. The interpreter must reject them rather than select one using MRO. Equal types, equal initializer expressions or equal constant values do not remove the conflict. Private declarations in different classes remain distinct. + +#### 12.6.4. The $parent Variable + +The $parent variable continues lookup after the class declaring the currently executing method, within the actual object's MRO. + + class Root { + public void visit() { + print("Root\n"); + } + } + + class Left extends Root { + public void visit() { + print("Left\n"); + $parent->visit(); + } + } + + class Right extends Root { + public void visit() { + print("Right\n"); + $parent->visit(); + } + } + + class Combined extends Left, Right {} + +Calling visit() on Combined prints Left, Right and Root, in that order. In Left's method, the remaining MRO is Right, Root. In Right's method, it is Root. + +The remaining sequence supplies an effective overload set using the same signature and argument rules as a normal call. Lookup cannot return to an earlier class. If no matching accessible method exists, the call is an error. + +$parent does not denote a second object. $this remains the same Combined instance throughout the chain. A private member does not become accessible merely because it occurs in the remaining sequence. + +#### 12.6.5. Interface Relationships + +An object is compatible with every class in its ancestry and every interface implemented directly or indirectly through those classes and interfaces. This includes relationships reached through secondary bases, not only the first base after extends. + +Interface contracts do not add another copy of instance state and do not determine which conflicting class implementation wins. They validate the effective methods obtained from the class hierarchy. + +#### 12.6.6. Combined Example + +The following example combines a shared ancestor, cooperative method calls, inherited fields, static state and an interface contract. + + interface Visitor { + public void visit(); + } + + class Root { + public int $value = 0; + public static int $calls = 0; + public const NAME = 'Root'; + + public void visit() { + self::$calls++; + print(self::NAME + ': ' + $this->value + "\n"); + } + } + + class Left extends Root { + public void visit() { + print("Left\n"); + $this->value++; + $parent->visit(); + } + } + + class Right extends Root { + public void visit() { + print("Right\n"); + $parent->visit(); + } + + public int read() { + return $this->value; + } + } + + class Combined extends Left, Right implements Visitor {} + + class Program { + public void main() { + object $first = new Combined(); + object $second = new Combined(); + $first->visit(); + print($first->read() + "\n"); + print($second->read() + "\n"); + print(Root::$calls + "\n"); + } + } + +The output is: + + Left + Right + Root: 1 + 1 + 0 + 1 + +Left and Right observe one Root::$value in the first instance. The second instance retains its own default value. Root::$calls is shared static state, while Root::NAME remains one constant declaration. The inherited effective visit() satisfies Visitor, and the $parent chain reaches Root once. + +### 12.7. Virtual Classes & Methods + +Virtual classes cannot be instantiated. A class containing an unimplemented virtual method must be declared virtual. Virtual methods declare a signature without providing a method body. + + virtual class Drawing { + protected int $x = 0; + protected int $y = 0; + + public virtual float area(); + + public void getCoordinates() { + print("\$x is $this->x\n"); + print("\$y is $this->y\n"); + } + } + + class Circle extends Drawing { + private int $radius; + + public void __construct(int $x, int $y, int $radius) { + $this->radius = $radius; + $this->x = $x; + $this->y = $y; + } + + public float area() { + return $this->radius * $this->radius * 3.14; + } + } + +A virtual derived class may leave obligations unimplemented. A concrete class must provide effective implementations for all required virtual methods and interface methods. Their visibility cannot be more restricted than the applicable contract. + +An implementation may be inherited; it does not have to be written again in every concrete class. An unresolved earlier virtual declaration must not be mistaken for an implemented method merely because a later declaration has a body. The effective signature must have a valid implementation. + +Unlike interfaces, virtual classes may contain instance state and methods with full implementations. Multiple virtual bases therefore remain subject to the same state and MRO rules as other multiple inheritance. + +The word virtual describes an abstract obligation in Aer. It is not required on every implemented method which participates in dynamic calls through $this. + +### 12.8. Class Constants + +Aer permits class constants. They belong to a class declaration rather than to a particular object. + + class Math { + public const PI = 3.14159265359; + + public float getPI() { + return self::PI; + } + } + +Class constants follow public, protected and private access rules. A shared ancestor's constant is one declaration, even when inherited through several paths. + +Two independent public or protected constants with the same name are a conflict, even when their types and values are identical. A derived class cannot resolve that conflict merely by declaring another constant of the same name. Private constants of different classes remain separate. + + class First { + private const LIMIT = 10; + + public int firstLimit() { + return self::LIMIT; + } + } + + class Second { + private const LIMIT = 'second'; + + public string secondLimit() { + return self::LIMIT; + } + } + + class Combined extends First, Second {} + +The methods retain the constant context of their declaring classes. This differs from selecting an inherited method implementation using MRO: visible constant conflicts are rejected rather than resolved by first occurrence. + +### 12.9. Static Keyword + +Aer allows class fields and methods to be static. A static field belongs to its declaring class and is shared independently of the number of object instances. + + class Counter { + public static int $value = 0; + + public static int next() { + return ++self::$value; + } + } + + int $first = Counter::next(); + +Inheriting Counter does not create a new declaration or copy of Counter::$value. Reaching it through a diamond also does not create another copy. + +Static fields follow the same declaration identity, visibility and conflict rules as instance fields. Independent public or protected static fields with the same name are errors; private static fields in different declaring classes remain independent. + +A static method can be called without an instance. Its self context belongs to its declaration. This draft does not require an implicit $this for calls made without an object. Class-call notation without an instance requires static, as described in section 11.8. + +### 12.10. Final Keyword + +Final methods cannot be overridden and final classes cannot be extended. The final keyword expresses an application design constraint which the engine enforces. + +MRO must not be used to bypass that constraint. A declaration which would displace an inherited final method of the same input signature is invalid, including displacement caused by another base appearing earlier in MRO. + +Methods with genuinely different input signatures remain distinct overloads. Marking one signature final does not make the method name itself a prohibition on every other parameter list. + +### 12.11. Interfaces + +Object interfaces allow the creation of code which specifies which methods a class must provide, without defining how those methods are implemented. Interfaces use the interface keyword in place of class, and their methods have declarations without bodies. + +All interface methods are public instance contracts. This draft does not introduce default interface method bodies. An interface may declare a constructor, which can be useful for creation contracts such as factories. + + interface MyInterface { + public void myFunction(); + } + + class MyClass implements MyInterface { + public void myFunction() { + } + } + +#### 12.11.1. Required and Additional Methods + +An interface describes required methods, not a closed list of all methods which a class may contain. + + interface Renderer { + public int render(int $value); + } + + class Document implements Renderer { + public int render(int $value) { + return $value; + } + + public string render(string $value) { + return $value; + } + } + +Document satisfies Renderer with render(int). Its render(string) is an additional valid overload. + +For each required input signature, the effective method must have the required public visibility, parameter types, passing modes, method category and declared return type. A concrete class must supply an implementation. A permitted call conversion does not replace the required signature: render(float) alone does not implement render(int). + +Return types are checked for contract agreement after MRO has selected the effective declaration. This draft requires an identical declared return type and does not introduce covariant return rules. + +#### 12.11.2. Inherited Implementations + +A class may satisfy an interface using an inherited method, even if the declaring base does not itself implement that interface. + + interface X { + public int render(int $value); + } + + class Base { + public int render(int $value) { + return $value; + } + } + + class Derived extends Base implements X {} + +Derived implements X. Base does not become an implementation of X merely because its method has the required shape. No delegating method needs to be written in Derived. + +If Base itself declares implements X, all of its derived classes inherit that interface relationship. They need not repeat implements X. + +#### 12.11.3. Preserving Inherited Contracts + +The effective methods of a class must satisfy every interface inherited through its classes and interfaces, including secondary bases and indirect paths. + +A derived class cannot replace a required int render(int) with string render(int) and remain a valid implementation of the same interface. This is a contract error even when the replacement would otherwise be selected by MRO. + + interface X { + public int render(int $value); + } + + class Compatible implements X { + public int render(int $value) { + return $value; + } + } + + class Incompatible { + public string render(int $value) { + return 'text'; + } + } + + // class Invalid extends Incompatible, Compatible {} + // Error: the effective render(int) does not satisfy inherited X. + +The interpreter must not skip Incompatible's effective declaration and choose Compatible's method merely to make contract validation succeed. + +#### 12.11.4. Multiple Interface Requirements + +Several interfaces may require the same input signature when their contracts agree. One effective implementation may satisfy all of them. + +Different input signatures coexist as separate obligations. The same input signature with incompatible return types is a conflicting contract, not an overload. + +Interface inheritance passes all requirements transitively. A virtual class may leave compatible requirements unimplemented for a later concrete class. Declaring a class virtual does not resolve mutually incompatible contracts. + +### 12.12. Type Relationships and Constructors + +The is operator and inherited interface relationships must use the complete transitive ancestry, including secondary bases and inherited interfaces. Class/interface identifiers remain valid as nominal targets for is, extends and implements, while named annotation types are not supported in AER#26. Object parameters and results use object. An empty object value is not an instance and must be handled without dereferencing it. + +Normal object construction selects the effective constructor using the same applicable overload rules. Base constructors and destructors are not all called implicitly: continuation is explicit through $parent. A cooperative chain through a diamond visits the common ancestor once. Program startup still supplies no constructor arguments. + +### 12.13. Required Validation + +The implementation change must be exercised by positive and negative tests. Coverage shall include consistent and inconsistent C3 graphs, both base orders, diamonds, same-name methods with equal and different signatures, exact int versus float matching, later-argument mismatches, ambiguous candidates, optional arguments, by-reference parameters, inherited final methods, access restrictions, shared instance and static fields, independent conflicting fields and constants, private same-name members, cooperative $parent calls, constructors, destructors, inherited interface implementations and incompatible interface contracts. + +Tests must assert observable results and rejected declarations. Merely constructing an instance does not prove overload choice or storage identity. A diamond test must read and write the same ancestor field through both branches, compare separate instances, and separately check shared static storage. Interface tests must cover A extends B implements X when B supplies the method but does not implement X, as well as A extends B when B already implements X. + +## 13. Implementation Status and Open Decisions + +The supplied interpreter remains the recorded implementation baseline. The following accepted requirements still need code changes and corresponding regression tests: + + * NULL coalescing must short-circuit and must not treat a non-empty callback as empty. + * Inheritance, full overload matching, signature identity, visibility, final and virtual checks, interface contracts and $parent must follow chapter 12. Class/interface annotation types are excluded from AER#26; legacy named-parameter acceptance must be diagnosed consistently while preserving new, is, extends and implements. + * Imports must warn on a failed load or a duplicate. Only successful loads enter the module registry, and duplicate loads skip initialization. module_loaded(string) needs implementation. + * require is restricted to the script declaration block. Repeating a successful require warns and skips loading. A missing required file remains fatal. + * include needs function-call syntax with inline caller-context semantics. A missing file warns and continues. Repeated inclusion executes the fragment again. Return from an included fragment must return from the enclosing user method or anonymous function and run applicable finally blocks. It must not be swallowed by an eval-like child frame. + * Locals and local constants require lexical block visibility. Ordinary loop-body variables have fresh bindings on each entry. A local constant initializer runs on the first execution of its declaration, not on reads. Re-executing that declaration within the same enclosing invocation is a fatal reinitialization error, including on a later loop iteration. Tests must cover two equal reads followed by that error, and independent method invocations. + * Closures require value capture and explicit reference capture using &. Escaping reference captures must keep their storage alive. Capture must not disable the declared result-type check. + * Object-call notation must pass arguments and return the __invoke result through the normal invocation machinery. + * The comma operator must work in expression contexts and in for initialization/update, with ordered evaluation and the right operand's value as result. Existing process crashes must be repaired, not merely recorded as unsupported syntax. + * The decoder must restore \e, decode one or two hexadecimal digits after \x and diagnose a missing digit. The lexer must support decimal literals and explicit 0b, 0o and 0x prefixes. The decoder must support classic octal escapes and the braced decimal, binary, octal and hexadecimal forms from section 6.9. + * Missing results in non-void methods must warn and return NULL. Explicit incompatible results still obey normal type checks. + * Finally must execute on controlled exits, including return, according to section 11.18.2. + * CLI arguments must preserve their boundaries and empty values. main must be public and have the single-entry-point shape. Class-name calls without an object require static; this decision is settled. + * Integer arithmetic has the agreed deterministic 64-bit wraparound policy. Its implementation must not accidentally depend on undefined signed C overflow. The minimum-int64 formatter separately needs repair: the tested in-range minimum currently prints as -l. + * JSON encoding must correctly handle supported arrays/maps or produce controlled diagnostics, without incorrect numeric strings or process crashes. + * Optional parameter expressions run only for omitted arguments. Explicit NULL must not activate such a default; normal destination-type default rules apply. + * Remove legacy return-reference declaration support. Reference parameters and explicit reference captures remain supported. Remove any dedicated implementation paths for automatic __get/__call dispatch, static interface-method contracts and variable variables; these are excluded from the agreed language. Check for existing paths before cleanup rather than introducing new machinery. + +The current character/string model is retained. The handling of numeric escape values beyond a byte remains undecided. Return references are excluded from AER#26; legacy return-reference declaration support must be removed, while reference parameters and reference captures remain supported. Local constant tests must reflect the agreed repeated-initialization error. The exact normal-completion result contract of include, and unchosen details of future namespaces and planned facilities, are not silently invented here. + +The supplied executable has been observed to reevaluate a method-local constant on repeated reads. A separate const-inside-for probe fails with an undefined-constant diagnostic. These observations motivate distinct regression tests for initializer evaluation, lexical visibility and the fatal repeated-initialization rule. The required loop example prints 1 and 1 before the error; it does not complete a second iteration. + +The original test suite documents the old executable. Tests that rely on method-wide local visibility, named parameter annotations, swallowed include returns, weak closure result checking, dropped invocation arguments or NULL selecting optional defaults must be updated to the accepted AER#26 behavior. Passing those old expectations alone will not demonstrate conformance after the changes. + +The supplied integer-backed char representation and byte-based strings are retained in AER#26. They require no Unicode or wide-character migration. Existing Boolean conversions, coercive equality, value comparison through is, division/modulo behavior and arithmetic precedence remain unchanged except for the separately agreed additions above. + +## 14. Built-in Runtime Facilities + +The supplied runtime contains a larger function library than the AER#19 language document describes. The following inventory was extracted from the core registration tables and every listed name was checked using function_exists() in the rebuilt interpreter. The list is an availability inventory. Each function's specified semantics remain its contract, and test coverage is an audit matter rather than an alternative language rule. + +The interpreter also supplies Exception, ErrorException, Directory and stdClass, and the interfaces Iterator, IteratorAggregate and Serializable. Reflection functions expose classes, methods, fields and interfaces. Other facilities include autoload handlers, shutdown handlers, variable inspection, array processing, string and byte operations, random values, dates, environment access, file-system operations and streams. Module functions are loaded separately using import. + +### 14.1. Core Function Inventory + +__builtin.c:aBuiltInFunc__ + +`is_array()`, `is_bool()`, `is_callback()`, `is_char()`, `is_float()`, `is_int()`, `is_object()`, `is_resource()`, `is_string()`, `is_void()`, `is_numeric()`, `round()`, `dechex()`, `decoct()`, `decbin()`, `hexdec()`, `bindec()`, `octdec()`, `srand()`, `base_convert()`, `substr()`, `substr_compare()`, `substr_count()`, `chunk_split()`, `addslashes()`, `addcslashes()`, `quotemeta()`, `stripslashes()`, `htmlspecialchars()`, `htmlspecialchars_decode()`, `get_html_translation_table()`, `htmlentities()`, `html_entity_decode()`, `strlen()`, `strcmp()`, `strncmp()`, `strcasecmp()`, `strncasecmp()`, `implode()`, `implode_recursive()`, `explode()`, `trim()`, `rtrim()`, `ltrim()`, `strtolower()`, `strtoupper()`, `ucfirst()`, `lcfirst()`, `ord()`, `chr()`, `bin2hex()`, `strstr()`, `stristr()`, `strpos()`, `stripos()`, `strrpos()`, `strripos()`, `strrchr()`, `strrev()`, `system()`, `ucwords()`, `str_repeat()`, `nl2br()`, `sprintf()`, `printf()`, `vprintf()`, `vsprintf()`, `size_format()`, `md5()`, `sha1()`, `crc32()`, `str_getcsv()`, `strip_tags()`, `str_shuffle()`, `str_split()`, `strspn()`, `strcspn()`, `strpbrk()`, `soundex()`, `wordwrap()`, `strtok()`, `str_pad()`, `str_replace()`, `str_ireplace()`, `strtr()`, `parse_ini_string()`, `time()`, `microtime()`, `getdate()`, `gettimeofday()`, `date()`, `strftime()`, `idate()`, `gmdate()`, `localtime()`, `mktime()`, `gmmktime()`, `base64_encode()`, `base64_decode()`, `urlencode()`, `urldecode()`. + +__hashmap.c:aHashmapFunc__ + +`sizeof()`, `array_key_exists()`, `array_pop()`, `array_push()`, `array_shift()`, `array_product()`, `array_sum()`, `array_keys()`, `array_values()`, `array_merge()`, `array_slice()`, `array_splice()`, `array_search()`, `array_diff()`, `array_udiff()`, `array_diff_assoc()`, `array_diff_uassoc()`, `array_diff_key()`, `array_intersect()`, `array_intersect_assoc()`, `array_uintersect()`, `array_intersect_key()`, `array_erase()`, `array_fill()`, `array_fill_keys()`, `array_combine()`, `array_reverse()`, `array_unique()`, `array_flip()`, `array_rand()`, `array_chunk()`, `array_pad()`, `array_replace()`, `array_filter()`, `array_map()`, `array_reduce()`, `array_walk()`, `array_walk_recursive()`, `in_array()`, `sort()`, `asort()`, `arsort()`, `ksort()`, `krsort()`, `rsort()`, `usort()`, `uasort()`, `uksort()`, `shuffle()`, `range()`, `current()`, `each()`, `pos()`, `next()`, `prev()`, `end()`, `reset()`, `key()`. + +__vfs.c:aVfsFunc__ + +`chdir()`, `chroot()`, `getcwd()`, `rmdir()`, `is_dir()`, `mkdir()`, `rename()`, `realpath()`, `sleep()`, `usleep()`, `unlink()`, `chmod()`, `chown()`, `chgrp()`, `disk_free_space()`, `disk_total_space()`, `file_exists()`, `filesize()`, `fileatime()`, `filemtime()`, `filectime()`, `filegroup()`, `fileinode()`, `fileowner()`, `is_file()`, `is_link()`, `is_readable()`, `is_writable()`, `is_executable()`, `filetype()`, `stat()`, `lstat()`, `getenv()`, `putenv()`, `touch()`, `link()`, `symlink()`, `umask()`, `sys_get_temp_dir()`, `get_current_user()`, `getpid()`, `getuid()`, `getgid()`, `php_uname()`, `dirname()`, `basename()`, `pathinfo()`, `strglob()`, `fnmatch()`, `zip_open()`, `zip_close()`, `zip_read()`, `zip_entry_open()`, `zip_entry_close()`, `zip_entry_name()`, `zip_entry_filesize()`, `zip_entry_compressedsize()`, `zip_entry_read()`, `zip_entry_reset_read_cursor()`, `zip_entry_compressionmethod()`. + +__vfs.c:aIOFunc__ + +`ftruncate()`, `fseek()`, `ftell()`, `rewind()`, `fflush()`, `feof()`, `fgetc()`, `fgets()`, `fread()`, `fgetcsv()`, `fgetss()`, `readdir()`, `rewinddir()`, `closedir()`, `opendir()`, `readfile()`, `file_get_contents()`, `file_put_contents()`, `file()`, `copy()`, `fstat()`, `fwrite()`, `fputs()`, `flock()`, `fclose()`, `fopen()`, `fpassthru()`, `fputcsv()`, `fprintf()`, `md5_file()`, `sha1_file()`, `parse_ini_file()`, `vfprintf()`. + +__vm.c:aVmFunc__ + +`function_exists()`, `is_callable()`, `register_autoload_handler()`, `register_shutdown_function()`, `get_defined_constants()`, `class_exists()`, `property_exists()`, `method_exists()`, `interface_exists()`, `get_class()`, `get_parent_class()`, `get_called_class()`, `get_declared_classes()`, `get_declared_interfaces()`, `get_class_methods()`, `get_class_vars()`, `get_object_vars()`, `is_subclass_of()`, `is_a()`, `rand()`, `rand_str()`, `getrandmax()`, `random_int()`, `random_bytes()`, `uniqid()`, `print()`, `exit()`, `eval()`, `get_defined_vars()`, `gettype()`, `get_resource_type()`, `unset()`, `var_dump()`, `print_r()`, `var_export()`, `ob_clean()`, `ob_end_clean()`, `ob_end_flush()`, `ob_flush()`, `ob_get_clean()`, `ob_get_contents()`, `ob_get_flush()`, `ob_get_length()`, `ob_get_level()`, `ob_implicit_flush()`, `ob_get_level()`, `ob_list_handlers()`, `ob_start()`, `get_memory_limit()`, `get_memory_peak_usage()`, `get_memory_usage()`, `assert_options()`, `assert()`, `restore_exception_handler()`, `set_exception_handler()`, `debug_backtrace()`, `ph7version()`, `phpinfo()`, `compact()`, `extract()`, `parse_url()`, `utf8_encode()`, `utf8_decode()`, `getopt()`, `get_include_path()`, `get_included_files()`. + +The built-in function_exists(string $name) returns TRUE when that function name is registered and FALSE otherwise. It does not invoke the function, load an absent module or test its implementation. This query has the same availability-checking role as its PHP counterpart. + +### 14.2. eval and exit + +The registered eval() function compiles executable statements in the current execution context. eval('print(7);') prints 7 and returns TRUE. A return inside evaluated code is subject to the enclosing method's return rules: eval('return 2+3;') is rejected in a void method, while returning that evaluated value from an int method produces 5. It must not be assumed to be a wholly separate untyped function scope. + +exit() terminates execution. The tested exit(7) stops before the next statement and supplies status 7 to the CLI environment. It is different from return, which ordinarily returns to a caller. + +### 14.3. Native Modules + +The source tree supplies dummy, math, ctype, json and xml module implementations. Focused execution verified the dummy example, sqrt(9) from math, ctype_digit('123') from ctype, and scalar string encoding from json. JSON encoding of supported arrays and maps is required to work correctly; the failures listed in chapter 13 are implementation defects to repair. XML operations and the complete contracts of native functions are not certified by this language audit. Documentation must not infer an API from a stale comment or an unregistered C function. + +### 14.4. Predefined Constants + +The compiler expands `__LINE__`, `__FILE__`, `__DIR__`, `__CLASS__`, `__FUNCTION__` and `__METHOD__` in the source context. In the checked Program::main context, the last two both produce the method name main; __METHOD__ does not produce the qualified spelling Program::main. The file and directory values describe the compiled source location. + +get_defined_constants() returns an indexed array of registered constant names, not an associative map from names to values. The following names were returned by the supplied build without importing modules. Names retained from the PH7 runtime, including PHP-prefixed names, do not imply PHP language compatibility. Their individual value and function contracts have not all been exercised. + +`EXTR_PREFIX_IF_EXISTS`, `EXTR_IF_EXISTS`, `EXTR_PREFIX_INVALID`, `EXTR_PREFIX_ALL`, `EXTR_PREFIX_SAME`, `EXTR_SKIP`, `EXTR_OVERWRITE`, `INI_SCANNER_RAW`, `INI_SCANNER_NORMAL`, `stderr`, `STDERR`, `stdout`, `STDOUT`, `stdin`, `STDIN`, `GLOB_ERR`, `GLOB_ONLYDIR`, `GLOB_BRACE`, `GLOB_NOESCAPE`, `GLOB_NOCHECK`, `GLOB_NOSORT`, `GLOB_MARK`, `SCANDIR_SORT_NONE`, `SCANDIR_SORT_DESCENDING`, `SCANDIR_SORT_ASCENDING`, `FILE_APPEND`, `FILE_SKIP_EMPTY_LINES`, `FILE_IGNORE_NEW_LINES`, `FILE_USE_INCLUDE_PATH`, `LOCK_UN`, `LOCK_NB`, `LOCK_SH`, `LOCK_EX`, `SEEK_END`, `SEEK_CUR`, `SEEK_SET`, `ASSERT_CALLBACK`, `ASSERT_QUIET_EVAL`, `ASSERT_BAIL`, `ASSERT_WARNING`, `ASSERT_ACTIVE`, `PATHINFO_FILENAME`, `PATHINFO_EXTENSION`, `PATHINFO_BASENAME`, `PATHINFO_DIRNAME`, `FNM_CASEFOLD`, `FNM_PERIOD`, `FNM_PATHNAME`, `FNM_NOESCAPE`, `PHP_QUERY_RFC3986`, `PHP_QUERY_RFC1738`, `PHP_URL_FRAGMENT`, `PHP_URL_QUERY`, `PHP_URL_PATH`, `PHP_URL_PASS`, `PHP_URL_USER`, `PHP_URL_PORT`, `PHP_URL_HOST`, `PHP_URL_SCHEME`, `HTML_SPECIALCHARS`, `HTML_ENTITIES`, `UTF8`, `UTF-8`, `ISO_8859_1`, `ISO-8859-1`, `ENT_HTML5`, `ENT_XHTML`, `ENT_XML1`, `ENT_HTML401`, `ENT_DISALLOWED`, `ENT_SUBSTITUTE`, `ENT_IGNORE`, `ENT_NOQUOTES`, `ENT_QUOTES`, `ENT_COMPAT`, `DATE_W3C`, `DATE_RSS`, `DATE_RFC3339`, `DATE_RFC2822`, `DATE_RFC1123`, `DATE_RFC1036`, `DATE_RFC850`, `DATE_RFC822`, `DATE_ISO8601`, `DATE_COOKIE`, `DATE_ATOM`, `DEBUG_BACKTRACE_PROVIDE_OBJECT`, `DEBUG_BACKTRACE_IGNORE_ARGS`, `PHP_ROUND_HALF_ODD`, `PHP_ROUND_HALF_UP`, `PHP_ROUND_HALF_EVEN`, `PHP_ROUND_HALF_DOWN`, `SORT_STRING`, `SORT_NUMERIC`, `SORT_REGULAR`, `SORT_DESC`, `SORT_ASC`, `COUNT_RECURSIVE`, `COUNT_NORMAL`, `STR_PAD_BOTH`, `STR_PAD_RIGHT`, `STR_PAD_LEFT`, `CASE_UPPER`, `CASE_LOWER`, `E_ALL`, `E_USER_DEPRECATED`, `E_DEPRECATED`, `E_RECOVERABLE_ERROR`, `E_STRICT`, `E_USER_NOTICE`, `E_USER_WARNING`, `E_USER_ERROR`, `E_COMPILE_WARNING`, `E_COMPILE_ERROR`, `E_CORE_WARNING`, `E_CORE_ERROR`, `E_NOTICE`, `E_PARSE`, `E_WARNING`, `E_ERROR`, `PHP_SHLIB_SUFFIX`, `__DATE__`, `__TIME__`, `DIR_SEP`, `DIRECTORY_SEPARATOR`, `PATH_SEPARATOR`, `PHP_INT_SIZE`, `MAXINT`, `PHP_INT_MAX`, `PHP_EOL`, `PHP_OS`, `PH7_VERSION`. + +## 15. Future Facilities + +The following facilities are planned. This chapter states their intended role and separates it from the supplied executable. It does not claim completed syntax, implementation or test coverage where details remain open. + +### 15.1. Namespaces + +Namespaces provide logical declaration spaces for classes, interfaces and named constants. They do not create objects, VM instances or filesystem directories. The global namespace remains available. + +Declarations of the same namespace aggregate into one logical namespace, including declarations loaded from different required files. Distinct namespaces may contain the same short type name without a collision. Within one namespace, normal duplicate-name and input-signature rules still apply. + +A fully qualified name identifies its declaration space explicitly. Unqualified lookup must obey specified lexical rules; it must not select a declaration by scanning arbitrary namespaces in file-load order. Ambiguous names are errors. Namespace qualification does not bypass access control, change inheritance or alter a method's declaring context. + +Native-module import remains a module-loading operation. It must not be silently reinterpreted as a namespace alias. require loads source declarations and include evaluates a method fragment; neither operation implicitly invents a namespace from its filename. Startup continues to use the entry Program class in the global namespace unless a separate entry-point design is adopted. + +The intended aggregation and isolation rules above are recorded now. The precise qualified-name grammar, declaration form, lookup hierarchy and any namespace-use or alias syntax require a separate design before implementation. The supplied interpreter currently recognizes a namespace directive but ignores it with a notice. + +### 15.2. Value Inspection and Destructuring + +empty and isset are planned operations for inspecting values or storage. Their behavior for undefined names and missing array entries must be defined explicitly; an ordinary eager function call cannot inspect an undefined operand if evaluating that operand has already raised an error. Their relationship to typed NULL defaults and the emptiness rules of section 6.11 must also be settled. PHP compatibility is not implied merely by the names. + +list is planned destructuring assignment from a collection into destinations. It requires rules for target types, nesting, keys, missing elements and evaluation order. It is not currently a registered ordinary function. + +### 15.3. Invocation Argument Inspection + +func_num_args() and func_get_args() are planned built-ins for inspecting the current user invocation. Their contract must distinguish supplied arguments from formal parameters filled by defaults and define the treatment of implicit captures, references and the special main invocation. They are absent from the supplied core registry. Recording their future role does not assert that they already work.