Last Updated: 2018-11-06

Authors:
Jens von Pilgrim, Jakub Siberski, Mark-Oliver Reiser,
Torsten Krämer, Ákos Kitta, Sebastian Zarnekow, Lorenzo Bettini, Jörg Reichert, Kristian Duske, Marcus Mews, Minh Quang Tran, Luca Beurer-Kellner

## Abstract

This document contains the N4JS Specification.

## Revision History

Date Author Description

2013-03-21

v.Pilgrim

initial commit

2016-03-13

v.Pilgrim

public release, version 0.3 (alpha)

2016-05-31

mor

support for definition-site variance, cf. Definition-Site Variance

2016-07-18

mor

rename manifest property artifactId to projectId; remove projectName

2016-09-09

mor

add @CovariantConstructor, cf. Covariant Constructors, plus related adjustments

2016-11-09

bsmith

convert from LaTeX to AsciiDoc

2017-07-03

qtran

Describe semantics of optional fields in ternay expressions Optional Fields

2018-09-13

mmews

## Licence

This specification and the accompanying materials is made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html

### Eclipse Public License - v 1.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (AGREEMENT). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT’S ACCEPTANCE OF THIS AGREEMENT.

#### 1. DEFINITIONS

Contribution means:
1. in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and

2. in the case of each subsequent Contributor:

1. changes to the Program, and

where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution ’originates’ from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor’s behalf. Contributions do not include additions to the Program which:

1. are separate modules of software distributed in conjunction with the Program under their own license agreement, and

2. are not derivative works of the Program.

Contributor

means any person or entity that distributes the Program.

Licensed Patents

mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

Program

means the Contributions distributed in accordance with this Agreement.

Recipient

means anyone who receives the Program under this Agreement, including all Contributors.

#### 2. GRANT OF RIGHTS

1. Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.

2. Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.

3. Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient’s responsibility to acquire that license before distributing the Program.

4. Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.

#### 3. REQUIREMENTS

A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:

1. it complies with the terms and conditions of this Agreement; and

1. effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;

2. effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;

3. states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and

4. states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.

When the Program is made available in source code form:

1. it must be made available under this Agreement; and

2. a copy of this Agreement must be included with each copy of the Program.

Contributors may not remove or alter any copyright notices contained within the Program.

Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.

#### 4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (Commercial Contributor) hereby agrees to defend and indemnify every other Contributor (Indemnified Contributor) against any losses, damages and costs (collectively Losses) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor’s responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

#### 5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

#### 6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

#### 7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient’s patent(s), then such Recipient’s rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient’s rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient’s rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient’s obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.

This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

## 1. Introduction

This specification defines the N4JS language.

In general, the N4JS JavaScript dialect used is identical to the standard ECMAScript as defined in the 6th edition of ECMA-262, also known as ECMAScript 2015, referred to as [ECMA15a].

### 1.1. Notation

#### 1.1.1. Grammar Notation

For the specification of the syntax and structure of elements, we use a slightly augmented similar to the grammar language of Xtext Grammar Language.

Similar to [ECMA11a], we define types with properties only for the purpose of explanation and usage within this specification. We use the Xtext notation style to assign values to meta-properties. Particularly, we use the Xtext notation for collection (+=) and boolean (?=) values. These properties are written in italics. Enumerations are defined similar to Xtext. In order to allow the specification of default values, which are often defined by omitting the value, we always define the literal explicitly if it can be defined by the user.

The following lists informally defines the grammar:

Terminal

Terminals (or terminal strings) are enclosed in single quotes, e.g., terminal.

Enumerations

Rules which contain only terminals used as values for properties are marked with enum for enumeration.

Properties

Values of non-terminals, e.g., other rules, can be assigned to properties. The property name and the assignment are not part of the original syntax and only used for the meta description. E.g., name=Identifier.

Collection Properties

If a property is a collection, values are added to that list via +=. E.g.,property+=Value .

Boolean Properties

Boolean properties are set to false by default, if the value (usually a terminal) is found, the boolean value is set to true. Often, the name of the property is similar to the terminal. E.g., final?='final'?.

Properties of a non-terminal are sometimes listed again below the grammar. In that case, often pseudo properties are introduced which are derived from other properties and which are only used for simplification.

#### 1.1.2. Type Judgments and Rules and Constraints Notation

##### 1.1.2.1. Typing Rules and Judgments

Definition: Rule

We use the common notation for rules such as type inference rules [1], that is

$\frac{premises}{conclusion}\phantom{\rule{5.0mm}{0ex}}\text{rule name}$

$premises$ is the rule’s premises (e.g., the expression to be inferred), $conclusion$ the result of the rule. $rulename$ is an optional condition which may be omitted.

Both parts of the rule may contain multiple expressions, which are concatenated via 'and'.

For example, the following

$\frac{{P}_{1}\phantom{\rule{5.0mm}{0ex}}{P}_{2}\phantom{\rule{5.0mm}{0ex}}{P}_{3}}{C}$

if ${P}_{1}$, ${P}_{2}$, and ${P}_{3}$ are all true, then $C$ is true as well.

The following judgments (with relation symbols) are used:

subtype $<$

-

type $\text{:}$

in which the left hand side is a declaration or expression, and the right hand side a type. We also use $\left[\phantom{\rule{-0.167em}{0ex}}\left[.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}\right]\phantom{\rule{-0.167em}{0ex}}\right]$ as a function returning the (inferred) type of an expression.

expectedTypeIn $⊲:$

a relation with three arguments: $container⊲expression:type$ means, that $expression$ is expected to be a subtype of $type$ inside $container$

The following statement, for example, defines transitivity of subtypes (in a simplified manner):

$\frac{\Gamma ⊢B\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}A\phantom{\rule{5.0mm}{0ex}}\Gamma ⊢C\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}B}{\Gamma ⊢C\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}A}$

$⊢$ is the context containing (bound) type variables etc., $⊢$ can be read as entails. Thus, the rule can be read as follows:

if the type B is a subtype of type A in context $\Gamma$ (i.e. with constraints on type variables specified in $\Gamma$), and if type C is a subtype of B, then C is also a subtype of A in context $\Gamma$.

In rules, we sometimes omit the environment if it is not needed. New information is sometimes added to the environment, in particular, substitutions (that is binding type variables to a type). The set of substitutions is written with $\theta$ (theta). If new substitutions are explicitly added to that set, we write $\theta \left(V←T\right)$ ($V$ is substituted with type $T$). Often, these bindings are computed from a parameterized type reference which declares type arguments which are bound to the type variables of the generic declaration. In this case we simply write $\theta \left(p\right)$, in which $p$ is the parameterized type declaration. As these new substitutions must become part of a (newly) created environment, we then usually write $\Gamma ←\theta \left(p\right)$. These substitutions are usually omitted.

##### 1.1.2.2. Types of an Element

A variable or other typed element may be associated with three types:

1. Declared type: the type explicitly specified in the code, e.g., var s: string.

2. Inferred type: the type inferred by the type inferencer, e.g., var s = "Hello" infers the type of s to string. I.e. $\Gamma ⊢s:string$ will be true, or $\left[\phantom{\rule{-0.167em}{0ex}}\left[s\right]\phantom{\rule{-0.167em}{0ex}}\right]\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}string$. If an element is annotated with a type ,i.e. it has a declared type, the inferred type will always be the declared type.

3. Actual type: the actual type of a variable during runtime. This type information is not available at compile time and ignored in this specification.

These types are not type declarations but type references, in fact, as they may be parameterized. For the sake of simplicity, we often omit the $Ref$ suffix to shorten formulas. Consequently, we define the following properties and pseudo properties for typed elements such as variables:

declaredType$Ref$

The explicitly declared type, this is usually a real property of the construct. Not all elements allow the specification of a declared type, such as expressions.

inferredType$Ref$ or $\left[\phantom{\rule{-0.167em}{0ex}}\left[.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}\right]\phantom{\rule{-0.167em}{0ex}}\right]$

This pseudo property is the inferred type computed by the type inferencer.

type$Ref$

A pseudo property for elements with a $declaredType$ property. It is similar to the inferred type, i.e. $e.type=\left[\phantom{\rule{-0.167em}{0ex}}\left[e\right]\phantom{\rule{-0.167em}{0ex}}\right]$

### 1.2. Auxiliary Functions

This section describes some auxiliary functions required for definition of type inference rules later on.

#### 1.2.1. Binding

Binding an identifier (variable reference) to a variable declaration (or variable definition) is not part of this specification as this is standard ECMAScript functionality. However, some valid ECMAScript bindings are permitted due to visibility constraints.

Definition: Binding Relation

We define a pseudo relation

$bind:VariableReference×VariableDeclaration$

which binds a reference, i.e. an identifier, to a declaration (e.g.,variable declaration).

Binding of variable references to declaration is defined by ECMAScript already. Type references only occur in type expressions, how these are handled is explained in Type Expressions.

We usually omit this binding mechanism in most rules and use the reference similarly to the declaration or definition it is bound to. If a variable reference $r$, for example, is bound to a variable declaration $D$, i.e. $bind\left(r,D\right)$, we simply write $r.type$ instead of $bind\left(r,D\right),D.type$ to refer to the type expression (of the variable).[2]

A DeclaredType references the type declaration by its simple name that has been imported from a module specifier. We define the method $bind$ for declared types as well:

We define a pseudo relation

$bind:DeclaredType×Class|Interface|Enum$

which binds a type reference, i.e. a simple name, to the type declaration.

#### 1.2.2. Merging Types

In some cases we have to merge types, e.g., types of a union type or item types of an array. For that purpose, we define a method $merge$ as follows.

Definition: Merge Function

We define a pseudo function

$merge:Type×.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}×Type⇒\mathcal{P}\left(Type\right)$

The idea of this function is to remove duplicates. For example; if a union type contains two type expressions $t{e}_{1}$ and $t{e}_{k}$, and if $\tau \left(t{e}_{1}\right)=\tau \left(t{e}_{2}\right)$, then $merge\left(\tau \left(t{e}_{1}\right),\tau \left(t{e}_{2}\right)\right)$ contains only one element. The order of the elements is lost, however.

##### 1.2.2.1. Logic Formulas

In general, we use a pragmatic mixture of pseudo code, predicate logic, and OCL. Within constraints (also within the inference rules), the properties defined in the grammar are used.

In some rules, it is necessary to type the rule variables. Instead of explicitly checking the metatype (via $\mu \left(X\right)=:MetaType$), we precede the variable with the type, that is: $MetaTypeX$.

Instead of "type casting" elements, often properties are simply accessed. If an element does not define that element, it is either assumed to be false or null by default.

If a property $p$ is optional and not set, we write $p=null$ to test its absence. Note that $p=null$ is different from $p=Null$, as the latter refers to the null type. Non-terminals may implicitly be subclasses. In that case, the concrete non-terminal, or type, of a property may be subject for a test in a constraint.

#### 1.2.3. Symbols and Font Convention

Variables and their properties are printed in italic when used in formulas (such as rules). A dot-notation is used for member access, e.g. $v.name$. Also defined functions are printed in italic, e.g., $acc\left(r,D\right)$. Properties which define sets are usually ordered and we assume 0-indexed access to elements, the index subscripted, e.g., $v.method{s}_{i}$.

We use the following symbols and font conventions:

$\wedge$, $\vee$, $\oplus$, $¬$

Logical and, or, exclusive or (xor), and not.

$⇒$, $⇔$, $\text{if}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}$, $\text{then}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}$, $\text{else}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}$

Logical implication, if and only if, and if-then-else.

$\text{true}$, $\text{false}$, $\text{null}$, $\varnothing$

Boolean true, boolean false, null (i.e., not specified, e.g., $v.sup=$ means that there are is no $sup$ (super class) specified), empty set.

$\in$, $\notin$, $\cup$, $\cap$, $|x|$

Element of, not an element of, union set, intersection set, cardinality of set x.

$\mathcal{P}\left(X\right)$

Power set of $X$, i.e. $\mathcal{P}\left(X\right)=\left\{U:U\subseteq X\right\}$.

$\exists$, $\nexists$, $\forall$

Exists, not exists, for all; we write $\exists x,.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},z:P\left(x,.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},z\right)$ and say

"there exists $x,.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},z$ such that predicate $P$ is true".

Note that $\nexists x:P\left(x\right)⇔\forall x:¬P\left(x\right)$.

$\mu \left(.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}\right)$

(mu) read "metatype of"; metatype of a variable or property, e.g.,

$\text{if}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}\mu \left(x\right)=:Class\text{then}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}\text{else}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}$
$\overline{x}$

Sequence of elements ${x}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{x}_{n}$. E.g., if we want to define a constraint that the owner of a members of a class $C$ is the class, we simply write

$C.\overline{members}.owner=C$

$\forall m\in C.members:m.owner=C$

or even more complicated with index variables.

Sequences are 1-based, e.g., a sequence $s$ with length $|s|=n$, has elements ${s}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{s}_{n}$.

## 2. Grammar

### 2.1. Lexical Conventions

As a super language on top of ECMAScript, the same lexical conventions are supported as described in [ECMA11a(p.S7)] within strict mode. Some further constraints are defined, however, restricting certain constructs. These constraints are described in the following.

#### 2.1.1. Identifier Names and Identifiers

As a reminder, identifiers are defined as follows in the ECMAScript specification:

IdentifierName: IdentifierStart* IdentifierPart;
IdentifierStart : UnicodeLetter | '_';
\ UnicodeEscapeSequence

N4JS supports a limited form of computed-names for member declarations:

N4JSPropertyComputedName:
'[' (SymbolLiteralComputedName | StringLiteralComputedName) ']'
;

SymbolLiteralComputedName: N4JSIdentifier '.' N4JSIdentifier ;

StringLiteralComputedName: STRING ;

As can be seen, a computed-name must be either

• a symbol reference, e.g., Symbol.iterator

• a string literal, i.e., a compile time known constant. This notation is useful when interoperating with libraries that define members whose names contain special characters (e.g., a field name starting with commercial-at)

In N4JS, identifiers are further constrained in order to avoid ambiguities and to make code more readable. Some of these constraints will lead to errors, others only to warnings. They do not apply for identifiers declared in definitions file (n4jsd) in order to enable declaration of external entities.

Req. IDE-1: N4JS Identifier Restrictions (ver. 1)

1. If the following constraints do not hold, errors are created.

#### 5.2.3. Methods

Methods are simply JavaScript functions. They are defined similarly to methods as proposed in [ECMA15a(p.S13.5)] except for the type information and some modifiers.

##### 5.2.3.1. Syntax
Syntax Method Declaration
N4MethodDeclaration <Yield>:
=> ({N4MethodDeclaration}
annotations+=Annotation*
accessModifier=N4JSMemberAccessModifier?
(abstract?=’abstract’ | static?=’static’)?
TypeVariables?
(
generator?='*' LiteralOrComputedPropertyName<Yield> -> MethodParamsReturnAndBody <Generator=true>
|   AsyncNoTrailingLineBreak LiteralOrComputedPropertyName<Yield> -> MethodParamsReturnAndBody <Generator=false>
)
) ';'?
;

fragment MethodParamsAndBody <Generator>*:
StrictFormalParameters<Yield=Generator>
(body=Block<Yield=Generator>)?
;

fragment MethodParamsReturnAndBody <Generator>*:
StrictFormalParameters<Yield=Generator>
(':' returnTypeRef=TypeRef)?
(body=Block<Yield=Generator>)?
;

fragment LiteralOrComputedPropertyName <Yield>*:
name=IdentifierName | name=STRING | name=NumericLiteralAsString
| '[' (=>((name=SymbolLiteralComputedName<Yield> | name=StringLiteralAsName) ']') | computeNameFrom=AssignmentExpression<In=true,Yield> ']')
;

SymbolLiteralComputedName <Yield>:
BindingIdentifier<Yield> ('.' IdentifierName)?
;

BindingIdentifier <Yield>:
IDENTIFIER
| <!Yield> 'yield'
| N4Keyword
;

IdentifierName: IDENTIFIER | ReservedWord | N4Keyword;
NumericLiteralAsString: DOUBLE | INT | OCTAL_INT | HEX_INT | SCIENTIFIC_INT;
StringLiteralAsName: STRING;

fragment AsyncNoTrailingLineBreak *: (declaredAsync?='async' NoLineTerminator)?;  // See Asynchronous Functions

fragment StrictFormalParameters <Yield>*:
'(' (fpars+=FormalParameter<Yield> (',' fpars+=FormalParameter<Yield>)*)? ')'
;

FormalParameter <Yield>:
{FormalParameter} BindingElementFragment<Yield>
;

fragment BindingElementFragment <Yield>*:
(=> bindingPattern=BindingPattern<Yield>
| annotations+=Annotation*
(
)
)
('=' initializer=AssignmentExpression<In=true, Yield>)?
;

fragment ColonSepTypeRef*:
':' declaredTypeRef=TypeRef
;
##### 5.2.3.2. Properties

Methods have all the properties of members and the following additional properties can be explicitly defined:

abstract

Method is declared but not defined.

typePars

Collection of type parameters of a generic method; empty by default.

returnTypeRef

Return type of the method, default return type is $Void$. The type of the method as a member of the owning classifier is not the method’s return type but is instead a function type.

fpars

List of formal parameters, may be left empty.

body

The body of the method (this is not available in the pure types model)

The following pseudo properties are defined via annotations:

final

Boolean flag set to true if annotation @Final is set. The flag indicates that method must not be overridden in subclasses; see Final Methods.

declaresOverride

Flag set to true if annotation @Overrides is set. The flag indicates that method must override a method of a superclass; see Overriding of Members.

Additionally, we define the following pseudo properties:

overrides

True if method overrides a super method or implements an interface method, false otherwise.

typeRef

Type of the method. This is, in fact, a function type (and not the return type).

The following pseudo property is set to make methods compatible with properties of an object literal, however it cannot be changed:

enumerable

Boolean flag reflecting the property descriptor $enumerable$, this is always set to false for methods.

##### 5.2.3.3. Semantics

Since methods are ECMAScript functions, all constraints specified in Function Type apply to methods as well. This section describes default values and function type conformance which is required for overriding and implementing methods.

In addition, method declarations and definitions have to comply with the constraints for naming members of classifiers (cf. [Req-IDE-52]) and with the constraints detailed in the following sections on final methods (Final Methods), abstract methods (Abstract Methods and method overriding and implementation (Overriding of Members, Implementation of Members).

The following constraints are defined for methods in ECMAScript 6 [ECMA15a(p.207)]

Req. IDE-53: Method Definition ECMAScript 6 (ver. 1)

• It is a Syntax Error if any element of the BoundNames of StrictFormalParameters also occurs in the VarDeclaredNames of FunctionBody.

• It is a Syntax Error if any element of the BoundNames of StrictFormalParameters also occurs in the LexicallyDeclaredNames of FunctionBody.

Methods – like functions – define a variable execution environment and therefore provide access to the actual passed-in parameters through the implicit arguments variable inside of their bodies (c.f. Arguments Object).

Methods are similar to function definitions but they must not be assigned to or from variables. The following code issues an error although the type of the method would be compatible to the type of the variable v:

class C {
m(): void {}
}
var v: {function():void} = new C().m;

Req. IDE-54: Method Assignment (ver. 1)

1. In contrast to ECMAScript 2015, methods are defined as readonly, that is, it is not possible to dynamically re-assign a property defined as method with a new value. This is because assigning or re-assigning a method breaks encapsulation. Methods are the Acronyms of a class, their implementation is internal to the class.

2. When assigning a method to a variable, a warning is issued since this would lead to an detached this reference inside the method when it is called without explicitly providing the receiver. No warning is issued only if it is guaranteed that no problems will occur:

1. The method’s body can be determined at compile time (i.e., it has been declared @Final) and it lacks usages of this or super. This is true for instance and static methods.

2. The method is the constructor.

 The following code demonstrates problems arising when methods are assigned to variables in terms of function expressions. Given are two classes and instances of each class as follows:
class C {
m(): void { }
static k(): void {}
}
class D extends C {
@Override m(): void { this.f()}
f(): void {}

@Override static k(): void { this.f()}
static f(): void {}
}
var c: C = new C();
var d: C = new D(); // d looks like a C

Assigning an instance method to a variable could cause problems, as the method assumes this to be bound to the class in which it is defined. This may work in some cases, but will cause problems in particular in combination with method overriding:

var v1: {@This(C)function():void} = c.m;
var v2: {@This(C)function():void} = d.m;

v1.call(c);
v2.call(c);

Calling c.m indirectly via v1 with c as this object will work. However, it won’t work for v2: the method is overridden in D, and the method in expects other methods available in D but not in C. That is, the last call would lead to a runtime error as method f which is called in D.m won’t be available.

The same scenario occurs in case of static methods if they are retrieved polymorphically via the variables of type constructor{C}:

var ctor: constructor{C} = C;
var dtor: constructor{C} = D;

var v3: {@This(constructor{C})function():void} = ctor.k;
var v4: {@This(constructor{C})function():void} = dtor.k;

In both cases, the problem could be solved by restricting these kinds of assignments to final methods only. In the static case, the problem would also be solved by accessing the static method directly via the class type (and not polymorphically via the constructor). Both restrictions are severe but would be necessary to avoid unexpected runtime problems.

The following example shows a problem with breaking the encapsulation of a class.

class C {
x: any = "";
f(): void { this.g(this); }
g(c: C): void { c.h(); }
h(): void {}
}
class D extends C {

@Override f(): void {
this.g(this.x);
}
@Override g(c: any) {
// do nothing, do not call h())
}
}

var c = new C();
var d = new D();

var v5: {@This(C)function():void} = c.f;
var v6: {@This(C)function():void} = d.f;

v5.call(c)
v6.call(c)

In D, method g is overridden to accept more types as the original method defined in C. Calling this new method with receiver type C (as done in the last line) will cause problems, as in D not only f has been adapted but also g. Eventually, this would lead to a runtime error as well.

##### 5.2.3.4. Final Methods

By default, methods can be overridden. To prevent a method from being overridden, it must be annotated with @Final.

Of course, a method cannot be declared both abstract and final (cf. [Req-IDE-46]). Private methods are implicitly declared final. Because static methods can be overridden in subclasses (which is different to Java), they also can be marked as final.

Default methods in interfaces, cf. Default Methods in Interfaces, may also be declared @Final.

Example 35. Final Methods in Interfaces

If a method in an interface is provided with a body, it may be declared final. This will ensure that the given method’s body will be in effect for all instances of the interface. Note that this means that;

1. a class implementing that interface must not define a method with the same name and

2. a class inheriting a method of that name cannot implement this interface.

The latter case is illustrated here:

interface I {
@Final m(): void {}
}

class C1 {
m(): void {}
}

// error at "I": "The method C1.m cannot override final method I.m."
class C2 extends C1 implements I {
}
##### 5.2.3.5. Abstract Methods

A method can be declared without defining it, i.e. without providing a method body, and is then called an abstract method. Such methods must be declared with modifier abstract and have their property $abstract$ set to true. Constraints for abstract methods are covered in [Req-IDE-46] (see Abstract Classes).

In interfaces, methods are always abstract by default and they do not have to be marked as abstract. If a method in an interface provides a body, then this is the default implementation. See Implementation of Members about how the default implementation may be mixed in the consumer.

##### 5.2.3.6. Generic Methods

Methods of generic classes can, of course, refer to the type variables defined by type parameters of the generic class. These type variables are used similarly to predefined or declared types. Additionally, methods may be declared generic independently from their containing class. That is to say that type parameters (with type variables) can be defined for methods as well, just like for generic functions (see Generic Functions).

For a given generic method M of a class C, the following constraint must hold:

Since type variables can be used similarly to types in the scope of a generic class, a generic method may refer to a type variable of its containing class.

class C {
<T> foo(p: T p): T { return p;}
};

If a generic type parameter is not used as a formal parameter type or the return type, a warning is generated unless the method overrides a member inherited from a super class or interface.

#### 5.2.4. Default Methods in Interfaces

If a method declared in an interface defines a body, then this is the so-called default implementation and the method is called a default method. This will be mixed into an implementor of the interface if, and only if, neither the implementing class nor any of its direct or indirect superclasses already provides an implementation for this method; for details see Member Consumption. Since the implementor is not known, some constraints exist for the body. I.e., no access to super is possible, cf. [Req-IDE-124].

In order to declare an interface to provide a default implementation in a definition file, annotation @ProvidesDefaultImplementation can be used, cf. [Req-IDE-167].

When a method in an interface is provided with a default implementation, it may even be declared @Final, see Final Methods.

##### 5.2.4.1. Asynchronous Methods

N4JS implements the async/await concept proposed for ECMAScript 7, which provides a more convenient and readable syntax for writing asynchronous code compared to using built-in type Promise directly. This concept can be applied to methods in exactly the same way as to declared functions. See Asynchronous Functions and Asynchronous Arrow Functions for details.

#### 5.2.5. Constructors

A constructor is a special function defined on a class which returns an instance of that class. The constructor looks like a normal method with name "constructor". The constructor can be defined explicitly or implicitly and every class has an (implicit) constructor.

For a given a class C, the constructor is available via two properties:

$ownedCtor$

the explicitly defined constructor (if any).

$ctor$

the explicit or implicit constructor.

If C is provided with an explicit constructor, we have $C.ctor=C.ownedCtor$ and $C.ownedCtor\in C.ownedMembers$. Note that $C.ctor\notin C.ownedMethods$ in all cases.

The return type of the constructor of a class C is C. If C has type parameters ${T}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{T}_{n}$, then the return type is $C<{T}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{T}_{n}>$. The constructor is called with the operator. Since the return type of a constructor is implicitly defined by the class, it is to be omitted. By this definition, a constructor looks like the following:

class C {
public constructor(s: string) {
// init something
}
}

Constructors define a variable execution environment and therefore provide access to the actual passed-in parameters through the implicit variable inside of their bodies (c.f. Arguments Object).

Req. IDE-56: Defining and Calling Constructors (ver. 1)

For a constructor $ctor$ of a class C, the following conditions must hold:

1. $ctor$ must neither be abstract nor static nor final and it must not be annotated with @Override.

2. If a class does not explicitly define a constructor then the constructor’s signature of the superclass constructor is assumed.

3. If a class defines a constructor with formal parameters then this constructor has to be called explicitly in constructors defined in subclasses.

4. If a super constructor is called explicitly, this call must be the only expression of an expression statement which has to be the first statement of the body.

5. Constructors may appear in interfaces, but some restrictions apply:

1. constructors in interfaces must not have a body.

2. constructors in interfaces or their containing interface or one of its direct or indirect super interfaces must be annotated with @CovariantConstructor.

6. A constructor must not have an explicit return type declaration.

7. The implicit return type of a constructor is this?.

8. A constructor must not have any type parameters.

Properties of object literals may be called constructor. However they are not recognized as constructors in these cases.

1. Required attributes must be initialized:
$\forall a\in C.attr:a.required⇒\exists e\in r.elements:a.name=e.name$

Note on syntax: ECMAScript 6 defines constructors similarly, [ECMA15a(p.S13.5)]. In ECMAScript 6 the super constructor is not called automatically as well.

The super literal used in order to call super methods is further described in The super Keyword.

##### 5.2.5.1. Structural This Type in Constructor

The use of a structural this reference as a formal parameter type is possible only in constructors. This parameter can be annotated with @Spec which causes the compiler to generate initialization code.

Simply using this as a type in the constructor causes the constructor to require an object providing all public fields of the class for initialization purposes. The fields have to be set manually as shown in the following code snippet.

class A{
public s: string;
public constructor(src: ~~this) {
this.s = src.s;
}
}

Remarks:

• The type of the formal parameter ~~this refers to the structural field type, see Structural Typing for details on structural typing. It contains all public fields of the type.

• Subclasses may override the constructor and introduce additional parameters. They have to call the super constructor explicitly, however, providing a parameter with at least all required attributes of the superclass. Usually the type this is replaced with the actual subclass, but in the case of a super() call the this type of structural formal parameters is replaced with the this type of the superclass, hence only required fields of the superclass must be present.

As with other structural references, it is possible to add the structural reference with additional structural members, which can be used to initialize private fields which become not automatically part of the structural field type. For example:

class A{
public s: string;
private myPrivateNumber: number;
public constructor(src: ~~this with { x: number; }) {
this.s = src.s;
this.myPrivateNumber = src.x;
}
}

Defining additional members may become a problem if a subclass defines public fields with the same name, as the ~~this type will contain these fields in the subclass. This is marked as an error in the subclass.

If the structural this type is used in a constructor of a class C, and if this structural reference contains an additional structural member $SM$, the following constraints must hold true:

1. For any subclass S of C, with $S.ctor=C.ctor$ (the subclass does not define its own constructor), S must not contain a public member with same name as $SM$:

$S<:C,S.ctor=C.ctor$ $\phantom{\rule{3.0em}{0ex}}⇒\nexists M\in S.members:$ $\phantom{\rule{5.0em}{0ex}}M.acc=\text{public}\wedge M.name=SM.name$

2. C itself must not contain a public member with same name as $SM$:

$\nexists M\in C.members:M.acc=\text{public}\wedge M.name=SM.name$
Example 36. Field name conflicts with structural member name

The situation described in [Req-IDE-58] is demonstrated in the following code fragment:

class A {
private myPrivateNumber: number;
public constructor(src: ~~this with { x: number; }) {
this.myPrivateNumber = src.x;
}
}

class B extends A {
public x: number; // will cause an error message
}
##### 5.2.5.2. @Spec Constructor

The tedious process of copying the members of the parameter to the fields of the class can be automated via the @Spec annotation if the argument has ~i~this structural initializer field typing. More details about this typing can be found in Structural Read-only, Write-only and Initializer Field Typing. This can be used as shown in the following listing:

class A {
public field: string;
public constructor(@Spec spec: ~i~this) {}
}
let a = new A({field: 'hello'});
console.log(a.field); // prints: hello

The code for initializing the public field of A is automatically generated, thanks to the @Spec annotation being given in the constructor.

Req. IDE-59: @Spec Constructor (ver. 1)

1. Annotation @Spec may only appear on a formal parameter of a constructor. Such a formal parameter is then called @Spec parameter or simply spec parameter and its owning constructor is referred to as a @Spec constructor or spec constructor. An argument to the spec parameter is called spec object.

2. Only a single formal parameter of a constructor may be annotated with @Spec.

3. If a formal parameter is annotated with @Spec, the parameter’s type must be ~i~this (i.e. a use-site structural initializer field type of this, see Structural Read-only, Write-only and Initializer Field Typing).

4. Using the data provided in the spec object, i.e. in the argument to the spec parameter, a spec constructor will automatically initialize

1. all owned data fields and owned setters of the containing class, and

2. all data fields and setters from interfaces implemented by the containing class

if and only if those members are also part of the spec parameter’s structural initializer field type.

5. Fields explicitly added to the spec parameter, e.g. @Spec spec: ~i~this with {name:string}, are used for initialization if a non-public field of the same name exists in the class, either as an owned member or from an implemented interface. The type of such an additional field must be a subtype of the declared type of the field being initialized:

$\forall s\in ctor.fpar.structuralMembers,ctor.fpar.spec:$
$\phantom{\rule{2.0em}{0ex}}\exists f\in ctor.owner.ownedFields⇒\Gamma ⊢s\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}f$

6. Even if the @Spec annotation is used, the super constructor must be invoked explicitly (as usual).

It follows from no. 4 above that

1. non-public data fields and setters are never initialized (because they will never be part of the spec parameter’s structural initializer field type),

2. properties provided in the spec object but not defined in the parameter’s structural initializer field type, are not used for initialization, even if a (protected or private) field of the same name exists in the class,

3. data fields and setters inherited from a super class are never initialized by a spec constructor (instead, this will happen in the spec constructor of the super class).

The last of these implications will be detailed further at the end of the coming section.

@Spec Constructors and Inheritance

Spec constructors are inherited by subclasses that do not have a constructor and, when creating instances of the subclass, will then require properties for writable public fields of the subclass in the spec object and include initialization code for them.

class A {
public fa;
public constructor(@Spec spec: ~i~this) {}
}
class B extends A {
public fb;
}

const b = new B({fa: 'hello', fb: 'world'}); // requires & initializes fb too!
console.log(b.fa); // prints: hello
console.log(b.fb); // prints: world

Public writable fields from implemented interfaces are included as well, i.e. required as property in spec object and initialized by auto-generated code in the @Spec constructor:

interface I {
public fi;
}
class B implements I {
public fb;
public constructor(@Spec spec: ~i~this) {}
}

const a = new B({fb: 'hello', fi: 'world'}); // requires & initializes fi too!
console.log(a.fb); // prints: hello
console.log(a.fi); // prints: world

When having a spec constructor in a class B that extends a super class A without an owned or inherited spec constructor, it should be noted that the ~i~this type will require properties for public writable fields of A, but the initialization code automatically generated due to the @Spec annotation will not initialize those members. For public writable fields from an interface I implemented by B, however, both a property will be required by ~i~this and initialization code will be generated in the @Spec constructor. This is illustrated in the following code example.

class A {
public fa;
}
interface I {
public fi;
}
class B extends A implements I {
public fb;
public constructor(@Spec spec: ~i~this) { // <- fa, fi, fb required in spec object
// Constructor is responsible for initializing fa, fi, fb.
// The @Spec annotation will generate initialization code
// for fb and fi, but not for fa!
}
}

let b = new B({
fa: 'hello', // <- fa is required (removing it would be a compile error)
fi: 'world',
fb: '!!'
});

console.log(b.fa); // undefined
console.log(b.fi); // world
console.log(b.fb); // !!

The rationale for this different handling of fields from super classes and implemented interfaces is 1. fields from an implemented interface are not seen as inherited but rather implemented by implementing class, so from the @Spec annotation’s perspective the field is a field of the implementing class, and 2. in case of a field inherited from a super class the correct way of initialization may depend on details of the super class and has to be taken care of by custom code in the constructor of the subclass (usually by invoking the non-@Spec constructor of the superclass with super).

Special Use Cases

The following examples illustrate further details of other use cases of spec constructors.

Example 37. Anonymous Interface in Constructor

The base class A in the examples redefines the constructor already defined in N4Object. This is not generally necessary and is only used here to make the example legible.

class A {
public s: string;
public constructor(@Spec spec: ~i~this) {
// initialization of s is automatically generated
}
}
class B extends A {
public t: string;
private n: number;
public constructor(spec: ~~this with {n: number;}) {
super(spec);    // only inherited field s is set in super constructor
}
}
Example 38. Spec Object and Subclasses
class A1 {
public s: string;
public n: number;
public constructor(@Spec spec: ~i~this) {}
}
class B extends A1 {
public constructor() {
super({s:"Hello"}); // <-- error, n must be set in object literal
}
}
class C extends A1 {
public constructor() {
super({s:"Hello"}); // <-- error, n must be set in object literal
this.n = 10; // <-- this has no effect on the super constructor!
}
}

class A2 {
public s: string;
public n: number?; // now n is optional!
public constructor(@Spec spec: ~i~this) {}
}
class D extends A2 {
public constructor() {
super({s:"Hello"}); // and this is ok now!
this.n = 10; // this explains why it is optional
}
}

class A3 {
public s: string;
public n: number = 10; // now n is not required in ~~this
public constructor(@Spec spec: ~i~this) {}
}
class E extends A3 {
public constructor() {
super({s:"Hello"}); // and this is ok now!
}
}

The last case (class E) demonstrates a special feature of the typing strategy modifier in combination with the this type, see Structural Typing for details.

The constructor in class B contains an error because the super constructor expects all required attributes in A1 to be set. The additional initialization of the required field A1.n as seen in C does not change that expectation. In this example, the field n should not have been defined as required in the first place.

Optional fields like n? in class A2 or fields with default values like n=10 in class A3 are not required to be part of the spec object.

Example 39. Superfluous Properties in @Spec Constructors

Each non-$\text{public}$ field has to be set in the constructor via the $\text{with}$ to the parameter otherwise properties are not used to set non-$\text{public}$ fields.

class C {
public s: string;
n: number;
constructor(@Spec spec: ~i~this) {}
}

// n is ignored here
new C( { s: "Hello", n: 42 });

// but:
var ol = { s: "Hello", n: 42 };
// "ol may be used elsewhere, we cannot issue warning here" at "ol"
new C(ol) ;

// of course this is true for all superfluous properties
// weird is not used in constructor
new C( { s: "Hello", weird: true } );
Restriction when initializing interface fields via @Spec constructor

In most cases, interface definitions in n4jsd files simply declare functions and fields that are supposed to be provided by the runtime environment. As a result, there are restrictions as to whether fields of interfaces defined in n4jsd files can initialized via @Spec constructors or not. In particular, fields of an interface declared in a n4jsd file cannot be initialized via @Spec constructor if the interface

1. is a built-in or

2. does not have an @N4JS annotation

The following example illustrates this restriction.

Example 40. Interface fields that cannot be initialized via @Spec constructors
Inf.n4jsd
export external interface I  {
public m: string;
}

@N4JS
export external interface J  {
public n: string;
}
Test.n4js
import { I } from "Inf";
// I is an external interface WITHOUT @N4JS annotation
class C implements I {
constructor(@Spec spec:~i~this) {}
}

// J is an external interface with @N4JS annotation
class D implements J {
constructor(@Spec spec:~i~this) {}
}

// XPECT warnings --> "m is a property of built-in / provided by runtime / external without @N4JS annotation interface I and can not be initialized in Spec constructor." at "m"
let c:C = new C({m: "Hello"});

// XPECT nowarnings
let d:D = new D({n: "Bye"});

console.log(c.m)
console.log(d.n)

/* XPECT output ---
<==
stdout:
undefined
Bye
stderr:
==>
--- */

In this example, the interface I is defined in the Inf.n4jsd file without the @N4JS annotation. As a result, its field m cannot be initialized via the @Spec constructor and hence the output of console.log(c.m) is undefined. On the other hand, since the interface J is declared with the annotation @N4JS, it is possible to initialize its field n in the @Spec constructor. That’s why the result of console.log(d.n) is Bye.

##### 5.2.5.4. Covariant Constructors

Usually, the constructor of a subclass need not be override compatible with the constructor of its super class. By way of annotation @CovariantConstructor it is possible to change this default behavior and enforce all subclasses to have constructors with override compatible signatures. A subclass can achieve this by either inheriting the constructor from the super class (which is usually override compatible, with the special case of @Spec constructors) or by defining a new constructor with a signature compatible to the inherited constructor. The same rules as for method overriding apply.

The @CovariantConstructor annotation may be applied to the constructor, the containing classifier, or both. It can also be used for interfaces; in fact, constructors are allowed in interfaces only if they themselves or the interface is annotated with @CovariantConstructor (see [Req-IDE-60]).

Definition: Covariant Constructor

A classifier C is said to have a covariant constructor if and only if one of the following applies:

1. C has a direct super class ${C}^{\text{'}}$ and ${C}^{\text{'}}$ is annotated with @CovariantConstructor or ${C}^{\text{'}}$ has a constructor annotated with @CovariantConstructor.

2. C has a directly implemented interface I and I is annotated with @CovariantConstructor or I has a constructor annotated with @CovariantConstructor.

3. C has a direct super class or directly implemented interface that has a covariant constructor (as defined here).

Note that C does not need to have an owned(!) constructor; also a constructor inherited from a super class can be declared covariant.

The following rules apply to covariant constructors.

Req. IDE-60: Covariant Constructors (ver. 1)

1. Annotation @CovariantConstructor may only be applied to classes, interfaces, and constructors. Annotating a constructor with this annotation, or its containing classifier, or both have all the same effect.

2. Given a class C with an owned constructor $ctor$ and a super class $Sup$ that has a covariant constructor (owned or inherited, see Covariant Constructors), then $Sup.constructor$ must be accessible from C,

1. $ctor$ must be override compatible with $S.constructor$:

$overrideCompatible\left(ctor,S.constructor\right)$

This constraint corresponds to [Req-IDE-72] except for the Override annotation which is not required here.

3. Given a classifier C implementing interface I and I has a covariant constructor (owned or inherited, see Covariant Constructors), we require

1. $I.constructor$ must be accessible from C,

2. an implementation-compatible constructor $ctor$ must be defined in C with

$overrideCompatible\left(ctor,I.constructor\right)$

This constraint corresponds to [Req-IDE-74] except for the @Override annotation, which is not required, here.

3. Given a classifier C without an owned constructor and an extended class or interface $Sup$ that has a covariant constructor (owned or inherited, see Covariant Constructors), we require the inherited constructor $ctor$ of C within the context of C to be override compatible to itself in the context of $Sup$. Using notation $m\left[T\right]$ to denote that a member M is to be treated as defined in container type T, which means the this-binding is set to T, we can write:

$overrideCompatible\left(ctor\left[C\right],ctor\left[Sup\right]\right)$

This constraint does not correspond to any of the constraints for the redefinition of ordinary members.

The following example demonstrates a use case for covariant constructors. It shows a small class hierarchy using covariant constructors, Cls and Cls2, together with a helper function createAnother that creates and returns a new instance of the same type as its argument value.

Example 41. Covariant Constructors
class A {}
class B extends A {}

@CovariantConstructor
class Cls {
constructor(p: B) {}
}
class Cls2 extends Cls {
constructor(p: A) { // it's legal to generalize the type of parameter 'p'
super(null);
}
}

function <T extends Cls> createAnother(value: T, p: B): T {
let ctor = value.constructor;
return new ctor(p);
}

let x = new Cls2(new A());
let y: Cls2;

y = createAnother(x, new B());

In the code of Covariant Constructors, we would get an error if we changed the type of parameter p in the constructor of Cls2 to some other type that is not a super type of B, i.e. the type of the corresponding parameter of Cls’s constructor. If we removed the @CovariantConstructor annotation on Cls, we would get an error in the new expression inside function createAnother.

The next example illustrates how to use @CovariantConstructor with interfaces and shows a behavior that might be surprising at first sight.

Example 42. Covariant Constructors in Interfaces
@CovariantConstructor
interface I {
constructor(p: number)
}

class C implements I {
// no constructor required!
}

class D extends C {
// XPECT errors --> "Signature of constructor of class D does not conform to overridden constructor of class N4Object: {function(number)} is not a subtype of {function()}." at "constructor"
constructor(p: number) {}
}

Interface I declares a covariant constructor expecting a single parameter of type number. Even though class C implements I, it does not need to define an owned constructor with such a parameter. According to [Req-IDE-60], it is enough for C to have a constructor, either owned or inherited, that is override compatible with the one declared by I. Class C inherits the default constructor from N4Object, which does not have any arguments and is thus override compatible to I’s constructor.

In addition, subclasses are now required to have constructors which are override compatible with the constructor of class C, i.e. the one inherited from N4Object. Covariant Constructors in Interfaces shows that this is violated even when repeating the exact same constructor signature from interface I, because that constructor now appears on the other side of the subtype test during checking override compatibility.

#### 5.2.6. Data Fields

A data field is a simple property of a class. There must be no getter or setter defined with the same name as the data field. In ECMAScript 6, a class has no explicit data fields. It is possible, however, to implicitly define a data field by simply assigning a value to a variable of the this element (e.g. this.x = 10 implicitly defines a field x). Data fields in N4JS are similar to these implicit fields in ECMAScript 6 except that they are defined explicitly in order to simplify validation and user assistance.

##### 5.2.6.1. Syntax
N4FieldDeclaration <Yield>:
{N4FieldDeclaration}
FieldDeclarationImpl<Yield>
;

fragment FieldDeclarationImpl <Yield>*:
(declaredModifiers+=N4Modifier)* BogusTypeRefFragment?
declaredName=LiteralOrComputedPropertyName<Yield>
(declaredOptional?='?')?
ColonSepTypeRef?
('=' expression=Expression<In=true,Yield>)?
Semi
;
##### 5.2.6.2. Properties

Fields have the following properties which can be explicitly defined:

declaredOptional

Tells whether the accessor was declared optional.

typeRef

Type of the field; default value is $Any$.

expr

Initializer expression, i.e. sets default value.

static

Boolean flag set to true if field is a static field.

const

Boolean flag set to true if field cannot be changed. Note that const fields are automatically static. Const fields need an initializer. Also see Assignment Modifiers.

 $const$ is not the (reversed) value of the property descriptor $writable$ as the latter is checked at runtime while const may or may not be checked at runtime.

The following pseudo properties are defined via annotations for setting the values of the property descriptor:

enumerable

Boolean flag reflecting the property descriptor $enumerable$, set via annotation @Enumerable(true|false). The default value is $\text{true}$.[32]

declaredWriteable

Boolean flag reflecting the property descriptor $writeable$, set via annotation @Writeable(true|false). The default value is $\text{true}$.[33]

final

Boolean flag making the field read-only, and it must be set in the constructor. Also see Assignment Modifiers.

###### Derived values for fields
readable

Always true for fields.

abstract

Always false for fields.

writeable

Set to false if field is declared const or final. In the latter case, it may be set in the constructor (cf. Assignment Modifiers).

###### 5.2.6.2.1. Semantics

Req. IDE-61: Attributes (ver. 1)

For any attribute $a$ if a class C, the following constraints must hold:

1. A required data field must not define an initializer:
$a.required⇒a.init=null$

2. There must be no other member with the same name of a data field f. In particular, there must be no getter or setter defined with the same name:

If a subclass should set a different default value, this has to be done in the constructor of the subclass.

For the relation of data fields and field accessors in the context of extending classes or implementing interfaces see Redefinition of Members.

###### 5.2.6.2.2. Type Inference

The type of a field is the type of its declaration:

$\frac{}{\Gamma ⊢f:\Gamma ⊢d}$

The type of a field declaration is either the declared type or the inferred type of the initializer expression:

$\phantom{\rule{3.0mm}{0ex}}\frac{d.declaredType\ne \text{null}\phantom{\rule{3.0mm}{0ex}}T=d.declaredType}{\Gamma ⊢d:T}$
$\phantom{\rule{3.0mm}{0ex}}\frac{d.declaredType=\text{null}\phantom{\rule{3.0mm}{0ex}}d.expression\ne \text{null}}{\Gamma ⊢d:T}$
$\phantom{\rule{3.0mm}{0ex}}E=\Gamma ⊢d.expression\phantom{\rule{3.0mm}{0ex}}E\notin \left\{\text{null, undefined}\right\}\phantom{\rule{3.0mm}{0ex}}T=E\right\}$
$\phantom{\rule{3.0mm}{0ex}}\frac{else}{\Gamma ⊢d:\text{any}}$

If the type contains type variables they are substituted according to type parameters which are provided by the reference:

##### 5.2.6.3. Assignment Modifiers

Assignment of data fields can be modified by the assignment modifiers const (similar to constant variable declarations, see Const) and @Final.

Req. IDE-62: Const Data Fields (ver. 1)

For a data field f marked as const, the following constraints must hold:

1. An initializer expression must be provided in the declaration (except in n4jsd files):
$f.expr\ne \text{null}$

2. A constant data field is implicitly static and must be accessed only via the classifier type. It is not possible, therefore, to use the this keyword in the initializer expression of a constant field:
$\nexists sub\in f.exp{r}^{*}:sub="this"$

3. A constant data field must not be annotated with @Final:
$f.const\to ¬f.final$

4. Constant data fields are not writeable (cf. [Req-IDE-68]):
$f.const\to ¬f.writeable$

Req. IDE-63: Final Data Fields (ver. 1)

For a data field f marked as @Final, the following constraints must hold:

1. A final data field must not be modified with const or static:
$f.final\to ¬f.const\wedge ¬f.declaredStatic$

2. A final data field is not writeable:
$f.final\to ¬f.writeable$
A final field may, however, be set in the constructor. See [Req-IDE-68] for details.

3. A final data field must be either initialized by an initializer expression or in the constructor. If the field is initialized in the constructor, this may be done either explicitly or via a spec style constructor.

$\begin{array}{c}\phantom{\rule{3.0mm}{0ex}}f.expr\ne \text{null}\\ \phantom{\rule{3.0mm}{0ex}}\vee \left(\exists assignExp:assignExpr.containingFunction=f.owner.constructor\\ \phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}\wedge assignExpr.left.target=\text{"this"}\\ \phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}\wedge bind\left(assignExpr.left.property,f\right)\right)\\ \phantom{\rule{3.0mm}{0ex}}\vee \left(f.public\wedge \exists fpar\in f.owner.constructor.fpars:\\ \phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}fpar.spec\wedge \exists sm\in structuralMembers:sm.name=f.name\right)\end{array}$
##### 5.2.6.4. Field Accessors (Getter/Setter)

Instead of a simple data field, a field can be defined by means of the getter and setter accessor methods. These accessor methods are similar to the accuser methods in object literals:

###### 5.2.6.4.1. Syntax
N4GetterDeclaration <Yield>:
=> ({N4GetterDeclaration}
(declaredModifiers+=N4Modifier)*
(body=Block<Yield>)? ';'?
;

BogusTypeRefFragment? 'get' -> declaredName=LiteralOrComputedPropertyName<Yield>
(declaredOptional?='?')?
'(' ')'
ColonSepTypeRef?
;

N4SetterDeclaration <Yield>:
=>({N4SetterDeclaration}
(declaredModifiers+=N4Modifier)*
'set'
->declaredName=LiteralOrComputedPropertyName <Yield>
)
(declaredOptional?='?')?
'(' fpar=FormalParameter<Yield> ')' (body=Block<Yield>)? ';'?
;

Notes with regard to syntax: Although ECMAScript 6 does not define fields in classes, it defines getter and setter methods similarly (cf. [ECMA15a(p.S13.3, p.p.209)]).

Example 43. Getter and Setter

The getter and setter implementations usually reference data fields internally. These are to be declared explicitly (although ECMAScript allows creating fields on the fly on their first usage). The following example demonstrates a typical usage of getter and setter in combination with a data field. The getter lazily initializes the field on demand. The setter performs some notification.

Getter Setter
class A {}

class C {
private _data: A = null;

public get data(): A {
if (this._data==null) {
this._data = new A();
}
return this._data;
}

public set data(data: A) {
this._data = data;
this.notifyListeners();
}

notifyListeners(): void {
// ...
}
}
###### 5.2.6.4.2. Properties

Properties for field accessors:

declaredOptional

Tells whether the accessor was declared optional.

readable

Derived value: true for getters and false for setters.

writable

Derived value: false for getters and true for setters.

###### 5.2.6.4.3. Semantics

There must be no field or method with the same name as a field accessor (follows from [Req-IDE-52]). In addition, the following constraints must hold:

Req. IDE-64: Field Accessors (ver. 1)

• The return type of a getter must not be void.

• The type of the parameter of a setter must not be void.

• If a getter $g$ is defined or consumed (from an interface) or merged-in (via static polyfill) in a class C and a setter S with $s.name=g.name\wedge s.static=g.static$ is inherited by C from one of its super classes, then C must define a setter ${s}^{\text{'}}$ with ${s}^{\text{'}}.name=g.name\wedge {s}^{\text{'}}.static=g.static$ [34].

• A setter must have exactly one formal parameter, i.e. variadic or default modifiers are not allowed.

The same applies to setters, accordingly.

 A getter and setter with the same name need not have the same type, i.e. the getter’s return type need not be the same as a subtype of the type of the setter’s parameter (the types can be completely unrelated).[35]

Getters and setters – like functions – define a variable execution environment and therefore provide access to the actual passed-in parameters through the implicit arguments variable inside of their bodies (c.f. Arguments Object).

##### 5.2.6.5. Optional Fields

Data fields and field accessors of a classifier C can be declared optional, meaning that a structural subtype of C need not provide this field, but if it does, the field must be of correct type. However, to ensure overall type safety, the scope of application of this optionality is limited to a small number of specific use cases, as described in the following.

###### 5.2.6.5.1. Syntax

To denote a data field or accessor as optional, a question mark is placed right after the name:

Syntax of optional fields
class C {
public field?: string;

public get getter?(): number {
return 42;
}
public set setter?(value: number) {}
}

The detailed grammar is given in the sections for data fields, cf. Syntax, and field accessors, cf. Syntax.

###### 5.2.6.5.2. Semantics

It is important to note that the optionality of a field is, by default and in most cases, ignored and has an effect only in certain special cases.

The effect of a field being optional is defined by the following requirement.

Req. IDE-240500: Optional Fields (ver. 1)

By default, a data field, getter, or setter that is declared optional is handled in the exact same way as if no optionality were involved (i.e. by default, optionality is ignored).

Optionality has an effect only in case of structural subtype checks $L<:R$ in which the left-hand side is one of the following:

1. an object literal.

2. a new expression.

3. an instance of a final class, i.e. the type of the value on left-hand side must be nominal and refer to a final class.

4. a reference to a const variable if its initializer expression is one of the following:

1. an object literal.

2. a new expression.

3. an instance of a final class (as explained above).

4. an ternary expression

and then

• in cases 1 and 4a, both fields and accessors (getters and setters) are optional. That means, an optional data field, getter, or setter of $R$ needs not be present in $L$.

• in cases 2, 3, 4b, and 4c, only getters are optional, setters are not optional. That means, an optional getter of $R$ needs not be present in $L$ and an optional field of $R$ requires only a setter in $L$. Note that these cases are more restricted than the cases 1 and 4a.

Moreover, optionality has an effect in case of ternary expression $L<:R$ in which the left-hand side is a ternary expression, e.g. l = b? trueExpr : falseExpr whose trueExpr or falseExpr possibly recursively contains an expression of the kind mentioned above. In this case, the optionality effect is the more restricted optinality of trueExpr and falseExpr.

If, according to these rules, a data field / getter / setter of $R$ need not be present in $L$ but a member with the same name and access is actually present in $L$, that member in $L$ must be a data field / getter / setter of the same type / a subtype / a super type, respectively. In other words, if a not actually required member is present in the subtype, ordinary rules for member compatibility apply as if no optionality were involved (cf. general subtyping rules for structural types).

In other words, in object literals (cases 1 and 4a) neither optional getters, optional setters, nor optional data fields are required. However, in case of new expressions and instances of final classes (cases 2, 3, 4b, 4c) only optional getters are not required in a subtype; optional setters are required as normal (i.e. optionality ignored) and optional data fields require at least a setter.

The following table summarizes the most common cases and shows how this relates to the different forms of structural typing.

 let x: ΔC = {}; let x: ΔC = new D0(); let x: ΔC = new DG(); let x: ΔC = new DS(); Δ Case Comment ~ ~~ ~w~ ~r~ ~i~ may have setter never has setter ✓ ✓ ✓ ✓ ✓ 1 nothing mandatory ✓ ✓ 2 setters mandatory ✓ ✓ 2 setters mandatory ✓ ✓ ✓ ✓ ✓ 2 setters mandatory none D0 not final none fooSF0() not nominal ✓ ✓ 3 setters mandatory

In the table, a "✓" means that the particular example is valid; in all other cases an error would be shown in N4JS source code. Here are the classes and functions used in the above table:

Classes and functions used in table
class C {
public field?: string;
}

class D0 {}

class DG {
public get field(): string { return "hello"; }
}

class DS {
public set field(value: string) {}
}

@Final class F0 {}

function fooD0(): D0   { return new D0(); }
function fooSF0(): ~F0 { return new F0(); }
function fooF0(): F0   { return new F0(); }

It follows from the above definitions in Requirements [Req-IDE-240500] that cases 4a and 4b are not transitive across a chain of several const variables, whereas case 4c is transitive. For example:

Transitivity of the use cases of optional fields
class C {
public get getter?(): string {return null;}
}
class D {}
@Final class F {}

let c: ~C;

// no transitivity via several const variables in use case "object literal":

const ol1 = {};
const ol2 = ol1;

// XPECT errors --> "~Object is not a structural subtype of ~C: missing getter getter." at "ol2"
c = ol2;

// no transitivity via several const variables in use case "new expression":

const new1 = new D();
const new2 = new1;

// XPECT errors --> "D is not a structural subtype of ~C: missing getter getter." at "new2"
c = new2;

// BUT: we do have transitivity via several const variables in use case "final nominal type":

const finalNominal1 = new F();
const finalNominal2 = finalNominal1;

// XPECT noerrors -->
c = finalNominal1;
// XPECT noerrors --> "transitivity applies in this case"
c = finalNominal2;

The following example demonstrates how optionality behaves in ternay expressions.

Optional fields in ternay expressions
interface ~I {
public m?: int;
}

class ~C { }

@Final class F { }

let b: boolean;
const cc: C = {}
let f1 = new F();
let f2: ~F = {};

// True expression is a const object literal, so both fields and accessors in I are optional.
// False expression is a new expression, so only getters in I are optionals.
// As a result, only getters in I are optional.
// XPECT errors --> "C is not a structural subtype of I: missing field m." at "b? cc : new C()"
var te1: I = b? cc : new C()

// No errors because both true and false expressions are object literal constants and hence
// Both fields and accessors in I are optional.
// XPECT noerrors
var te2: I = b? cc : {}
###### 5.2.6.5.3. Background

The following example illustrates why optionality of fields has to be restricted to the few special cases defined above (i.e. object literals, new expressions, etc.).

Problem 1 of optional fields
class C {
public field?: string = "hello";
}

class D {}
class DD extends D {
public field: number = 42;
}

let c: ~C;
let d: D;

d = new DD();

c = d;  // without the restrictive semantics of optional fields, this assignment would be allowed (but shows compile-time error in N4JS)

console.log(c.field); // prints 42 even though the type is string
c.field.charAt(0); // exception at runtime: c.field.charAt is not a function

In the last line of the above example, c.field is actually 42 but the type systems claims it is of type string and thus allows accessing member charAt of type string which is undefined at runtime the actual value 42.

The next example shows why cases 2 and 3 (i.e. new expressions and instances of final classes) have to be handled in a more restrictive manner than case 1 (i.e. object literals).

Problem 2 of optional fields
class C {
public field?: string;
}

class D {}

let c: ~C;

c = new D(); // error: new expression but D is missing setter

c.field = "hello";

In the previous code, if c = new D() were allowed, we would add a new property field to the instance of class D in the last line, which N4JS aims to avoid in general, unless unsafe language features such as dynamic types are being employed.

#### 5.2.7. Static Members

Static data fields, field accessors and methods are quite similar to instance members, however they are not members of instances of the type but the type itself. They are defined similarly to instance members except that they are specified with the modifier static. Since they are members of the type, the this keyword is not bound to instances of the class, but again to the type itself. This is similar as in ECMAScript 6 ([ECMA15a(p.14.5.15)]). Since static members are not instance but type members, it is even possible that a static member has the same name as an instance member.

Note that static members are not only allowed in classes but also in interfaces, but there are important differences (for example, no inheritance of static members of interfaces, cf. Section Static Members of Interfaces).

Req. IDE-65: Static member not abstract (ver. 1)

For a static field accessor or method S, the following constraint must hold:

• $s.static⇔¬s.abstract$

Like instance methods, static methods of classes are inherited by subclasses and it is possible to override static methods in subclasses. The very same override constraints are valid in this case as well.

##### 5.2.7.1. Access From and To Static Members

Req. IDE-66: Accessing Static Members (ver. 1)

Let M be a static member of class C. Except for write-access to fields, which will be explained later, you can access M via:

1. The class declaration instance, i.e. the classifier or constructor type, constructor{C}, i.e. C.m

2. The class declaration instance of a subtype, i.e. the classifier or constructor type, i.e. D.m, if D is a subclass of C.

3. v.m, if v is a variable of type C (i.e. classifier type as defined in Constructor and Classifier Type) or a subtype thereof.

4. this.m inside the body of any static method declared in C or any sub-class of C.

5. Via a type variable T which upper bound is a subclassof C e.g., function <T extends C> f(){T.m}

Req. IDE-67: Static Member Access (ver. 1)

It is not possible to access instance members from static members. This is true in particular for type variables defined by a generic classifier.

For static data fields and static setter f the following constraint must hold:

• For every assign expression $assignExpr$ with $f.static\wedge assignExpr.left=T.f⇒T=f.owner$.

• For every writing unary expression $u$ with $u.op\in \left\{++,--\right\}\wedge f.static\wedge u.expression=T.f⇒T=f.owner$.

In the special case of m being a static data field, write-access is only possible via the defining type name C.m. In the list above, only the first line can be used when assigning values to a field. Note that this only applies to fields and set-accessors.[36]

It is even possible to call a static field accessor or method of a class using dynamic polymorphism, as demonstrated in the following example:

Example 44. Static members of classes, inheritance and polymorphism
class A {
static m(): void { console.log('A#m'); }

static foo(): void { console.log('A#foo'); }

static bar(): void {
this.foo();
}
}

class B extends A {
@Override
static foo(): void { console.log('B#foo'); }
}

A.m(); // will print "A#m"
B.m(); // will print "A#m" (m is inherited by B)

var t: type{A} = A;
t.foo(); // will print "A#foo"
t = B;
t.foo(); // will print "B#foo"

// using 'this':

A.bar(); // will print "A#foo"
B.bar(); // will print "B#foo"

This is quite different from Java where static methods are not inherited and references to static methods are statically bound at compile time depending on the declared type of the receiver (and not its value):

Example 45. Static members in Java
// !!! JAVA CODE !!!
public class C {

static void m() { System.out.println("C#m"); }

public static void main(String[] args) {
final C c = null;
c.m();  // will print "C#m" (no NullPointerException at runtime)
}
}
##### 5.2.7.2. Generic static methods

It is not possible to refer to type variables of a generic class, as these type variables are never bound to any concrete types. A static method can, however, be declared generic. Generic static methods are defined similarly to generic instance methods. Since they cannot refer to type variables of a generic class, the constraint to avoid type variables with equal names (see [Req-IDE-55]) does not need to hold for generic static methods.

##### 5.2.7.3. Static Members of Interfaces

Data fields, field accessors and methods of interfaces may be declared static. A few restrictions apply:

Req. IDE-69: Static Members of Interfaces (ver. 1)

1. Static members of interfaces may only be accessed directly via the containing interface’s type name (this means, of the four ways of accessing static members of classes defined in [Req-IDE-66] above, only the first one applies to static members of interfaces).

2. The this literal may not be used in static methods or field accessors of interfaces and it may not be used in the initializer expression of static fields of interfaces. See [Req-IDE-173].

3. The super literal may not be used in static methods or field accessors of interfaces (in fact, it may not be used in interfaces at all, cf. [Req-IDE-123]).

Note that the this type as a return type for methods is only allowed for instance methods and as an argument type only in constructors (structurally typed). There is no need to disallow these cases for static interface methods in the constraints above.

In general, static members may not be abstract, cf. [Req-IDE-46], which applies here as well. Static methods and field accessors of interfaces, therefore, always have to provide a body.

Static members of interfaces are much more restricted than those of classes. Compare the following example to Static Polymorphism for classes above:

Example 46. Static members of interfaces
interface I {
static m(): void { console.log('I#m'); }
}

interface J extends I {}

I.m(); // prints "I#m"
J.m(); // ERROR! (m is not inherited by J)

var ti: type{I} = I;
ti.m(); // ERROR! (access to m only allowed directly via type name I)
ti = J;
ti.m(); // ERROR! (access to m only allowed directly via type name I)

The last line in is the reason why access to static members has to be restricted to direct access via the type name of the containing interfaces.

#### 5.2.8. Redefinition of Members

Members defined in classes or interfaces can be redefined by means of being overridden or implemented in subclasses, sub-interfaces, or implementing classes. Fields and methods with default implementation defined in interfaces can be consumed by the implementor, but certain restrictions apply.

Req. IDE-70: Override Compatible (ver. 1)

A member M is override compatible to a member S if and only if the following constraints hold:

1. The name and static modifiers are equal:
$M.name=S.name\wedge M.static=S.static$

2. The metatypes are compatible:

$\mu \left(S\right)=\text{Method}\phantom{\rule{3.0mm}{0ex}}\to \phantom{\rule{3.0mm}{0ex}}\mu \left(M\right)=\text{Method}$
$\mu \left(S\right)=\text{Field}\phantom{\rule{3.0mm}{0ex}}\to \phantom{\rule{3.0mm}{0ex}}\mu \left(M\right)\in \text{Field, Getter, Setter}$
$\mu \left(S\right)=\text{Getter}\phantom{\rule{3.0mm}{0ex}}\to \phantom{\rule{3.0mm}{0ex}}\mu \left(M\right)\in \text{Field, Getter}$
$\mu \left(S\right)=\text{Setter}\phantom{\rule{3.0mm}{0ex}}\to \phantom{\rule{3.0mm}{0ex}}\mu \left(M\right)\in \text{Field, Setter}$

3. The overridden member must not be declared final:
$¬S.final$

4. Overridden member declared const can only be overridden (redefined) by const members:
$S.const⇔M.const$

5. It is not possible to override a non-final / non-const field or a setter with a final / const field:
$\left(\mu \left(S\right)=\text{Field}\wedge ¬\left(S.final\vee S.const\right)\right)\vee \mu \left(S\right)=\text{Setter}⇒¬\left(\mu \left(M\right)=\text{Field}\wedge \left(M.final\vee M.const\right)\right)$

6. It is not possible to override a non-abstract member with an abstract one:
$¬M.abstract\vee S.abstract$

7. The types are compatible:

$\left(\mu \left(M\right)\in \text{Method, Getter, Field}\wedge \mu \left(S\right)\ne \text{Setter}\right)\phantom{\rule{3.0mm}{0ex}}\to \Gamma ⊢M\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}S$
$\left(\mu \left(M\right)\in \text{Setter, Field}\wedge \mu \left(S\right)\ne \text{Getter}\wedge ¬S.const\right)\phantom{\rule{3.0mm}{0ex}}\to \Gamma ⊢S\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}M$4

8. The access modifier is compatible:
$M.acc\ge S.acc$

We define a relation $overrideCompatible\left(M,S\right)$ accordingly.

Members overriding or implementing other members must be declared as override. If a member does not override another, however, it must not be declared as override.

Req. IDE-71: Non-Override Declaration (ver. 1)

If and only if a member M of a class C (extending a class S and interfaces ${I}_{i}$) does not override or implement another member, then it must not be declared as override. That is the following constraint must hold:

$\phantom{\rule{3.0mm}{0ex}}¬M.override$
$\phantom{\rule{3.0mm}{0ex}}\wedge$
$\phantom{\rule{3.0mm}{0ex}}\nexists {M}^{\text{'}}\in C.super.members\cup {\bigcup }_{i=1}^{n}{I}_{i}.members:$
$\phantom{\rule{3.0mm}{0ex}}{M}^{\text{'}}.name=M.name\wedge {M}^{\text{'}}.static=M.static$
$\phantom{\rule{3.0mm}{0ex}}\wedge {M}^{\text{'}}.acc>\text{private}$

##### 5.2.8.1. Overriding of Members

In general, the N4JS platform supports overriding members by redefining them in sub-classes. This definition allows for overriding of static methods, but it does not apply to constructors because $C.ctor\notin C.ownedMethods$.

Req. IDE-72: Overriding Members (ver. 1)

Given a class C and a superclass $Sup$. If for an instance or static member M defined in C a member S exists with null then we call M the overriding member and S the overridden member. In that case the following constraints must hold:

1. S must be accessible from C

2. M must be override compatible with S:
$overrideCompatible\left(M,S\right)$

3. If S is a field and M is an accessor, then an additional accessor ${M}^{\text{'}}$ must exists so that $M,{M}^{\text{'}}$ are an accessor pair for S:

$\phantom{\rule{3.0mm}{0ex}}\mu \left(S\right)=\text{Field}\wedge \mu \left(M\right)=Accessor$
$\phantom{\rule{3.0mm}{0ex}}\to \exists {M}^{\text{'}}\in C.member:$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{4.0em}{0ex}}overrideCompatible\left({M}^{\text{'}},S\right)\wedge \left\{\mu \left(M\right),\mu \left({M}^{\text{'}}\right)\right\}=\text{Getter,Setter}$

4. M must be declared as override:
M.override

Remarks:

• An overridden method, getter, or setter may called via super. Note that this is not possible for fields.

• There is no ’hiding’ of fields as in Java, instead there is field overriding.

• It is not possible to override a field with a consumed getter and an overridden setter, because the getter is not consumed if there exists a field in a superclass. In this case, the consuming and extending class needs to define the accessor pair explicitly. The same is true for other combination of accessors and fields.

• Overriding a field usually makes only sense if the visibility of the field is to be increased.

##### 5.2.8.2. Implementation of Members

For the following constraints, we define two helper sets ${M}_{C}$ and ${M}_{I}$ as follows:

Given a C, and interface ${I}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{I}_{n}$, implemented by C, with

${M}_{C}\phantom{\rule{3.0mm}{0ex}}=C.ownedMembers\cup \left\{m\in C.superType.members|m.acc>\text{private}\right\}$
${M}_{I}\phantom{\rule{3.0mm}{0ex}}={\bigcup }_{i=1}^{n}{I}_{i}.members$

Note that these sets already contain only non-private data fields.

###### 5.2.8.2.1. Member Consumption

A member M defined in an interface I is consumed by an implementor C, if it becomes a member of the class, that is, $M\in C.members$.

A member M is consumed if there is no member defined in the implementor with the same name and if there is no non-private, non-abstract member with that name inherited by the implementor from its superclass. [37]

If the implementor defines the member itself, then the member is implemented rather than consumed.

The concrete rules are described in the following;

It is not always possible to directly consume a member. In general, a rather conservative strategy is used: if two implemented interfaces define the same (non-abstract) member then the implementor must redefine the member in order to solve conflicts. Even if the two conflicting members have the same types, the implementor must redefine them as we generally assume semantic differences which the consumer has to be aware of. Data fields defined in interfaces, in particular, are assumed to be concrete. It is not, therefore, possible to consume a field defined in two implemented interfaces.

Req. IDE-73: Consumption of Interface Members (ver. 1)

Given a classifier C [38], and interfaces ${I}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{I}_{n}$ implemented (or extended) by C, and sets ${M}_{C}$ and ${M}_{I}$ as defined in [interface_and_class_member_sets]. A non-static member M defined in any interface ${I}_{i}$ is merged into the consumer (C), if for all other (possible) members ${M}^{\text{'}}$ of C

$\forall {M}^{\text{'}}\in {M}_{C}\cup {M}_{I}\setminus \left\{M\right\}:M.name={M}^{\text{'}}.name\wedge ¬{M}^{\text{'}}.static$

the following constraints hold:

1. The other member’s meta type matches the meta type of the merge candiate:

$\mu \left(M\right)=\text{Method}\phantom{\rule{3.0mm}{0ex}}\to \mu \left({M}^{\text{'}}\right)=\text{Method}$
$\mu \left(M\right)\ne \text{Method}\phantom{\rule{3.0mm}{0ex}}\to \mu \left({M}^{\text{'}}\right)\in \text{Field, FieldAccessor}$

2. The other member is abstract and not owned by the consumer:

$\phantom{\rule{3.0mm}{0ex}}\mu \left(M\right)=\mu \left({M}^{\text{'}}\right)\vee \mu \left(M\right)=\text{Field}$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{2.0em}{0ex}}\to {M}^{\text{'}}.abstract\wedge {M}^{\text{'}}\notin C.ownedMembers$

3. The merge candidate’s access modifier is not less than the modifier of the other member:

$\phantom{\rule{3.0mm}{0ex}}\mu \left(M\right)=\mu \left({M}^{\text{'}}\right)\vee \mu \left(M\right)=\text{Field}$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{2.0em}{0ex}}\to M.acc\ge {M}^{\text{'}}.acc$

4. The merge candidate’s type compatible with the other member:

$\mu \left(M\right)\in \left\{\text{Method, Getter, Field}\right\}\wedge \mu \left({M}^{\text{'}}\right)\ne \text{Setter}\phantom{\rule{3.0mm}{0ex}}\to \Gamma ⊢M\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}{M}^{\text{'}}$
$\mu \left(M\right)\in \left\{\text{Setter, Field}\right\}\wedge \mu \left({M}^{\text{'}}\right)\ne \text{Getter}\phantom{\rule{3.0mm}{0ex}}\to \Gamma ⊢{M}^{\text{'}}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}M$

###### 5.2.8.2.2. Member Implementation

Req. IDE-74: Implementation of Interface Members (ver. 1)

For any non-static abstract member M defined in an interface I implemented (or extended) by a classifier C, M must be accessible from C and one or two member(s) in C must exist which are implementation-compatible with M. The implementing member(s) must be declared as override if they are directly defined in the consumer.

1. M must be accessible from C.

2. An implementation-compatible member ${M}^{\text{'}}$ must exist in C:

1. if M is not a field:

$\mu \left(M\right)\ne \text{Field}\phantom{\rule{3.0mm}{0ex}}\to$
$\phantom{\rule{3.0mm}{0ex}}\exists {M}^{\text{'}}\in C.members:$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}overrideCompatible\left({M}^{\text{'}},M\right)$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}\wedge \left({M}^{\text{'}}\in C.ownedMembers\to {M}^{\text{'}}.override\right)$

2. if M is a field, then either an implementation-compatible field ${F}^{\text{'}}$ or accessor pair ${G}^{\text{'}},{S}^{\text{'}}$ must exist:

$\mu \left(M\right)=\text{Field}\phantom{\rule{3.0mm}{0ex}}\to$
$\phantom{\rule{3.0mm}{0ex}}\exists {F}^{\text{'}}\in C.fields:$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}overrideCompatible\left({F}^{\text{'}},M\right)$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}\wedge \left({F}^{\text{'}}\in C.ownedMembers\to {F}^{\text{'}}.override\right)$
$\phantom{\rule{3.0mm}{0ex}}\vee$
$\phantom{\rule{3.0mm}{0ex}}\exists {G}^{\text{'}}\in C.getters,{S}^{\text{'}}\in C.setters:$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}overrideCompatible\left({G}^{\text{'}},M\right)$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}\wedge overrideCompatible\left({S}^{\text{'}},M\right)$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}\wedge \left({G}^{\text{'}}\in C.ownedMembers\to {G}^{\text{'}}.override\right)$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}\wedge \left({S}^{\text{'}}\in C.ownedMembers\to {S}^{\text{'}}.override\right)$

Methods defined in interfaces are automatically declared abstract if they do not provide a default implementation. This can also be expressed explicitly via adding the abstract modifier. If a class implementing an abstract interface does not implement a method declared in the interface, the class needs to be declared abstract (cf. Abstract Classes).

Consequences for method implementation:

1. It may be require the implementor to explicitly define a method in order to solve type conflicts produced by methods of different interfaces with same name but different signatures.

2. Methods in an implementor cannot decrease the accessibility of methods from implemented interfaces, that is

$\phantom{\rule{3.0mm}{0ex}}\forall M\in C.methods,{M}^{\text{'}}\in {I}_{i}.methods\left(i=1.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}n\right):$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{2.0em}{0ex}}M.name={M}^{\text{'}}.name\to M.acc\ne private⇒M.acc\ge {M}^{\text{'}}.acc$

3. Methods in the implementor must be a supertype [39] of methods from implemented interfaces. That is to say the implemented methods are override-compatible.

4. There may be several methods ${M}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{M}_{n}$ defined in different implemented interfaces and a single owned method ${M}^{\text{'}}$ in ${M}_{C}$. In this case, the above constraints must hold for all methods. In particular, ${M}^{\text{'}}$’s signature must conform to all conflicting methods’ signatures. This is possible by using union types for the arguments and an intersection type as return type. Such a method ${M}^{\text{'}}$ is said to resolve the conflict between the implemented (and also inherited) methods.

5. Since abstracts methods may become part of the implementor methods, the implementor must either define these methods or it must be declared abstract itself. Since interfaces are abstract by default, responsibility for implementing abstract methods is passed on to any implementor of interfaces.

6. If two implemented interfaces provide (non-abstract) members with the same name, they are not automatically consumed by the implementor even if the types would be similar. In these cases, the implementor has to redefine the members in order to be aware of possible semantic differences.

There is currently no separate annotation to indicate that methods are implemented or overridden in order to solve conflicts. We always use the @Override annotation.

Example 47. Method Consumption

Consumption of methods shows simple examples of above rules. Assuming that class C extends super class S and implements interface I1 and I2:

class C extends S implements I1, I2 {...}

The columns describe different scenarios in which a method (with same name) is defined in different classifiers. We assume that the defined methods are always non-abstract (i.e. have default implementations), non-private and have the same signature. The last row shows which method will be actually used in class C. If the method is defined in class C, and if this method is printed bold, then this means that the method is required to be defined in C in order to solve conflicts.

 Interface I1 Interface I2 class S class C $\in C.members$ MI1 MI1 MI1 MI1 MI1 MI1 MI2 MI2 MI2 MS MS MS MC MC MC MI1 MC MC MS MS MC
Consuming Field Initializers

Aside from the fields themselves, an implementor always consumes the field initialization if the field is consumed – this is how the consumption is noticed at runtime.

Example 48. Field and Field Initializer Consumption
/* XPECT  output ~~~
<==
stdout:
s: C , t: D ,u: I1 ,v: I2
stderr:
==>
~~~ */

interface I0 {
v: string = "I0";
}

interface I1 {
s: string = "I1";
t: string = "I1";
u: string = "I1";
}

interface I2 extends I1, I0 {
@Override
t: string = "I2";
@Override
v: string = "I2";
}

class C {
s: string = "C";
}

class D extends C implements I1, I2 {
@Override
t: string = "D";
}

var d = new D();

console.log(
"s:", d.s, ", t:", d.t, ",u:", d.u, ",v:", d.v
)

We expect the following output (for each field):

• d.s = "C" : s: is inherited from C, so it is not consumed from I1 (or I2). Consequently, the initializer of s in C is used.

• d.t = "D": t is defined in D, solving a conflict stemming from the definition of t in I1 and I2. Thus, the initializer of t in D is used.

• d.u = "I1" : u is only defined in I1, thus the initializer defined in I1 is used.

• d.v = "I2" : v is overridden in I2, so is the field initializer. This is why d.v must be assigned to I2 and not I0.

### 5.3. Structural Typing

In general, N4JS uses nominal typing. This is to say that a duck is a duck only if it is declared to be a duck. In particular when working with external APIs, it is more convenient to use structural or duck typing. That is, a thing that can swim and quacks like a duck, is a duck.

Interfaces or classes can be used for this purpose with a typing strategy modifier. Given a type $T$, the simple ~ (tilde) can be added to its declaration (on definition-site) or in a reference (on use-site) to indicate that the type system should use structural typing rather than nominal typing.[40] This means that some other type must provide the same members as type $T$ to be deemed a structural subtype. However, the operator cannot be used anymore with the type or reference as this operator relies on the declaration information (or at least the closest thing available at runtime). In this case, $T$ is, therefore, always a structural subtype of ~T.

Sometimes it is convenient to refer only to the fields of a classifier, for example when the initial field values are to be provided in a variable passed to the constructor. In that case, the type can be modified with ~~ (two tildes). This is only possible on use-site, i.e. on type references. Furthermore, only on the use-site, it is possible to consider only either readable or writable or fields by using the read-only ~r~ or write-only ~w~ structural field typing. For initialization blocks, it is even possible to use structural initializer field typing via the ~i~ operator.

#### 5.3.1. Syntax

Structural typing is specified using the typing strategy modifier. There are two modifiers defined; one for definition-site and one for use-site structural typing.

Structural Type Operator and References
TypingStrategyUseSiteOperator returns TypingStrategy:
'~' ('~' | STRUCTMODSUFFIX)?;

TypingStrategyDefSiteOperator returns TypingStrategy:
'~';

terminal STRUCTMODSUFFIX:
('r' | 'i' | 'w') '~'
;

ParameterizedTypeRefStructural returns ParameterizedTypeRefStructural:
definedTypingStrategy=TypingStrategyUseSiteOperator
declaredType=[Type|TypeReferenceName]
(=> '<' typeArgs+=TypeArgument (',' typeArgs+=TypeArgument)* '>')?
(=> 'with' '{' astStructuralMembers+=TStructMember* '}')?
;

ThisTypeRefStructural returns ThisTypeRefStructural:
definedTypingStrategy=TypingStrategyUseSiteOperator
'this'
('with' '{' astStructuralMembers+=TStructMember* '}')?
;

#### 5.3.2. Definition Site Structural Typing

An interface or class can be defined to be used with structural typing by adding the structural modifier to its definition (or, in case of external classes, to the declaration). This changes the default type system strategy from nominal to structural typing for that type. That means that all types with the same members as the specified type are subtypes of that type, except for subtypes of N4Object. In the latter case, programmers are enforced to nominal declare the type relation.

If a type $T$ is declared as structural at its definition, $T.defStructural$ is true.

Req. IDE-75: Definition Site Structural Typing (ver. 1)

1. The structurally defined type cannot be used on the right hand side of the instanceof operator:

2. A type $X$ is a subtype of a structurally defined type $T$ either

1. if it is not a subtype of N4Object [41] but it contains all public, non-static members of that type

$X\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}\left\{\text{N4Object}\right\}\phantom{\rule{3.0em}{0ex}}T.defStructural\right\}$
$\forall m\in T.members,m.acc=\text{public},¬m.static,m\ne T.ctor:\right\}$
$\phantom{\rule{1.0em}{0ex}}\exists {m}^{\text{'}}\in X.members:\right\}$
$\phantom{\rule{2.0em}{0ex}}{m}^{\text{'}}.acc=\text{public}\wedge ¬{m}^{\text{'}}.static\wedge {m}^{\text{'}}.name=m.name\right\}$
$\phantom{\rule{2.0em}{0ex}}\wedge \Gamma ⊢{m}^{\text{'}}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}m\right\}$
$\frac{\phantom{\rule{2.0em}{0ex}}\wedge \mu \left(m\right)=\text{Field}⇒\Gamma ⊢m\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}{m}^{\text{'}}}{\phantom{\rule{13.0em}{0ex}}\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}T\phantom{\rule{13.0em}{0ex}}}$
or

2. if it is a subtype of N4Object which explicitly extends or implements the structurally defined type.

$\frac{X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\left\{\text{N4Object}\right\}\phantom{\rule{3.0mm}{0ex}}T.defStructural\phantom{\rule{3.0mm}{0ex}}T\in X.superType{s}^{*}}{\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}T}$
3. A structurally defined type $T$ is implicitly derived from Object if no other type is specified. In particular, a structurally defined type must not be inherited from

$\frac{T.defStructural}{\Gamma ⊢T\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\text{Object}}$

$T.defStructural⇒\Gamma ⊢T\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}\text{N4Object}\wedge \text{N4Object}\notin T.superType{s}^{*}$

Example 49. Declaration Site Structural Typing

The following snippet demonstrates the effect of definition-site structural types by comparing them to nominal declared types:

Declaration Site Structural Typing
interface ~Tilde { x; y; }
interface Nominal { x; y; }
class C { public x; public y;}
class D extends C implements Tilde { }

function f(p: Tilde) {}
function g(p: Nominal) {}

f(new C());         // error: nominal typing, C does not implement ~Tilde
f(new D());         // ok, D is a nominal subtype (as it implements Tilde)
f({x:10,y:10});     // ok: Tilde is used with structural typing for non-N4-classifiers

Definition site structural typing may lead to unexpected results. For example;

class C{}
class ~E extends C{}

It may be unexpected, but E is not a subtype of C, i.e. $E\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}C$! E.g., instanceof won’t work with E, while it works with C!

#### 5.3.3. Use-Site Structural Typing

Use-site structural typing offers several typing strategy modifiers to define the accessability of public properties of classes and interfaces. They can be used e.g. on variable declarations like this: var c : ~C. The table Available Fields of Structural Types shows which properties of structural types can be accessed in the different type strategies. For example, when using the write-only structural strategy (i.e. $~\text{w}~\text{X}$), only the writeable fields, can be accessed for writing. In the table, the term field to both, public datafields and accessors of type $X$. Non-public properties are never accessable in use-site structural types. In any field-structural type, methods of the referenced nominal type $X$ are not available. The initializer structural typing provides readable fields for every writeable field of the references type.

Table 9. Available Fields of Structural Types
Property of $X$ $~\text{X}$ $~~\text{X}$ $~\text{r}~\text{X}$ $~\text{w}~\text{X}$ $~\text{i}~\text{X}$

public method

$\varnothing$

$\varnothing$

$\varnothing$

$\varnothing$

public writable field

$\varnothing$

$\varnothing$

$\varnothing$

writable fields

Multiple structural typing strategies can be nested when there are multiple use sites, like in the example Nested Structural Typing Strategies below at the locations ST1 and ST2. In the example, the datafield a.field has the nested structural type ~r~ ~i~ A and thus the datafield a.field.df is readable. Nested structural types are evaluated on the fly when doing subtype checks.

Example 50. Nested Structural Typing Strategies
class A {
public df : string;
}
interface I<T> {
public field : ~r~T; // ST1
}
var a : ~i~A; // ST2

The following example demonstrates the effect of the structural type modifiers:

Example 51. Effect of structural type modifiers on use-site

Let’s assume the type defined on the left. The following pseudo code snippets explicitly list the type with its members virtually created by a structural modifier. Note that this is pseudo code, as there are no real or virtual types created. Instead, only the subtype relation is defined accordingly:

Effect of structural type modifiers on use-site

Effect of structural type modifiers on use-site

var c:C

class C {
private x;
public y;
public f()
private g()
public get z():Z
public set z(z:Z)
}
interface I {
a;
func();
}
var cstructural:~C

class cstructural {

public y;
public f()

public get z():Z
public set z(z:Z)
}
interface ~I {
a;
func();
}
var cfields:~~C

class cfields {

public y;

public get z():Z
public set z(z:Z)
}
interface ~~I {
a;

}

Type

Structural Type

Structural Field Type

Structural Read-only Field Type Structural Write-only Field Type Structural Initializer Field Type var crofields:~r~C class crofields { public get y():Y public get z():Z } interface ~r~I { public get a():A } var cwofields:~w~C class cwofields { public set y(y:Y) public set z(z:Z) } interface ~w~I { public set a(a:A) } var cinitfields:~i~C class cinitfields { public get y():Y public get z():Z } interface ~i~I { public get a():A }

Note that even if a type is defined without the structural modifier, it is not possible to use instanceof for variables declared as structural, as shown in the next example:

Type Structural Type Structural Field Type class C {..} interface I {..} foo(c: C, i: I) { c instanceof C; // ok c instanceof I; // ok } class C {..} interface I {..} foo(c: ~C, i: ~I) { c instanceof C; // error c instanceof I; // error } class C {..} interface I {..} foo(c: ~~C, i: ~~I) { c instanceof C; // error C instanceof I; // error }
• If a type is referenced with the structural type modifier ~ , the property $T.refStructural$ is true.

• If a type is referenced with the structural field type modifier ~~, the property $T.refStructuralField$ is true.

• If a type is referenced with the structural read-only field type modifier ~r~, the property $T.refStructuralReadOnlyField$ is true.

• If a type is referenced with the structural write-only field type modifier ~w~, then the property $T.refStructuralWriteOnlyField$ is true.

• If a type is referenced with the structural initializer field type modifier ~i~, then the property $T.refStructuralInitField$ is true.

We call the following:

• $T$ the (nominal) type T,

• $~\text{T}$ the structural version of $T$,

• $~~\text{T}$ the structural field version of $T$,

• $~\text{r}~\text{T}$ the structural read-only field,

• $~\text{w}~\text{T}$ the structural write-only field and

• $~\text{i}~\text{T}$ the structural initializer field version of $T$.

Req. IDE-76: Use-Site Structural Typing (ver. 1)

1. The structural version of a type is a supertype of the nominal type:
$T\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}:~\text{T}$

2. The structural field version of a type is a supertype of the structural type:
$~\text{T}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}:~~\text{T}$

3. The structural read-only field version of a type is a supertype of the structural field type:
$~~\text{T}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}:~\text{r}~\text{T}$

4. The structural write-only field version of a type is a supertype of the structural field type:
$~~\text{T}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}:~\text{w}~\text{T}$

5. The structural (field) version of a type cannot be used on the right hand side of the instanceof operator:

$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}⇒¬\left(T.refStructural$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{6.0em}{0ex}}\vee T.refStructuralField$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{6.0em}{0ex}}\vee T.refStructuralReadOnlyField$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{6.0em}{0ex}}\vee T.refStructuralWriteOnlyField$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{6.0em}{0ex}}\vee T.refStructuralInitField\right)$

That is, the following code will always issue an error: x instanceof ~T [42].

6. A type $X$ is a subtype of a structural version of a type $~\text{T}$, if it contains all public, non-static members of the type $T$: [43]

$\forall m\in T.members,m.owner\notin \text{N4Object},m.acc=\text{public},¬m.static,m\ne T.ctor:$
$\phantom{\rule{1.0em}{0ex}}\exists {m}^{\text{'}}\in X.members:$
$\phantom{\rule{2.0em}{0ex}}{m}^{\text{'}}.acc=\text{public}\wedge ¬{m}^{\text{'}}.static\wedge {m}^{\text{'}}.name=m.name$
$\frac{\phantom{\rule{2.0em}{0ex}}\wedge \Gamma ⊢{m}^{\text{'}}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\Gamma ⊢m}{\phantom{\rule{13.0em}{0ex}}\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\Gamma ⊢~\text{T}\phantom{\rule{13.0em}{0ex}}}$

7. A type $X$ is a subtype of a structural field version of a type $~~\text{T}$, if it contains all public, non-static fields of the type $T$. Special cases regarding optional fields are described in Optional Fields.

$\forall m\in T.fields,m.owner\notin \text{N4Object},m.acc=\text{public},¬m.static$

$\phantom{\rule{3.0em}{0ex}}{m}^{\text{'}}.acc=\text{public}\wedge ¬{m}^{\text{'}}.static\wedge {m}^{\text{'}}.name=m.name$
$\phantom{\rule{3.0em}{0ex}}\wedge \Gamma ⊢{m}^{\text{'}}:{T}_{m}\wedge \Gamma ⊢m:{T}_{{m}^{\text{'}}}\wedge {T}_{m}={T}_{{m}^{\text{'}}}\right\}$
$\frac{\phantom{\rule{3.0em}{0ex}}\wedge {m}^{\text{'}}.assignability\ge m.assignability}{\phantom{\rule{13.0em}{0ex}}\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}~~\text{T}\phantom{\rule{13.0em}{0ex}}}$

8. A type $X$ is a subtype of a structural read-only field version of a type $~\text{r}~\text{T}$, if it contains all public and non-static readable fields of the type $T$. Special cases regarding optional fields are described in Optional Fields.

$\forall m\in T.fields\cup T.getters,m.owner\notin \text{N4Object},m.acc=\text{public},¬m.static$

$\phantom{\rule{3.0em}{0ex}}{m}^{\text{'}}.acc=\text{public}\wedge ¬{m}^{\text{'}}.static\wedge {m}^{\text{'}}.name=m.name$
$\phantom{\rule{3.0em}{0ex}}\wedge \Gamma ⊢{m}^{\text{'}}:{T}_{m}\wedge \Gamma ⊢m:{T}_{{m}^{\text{'}}}\wedge {T}_{m}={T}_{{m}^{\text{'}}}$
$\frac{\phantom{\rule{3.0em}{0ex}}\wedge {m}^{\text{'}}.assignability\ge m.assignability}{\phantom{\rule{13.0em}{0ex}}\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}~\text{r}~\text{T}\phantom{\rule{13.0em}{0ex}}}$

9. A type $X$ is a subtype of a structural write-only field version of a type $~\text{w}~\text{T}$, if it contains all public and non-static writable fields of the type $T$. Special cases regarding optional fields are described in Optional Fields.

$\forall m\in T.fields\cup T.setters,m.owner\notin \text{N4Object},m.acc=\text{public},¬m.static,¬m.final$

$\phantom{\rule{3.0em}{0ex}}{m}^{\text{'}}.acc=\text{public}\wedge ¬{m}^{\text{'}}.static\wedge {m}^{\text{'}}.name=m.name$
$\phantom{\rule{3.0em}{0ex}}\wedge \Gamma ⊢{m}^{\text{'}}:{T}_{m}\wedge \Gamma ⊢m:{T}_{{m}^{\text{'}}}\wedge {T}_{m}={T}_{{m}^{\text{'}}}$
$\frac{\phantom{\rule{3.0em}{0ex}}\wedge {m}^{\text{'}}.assignability\ge m.assignability}{\phantom{\rule{13.0em}{0ex}}\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}~\text{w}~\text{T}\phantom{\rule{13.0em}{0ex}}}$

10. A type $X$ is a subtype of a structural field version of a type $~~\text{this}$, if it contains all public, non-static fields, either defined via data fields or field get accessors, of the inferred type of this. Special cases regarding optional fields are described in Optional Fields.

$\Gamma ⊢this:T$
$\forall m\in T.fields\cup T.setters,m.owner\notin \text{N4Object},m.acc=\text{public},¬m.static$
$\vee m.expr\ne \text{null}$

$\phantom{\rule{3.0em}{0ex}}{m}^{\text{'}}.acc=\text{public}\wedge ¬{m}^{\text{'}}.static\wedge {m}^{\text{'}}.name=m.name$
$\frac{\phantom{\rule{3.0em}{0ex}}\wedge \Gamma ⊢{m}^{\text{'}}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}m\wedge {m}^{\text{'}}.assignability\ge m.assignability}{\phantom{\rule{13.0em}{0ex}}\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}~~\text{t}his\phantom{\rule{13.0em}{0ex}}}$

11. A structural field type $~~\text{T}$ is a subtype of a structural type $~\text{X}$, if $~\text{X}$ only contains fields (except methods inherited from Object) and if $~~\text{T}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}~~\text{X}$.

$\frac{X.methods\setminus \text{Object}.methods=\varnothing \wedge \Gamma ⊢~~\text{T}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}~~\text{X}}{\Gamma ⊢~~\text{T}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}~\text{X}}$
12. Use-site structural typing cannot be used for declaring supertypes of classes or interfaces. That is to say that structural types cannot be used after extends, implements or with in type declarations [44].

Note that all members of N4Object are excluded. This implies that extended reflective features (cf. Reflection meta-information ) are not available in the context of structural typing. The instanceof operator is still working as described in Relational Expression, in that it can be used to check the type of an instance.

If a type $X$ is a (nominal) subtype of T, it is, of course, also a subtype of $~\text{T}$:

$\frac{\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\Gamma ⊢T}{\Gamma ⊢X\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\Gamma ⊢~\text{T}}$

This is only a shortcut for the type inference defined above.

Req. IDE-77: Definition and Use-Site Precedence (ver. 1)

If a type is structurally typed on both definition and use-site, the rules for use-site structural typing ([Req-IDE-76]) are applied.

Example 52. Use-Site Structural Typing

The following example demonstrates the effect of the structural (field) modifier, used in this case for function parameters.

interface I { public x: number; public foo()};
class C { public x: number; public foo() {}};

function n(p: I) {}
function f(p: ~I) {}
function g(p: ~~I) {}

n(new C());     // error: nominal typing, C does not implement I
f(new C());     // ok: C is a (structural) subtype of ~I
f({x:10});      // error, the object literal does not provide function foo()
g({x:10});      // ok: object literal provides all fields of I
Example 53. Structural types variable and instanceof operator

It is possible to use a variable typed with a structural version of a type on the left hand side of the instanceof operator, as demonstrated in this example:

class C {
public x;
public betterX() { return this.x||1;}
}

function f(p: ~~C) {
if (p instanceof C) {
console.log((p as C).betterX);
} else {
console.log(p.x||1);
}
}

The following table describes the member availability of X in various typing scenarios. Such as ~~X, ~r~X, ~w~X, ~i~X.

Table 10. Member Availability in various Typing Scenarios
Member of type X ~~X ~r~X ~w~X ~i~X

private m0;

—

—

—

—

public set m1(m) { }

write

—

write

public get m2() {…​}

—

public m3;

write

public m4 = 'init.m4';

write

public m5: any?;

write

read$?$

@Final public m6 = 'init.m6';

@Final public m7;

public get m8() {…​}

write

public set m8(m) { }

#### 5.3.4. Structural Read-only, Write-only and Initializer Field Typing

Structural read-only, write-only and initializer field typings are extensions of structural field typing. Everything that is defined for the field structural typing must comply with these extension field typings. For the read-only type, readable fields (mutable and @Final ones) and setters are considered, for the write-only type; only the setters and mutable fields are considered. Due to the hybrid nature of the initializer type it can act two different ways. To be more precise, a type $X$ (structural initializer field type) is a supertype of $Y$ (structural initializer field type) if for each public, non-static, non-optional writable field (mutable data field of setter) of $X$, there is a corresponding, public, non-static readable field of $Y$. All public member fields with @Final annotation are considered to be mandatory in the initializer field typing @Spec constructors. The already-initialized @Final fields can be either omitted from, or can be re-initialized via, an initializer field typing @Spec style constructor.

Example 54. Subtype relationship between structural field typing
class A1 {
public s: string;
}

class A2 {
public set s(s: string) { }
public get s(): string { return null; }
}

class A3 {
@Final public s: string = null;
}

class A4 {
public get s(): string { return null; }
}

class A5 {
public set s(s: string) { }
}
 A1 ~A1 ~~A1 ~r~A1 ~r~A2 ~r~A3 ~r~A4 ~r~A5 ~w~A1 ~w~A2 ~w~A3 ~w~A4 ~w~A5 ~i~A1 ~i~A2 ~i~A3 ~r~A4 ~r~A5 A1 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~A1 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~~A1 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~r~A1 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~r~A2 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~r~A3 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~r~A4 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~r~A5 ✓ ✓ ✓ ✓ ✓ ~w~A1 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~w~A2 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~w~A3 ✓ ✓ ✓ ✓ ✓ ~w~A4 ✓ ✓ ✓ ✓ ✓ ~w~A5 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~i~A1 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~i~A2 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~i~A3 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~r~A4 ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ~r~A5 ✓ ✓ ✓ ✓ ✓

#### 5.3.5. Public Setter Annotated With ProvidesInitializer

Public setters with ProvidesInitializer annotation can declare optional fields implemented by means of field accessors instead of data fields. Data fields with an initializer are treated as optional in the initializer field type.

It is important to note that it is valid to use the ProvidesInitializer annotation for setters in n4js files and not only definition files.

Example 55. Setters with @ProvidesInitializer treated as optional
class C {
private _y: int = 1;

public get y() { return this._y; }
@ProvidesInitializer
public set y(v: int) { this._y = v; }

public constructor(@Spec spec: ~i~this) { }
}

console.log(new C({}).y); // 1
console.log(new C({y: 42}).y); //24

#### 5.3.6. Structural Types With Optional Fields

Public optional fields become a member of the structural (field) type as well. To ensure the overall type safety, the semantics of optionality (e.g. on or off) depends on the context, in which the optional fields are currently being used (See Optional Fields).

#### 5.3.7. Structural Types With Access Modifier

The access modifier of the subtype have to provide equal or higher visibility.

Example 56. Access modifier in structural typing
class C {
public s: number;
}
class D {
project s: number;
}
function f(c: ~C) {}
f(new D()); // error: D is no (structural) subtype of ~C, as visibility of s in D is lower
function g(d: ~D) {}
g(new C()); // ok: C is a (structural) subtype of ~D, as visibility of s in C is greater-than-or-equal to s in D

#### 5.3.8. Structural Types With Additional Members

It is possible to add additional members when structurally referencing a declared type.

##### 5.3.8.1. Syntax
TStructMember:
TStructGetter | TStructGetterES4 | TStructSetter | TStructMethod | TStructMethodES4 | TStructField;

TStructMethod:
=>
({TStructMethod} ('<' typeVars+=TypeVariable (',' typeVars+=TypeVariable)* '>')?
returnTypeRef=TypeRef name=TypesIdentifier '(')
(fpars+=TAnonymousFormalParameter (',' fpars+=TAnonymousFormalParameter)*)? ')'
';'?;

TStructMethodES4 returns TStructMethod:
=>
({TStructMethod} ('<' typeVars+=TypeVariable (',' typeVars+=TypeVariable)* '>')?
name=TypesIdentifier '(')
(fpars+=TAnonymousFormalParameter (',' fpars+=TAnonymousFormalParameter)*)? ')'
(':' returnTypeRef=TypeRef)?
';'?;

TStructField:
(
typeRef=TypeRef name=TypesIdentifier
| name=TypesIdentifier (':' typeRef=TypeRef)?
)
';';

TStructGetter:
=> ({TStructGetter}
declaredTypeRef=TypeRef
'get'
name=TypesIdentifier)
'(' ')' ';'?;

TStructGetterES4 returns TStructGetter:
=> ({TStructGetter}
'get'
name=TypesIdentifier)
'(' ')' (':' declaredTypeRef=TypeRef)? ';'?;

TStructSetter:
=> ({TStructSetter}
'set'
name=TypesIdentifier)
'(' fpar=TAnonymousFormalParameter ')' ';'?;

TAnonymousFormalParameter:
| variadic?='...'? (=> name=TIdentifier ':') typeRef=TypeRef;
###### 5.3.8.1.1. Semantics

Req. IDE-78: Additional structural members (ver. 1)

It is only possible to add additional members to a type if use-site structural typing is used.

The following constraints must hold:

1. For all additional members defined in a structural type reference, the constraints for member overriding ([Req-IDE-72]) apply as well.

2. All additional members have the access modifier set to public.

3. Type variables must not be augmented with additional structural members.

Additional fields may be declared optional in the same way as fields in classes. The rules given in Structural Types With Optional Fields apply accordingly. Consider the following example:

Example 57. Additional optional members in structural typing
class C {
public f1: number;
}

var c1: ~C with { f3: string; } c1;
var c2: ~C with { f3: string?; } c2;

c1 = { f1:42 };  // error: "~Object with { number f1; } is not a subtype of ~C with { string f3; }."
c2 = { f1:42 };  // ok!!

Augmenting a type variable T with additional structural members can cause collisions with another member of a type argument for T. Hence, type variables must not be augmented with additional structural members like in the following example.

Example 58. Forbidden additional structural members on type variables
interface I<T> {
public field : ~T with {prop : int} // error "No additional structural members allowed on type variables."
}

Using an additional structural member on a type variable T could be seen as a constraint to T. However, constraints like this should be rather stated using an explicit interface like in the example below.

Example 59. Use explicitly defined Interfaces
interface ~J {
prop : int;
}
interface II<T extends J> {
}

## 6. Functions

Functions, be they function declarations, expressions or even methods, are internally modeled by means of a function type. In this chapter, the general function type is described along with its semantics and type constraints. Function definitions and expressions are then introduced in terms of statements and expressions. Method definitions and special usages are described in Methods.

### 6.1. Function Type

A function type is modeled as Object (see [ECMA11a(p.S13, p.p.98)] in ECMAScript.

Function types can be defined by means of;

#### 6.1.1. Properties

In any case, a function type declares the signature of a function and allows validation of calls to that function. A function type has the following properties:

typePars

(0-indexed) list of type parameters (i.e. type variables) for generic functions.

fpars

(0-indexed) list of formal parameters.

returnType

(possibly inferred) return type (expression) of the function or method.

name

Name of function or method, may be empty or automatically generated (for messages).

body

The body of the function, it contains statements $stmts$. The body is null if a function type is defined in a type expression, and it is the last argument in case of a function object constructor, or the content of the function definition body.

Additionally, the following pseudo properties for functions are defined:

thisTypeRef

The this type ref is the type to which the this-keyword would be evaluated if used inside the function or member. The inference rules are described in This Keyword.

fpars

List of formal parameters and the this type ref. This is only used for sub typing rules. If this is not used inside the function, then any is set instead of the inferred thisTypeRef to allow for more usages. The property is computed as follows:

$tfpars=\text{if}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}\phantom{\rule{3.0mm}{0ex}}\text{this is used or explicitly declared}\phantom{\rule{3.0mm}{0ex}}\text{then}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}thisTypeRef+fpars\phantom{\rule{3.0mm}{0ex}}\text{else}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}any+fpars$

Parameters (in $pars$) have the following properties:

name

Name of the parameter.

type

Type (expression) of the parameter. Note that only parameter types can be variadic or optional.

The function definition can be annotated similar to Methods except that the final and abstract modifiers aren’t supported for function declarations. A function declaration is always final and never abstract. Also, a function has no property advice set.

#### Semantics

Req. IDE-79: Function Type (ver. 1)

Type Given a function type $F$, the following constraints must be true:

1. Optional parameters must be defined at the end of the (formal) parameter list. In particular, an optional parameter must not be followed by a non-optional parameter:

$F.fpar{s}_{i}.optional\to \nexists k>i:¬F.fpar{s}_{k}.optvar$
2. Only the last parameter of a method may be defined as variadic parameter:

$F.fpar{s}_{i}.variadic\to i=|F.fpars|-1$
3. If a function explicitly defines a return type, the last statement of the transitive closure of statements of the body must be a return statement:

$F.typeRef\ne Undefined\to$
$|f.body.stmts|>0$

4. If a function explicitly defines a return type, all return statements must return a type conform to that type:

$\phantom{\rule{3.0mm}{0ex}}F.typeRef\ne Undefined$
$\phantom{\rule{3.0mm}{0ex}}⇔$

$\phantom{\rule{3.0mm}{0ex}}r.expr\ne null\wedge \left[\phantom{\rule{-0.167em}{0ex}}\left[r.expr.typeRef\right]\phantom{\rule{-0.167em}{0ex}}\right]<:\left[\phantom{\rule{-0.167em}{0ex}}\left[F.typeRef\right]\phantom{\rule{-0.167em}{0ex}}\right]$

#### 6.1.2. Type Inference

For the given non-parameterized function types ${F}_{left}$ with ${F}_{left}.tfpars={L}_{0},{L}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}{L}_{k}$ and $|{F}_{left}.typesPars|=0$
${F}_{right}$ with ${F}_{right}.tfpars={R}_{0},{R}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}{R}_{n}$ and $|{F}_{right}.typesPars|=0$,
we say ${F}_{left}$ conforms to ${F}_{right}$, written as ${F}_{left}<:{F}_{right}$, if and only if:

• ${F}_{right}.returnType=\text{void}$
$\vee \left({F}_{left}.returnType=\text{void}\wedge {F}_{right}.opt\right)$
$\vee \left({F}_{left}.returnType<:{F}_{right}.returnType\wedge ¬\left({F}_{left}.opt\wedge ¬{F}_{right}.opt\right)\right)$

• if $k\le n$:

• else ($k>n$):

Function Variance Chart shows a simple example with the function type conformance relations.

Figure 6. Function Variance Chart

{function()} $<:$ {function(A)} $<:$ {function(A, A)} might be surprising for Java programmers. However, in JavaScript it is possible to call a function with any number of arguments independently from how many formal parameters the function defines.

If a function does not define a return type, any is assumed if at least one of the (indirectly) contained return statements contains an expression. Otherwise void is assumed. This is also true if there is an error due to other constraint violations.

with

$\begin{array}{c}\phantom{\rule{3.0mm}{0ex}}\frac{\left\{r\in F.body.statements|\mu \left(r\right)=\text{ReturnStatement}\right\}\cup \bigcup _{s\in F.body.statements}returns\left(s\right)}{returns\left(F\right):RETS}\\ \phantom{\rule{3.0mm}{0ex}}\frac{\left\{sub\in s.statements|\mu \left(sub\right)=\text{ReturnStatement}\right\}\cup \bigcup _{sub\in s.statements}returns\left(sub\right)}{returns\left(s\right):RETS}\end{array}$
Example 60. Function type conformance

The following incomplete snippet demonstrates the usage of two function variables $f1$ and $f2$, in which $\left[\phantom{\rule{-0.167em}{0ex}}\left[f2\right]\phantom{\rule{-0.167em}{0ex}}\right]<:\left[\phantom{\rule{-0.167em}{0ex}}\left[f1\right]\phantom{\rule{-0.167em}{0ex}}\right]$ must hold true according to the aforementioned constraints. A function bar declares a parameter $f1$, which is actually a function itself. $f2$ is a variable, to which a function expression is a assigned. Function bar is then called with $f2$ as an argument. Thus, the type of $f2$ must be a subtype of the $f1$’s type.

function bar(f1: {function(A,B):C}) { ... }

var f2: {function(A,B):C} = function(p1,p2){...};
bar(f1);

The type of this can be explicitly set via the @This annotation.

Example 61. Function Subtyping
function f(): A {..}
function p(): void {..}

fAny(log: {function():any}) {...}
fVoid(f: {function():void}) {..}
fA(g: {function():A}) {...}

fAny(f);    // --> ok       A <: any
fVoid(f);   // -->error     A !<: void
fA(f);      // --> ok (easy)    A <: A

fAny(p);    // --> ok       void <: any
fVoid(p);   // --> ok       void <: void
fA(p);      // --> error    void !<: A
Example 62. Subtyping with function types

If classes A, B, and C are defined as previously mentioned, i.e. $C<:B<:A$, then the following subtyping relations with function types are to be evaluated as follows:

       {function(B):B} <: {function(B):B}           -> true
{function():A} <: {function():B}            -> false
{function():C} <: {function():B}            -> true
{function(A)} <: {function(B)}             -> true
{function(C)} <: {function(B)}             -> false

{function():void} <: {function():void}         -> true
{function():undefined} <: {function():void}         -> true
{function():void} <: {function():undefined}    -> true (!)

{function():B} <: {function():void}         -> true (!)
{function():B} <: {function():undefined}    -> false (!)
{function():void} <: {function():B}            -> false
{function():undefined} <: {function():B}            -> true

The following examples demonstrate the effect of optional and variadic parameters:

{function(A)} <: {function(B)}                      -> true
{function(A...)} <: {function(A)}                   -> true
{function(A, A)} <: {function(A)}                   -> false
{function(A)} <: {function(A,A)}                    -> true (!)
{function(A, A...)} <: {function(A)}                -> true
{function(A)} <: {function(A,A...)}                 -> true (!)
{function(A, A...)} <: {function(B)}                -> true
{function(A?)} <: {function(A?)}                    -> true
{function(A...)} <: {function(A...)}                -> true
{function(A?)} <: {function(A)}                     -> true
{function(A)} <: {function(A?)}                     -> false
{function(A...)} <: {function(A?)}                  -> true
{function(A?)} <: {function(A...)}                  -> true (!)
{function(A,A...)} <: {function(A...)}              -> false
{function(A,A?)} <: {function(A...)}                -> false
{function(A?,A...)} <: {function(A...)}             -> true
{function(A...)} <: {function(A?,A...)}             -> true
{function(A...)} <: {function(A?)}                  -> true
{function(A?,A?)} <: {function(A...)}               -> true (!)
{function(A?,A?,A?)} <: {function(A...)}            -> true (!)
{function(A?)} <: {function()}                      -> true (!)
{function(A...)} <: {function()}                    -> true (!)

The following examples demonstrate the effect of optional return types:

{function():void} <: {function():void}              -> true
{function():X}    <: {function():void}              -> true
{function():X?}   <: {function():void}              -> true
{function():void} <: {function():Y}                 -> false
{function():X}    <: {function():Y}                 -> X <: Y
{function():X?}   <: {function():Y}                 -> false (!)
{function():void} <: {function():Y?}                -> true (!)
{function():X}    <: {function():Y?}                -> X <: Y
{function():X?}   <: {function():Y?}                -> X <: Y
{function():B?} <: {function():undefined}    -> false (!)
{function():undefined} <: {function():B?}           -> true

The following examples show the effect of the @This annotation:

{@This(A) function():void} <: {@This(X) function():void}    -> false
{@This(B) function():void} <: {@This(A) function():void}    -> false
{@This(A) function():void} <: {@This(B) function():void}    -> true
{@This(any) function():void} <: {@This(X) function():void}  -> true
{function():void} <: {@This(X) function():void}             -> true
{@This(A) function():void} <: {@This(any) function():void}  -> false
{@This(A) function():void} <: {function():void}             -> false

For the given function types
${F}_{left}$ with ${F}_{left}.tfpars={L}_{0},{L}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}{L}_{k}$
${F}_{right}$ with ${F}_{right}.tfpars={R}_{0},{R}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}{R}_{n}$,
we say ${F}_{left}$ conforms to ${F}_{right}$, written as ${F}_{left}<:{F}_{right}$, if and only if:

• if $|{F}_{left}.typePars|=|{F}_{right}.typePars|=0$:

• else if
$|{F}_{left}.typePars|>0\wedge |{F}_{right}.typePars|=0$:

• $\exists \theta :\left(\Gamma ←\theta \right)⊢{F}_{left}<:{F}_{right}$ (cf. Function Type Conformance Non-Parameterized )

(i.e. there exists a substitution $\theta$ of type variables in ${F}_{left}$ so that after substitution it becomes a subtype of ${F}_{right}$ as defined by Function Type Conformance Non-Parameterized)

• else if $|{F}_{left}.typePars|=|{F}_{right}.typePars|$:

• $\Gamma ←\left\{{V}_{i}^{r}←{V}_{i}^{l}|0\le i\le n\right\}⊢{F}_{left}<:{F}_{right}$ ( accordingly)

• -

$\begin{array}{c}\forall 0\le i\le n:\\ intersection\left\{{V}_{i}^{l}.upperBounds\right\}:>intersection\left\{{V}_{i}^{r}.upperBounds\right\}\end{array}$

with ${F}_{left}.typePars={V}_{0}^{l},{V}_{1}^{l},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}{V}_{n}^{l}$ and ${F}_{right}.typePars={V}_{0}^{r},{V}_{1}^{r},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}{V}_{n}^{r}$
(i.e. we replace each type variable in ${F}_{right}$ by the corresponding type variable at the same index in ${F}_{left}$ and check the constraints from Function Type Conformance Non-Parameterized as if ${F}_{left}$ and ${F}_{right}$ were non-parameterized functions and, in addition, the upper bounds on the left side need to be supertypes of the upper bounds on the right side).

Note that the upper bounds on the left must be supertypes of the right-side upper bounds (for similar reasons why types of formal parameters on the left are required to be supertypes of the formal parameters’ types in ). Where a particular type variable is used, on co- or contra-variant position, is not relevant:

Example 63. Bounded type variable at co-variant position in function type
class A {}
class B extends A {}

class X {
<T extends B> m(): T { return null; }
}
class Y extends X {
@Override
<T extends A> m(): T { return null; }
}

Method m in Y may return an A, thus breaking the contract of m in X, but only if it is parameterized to do so, which is not allowed for clients of X, only those of Y. Therefore, the override in the above example is valid.

The subtype relation for function types is also applied for method overriding to ensure that an overriding method’s signature conforms to that of the overridden method, see [Req-IDE-72] (applies to method comnsumption and implementation accordingly, see [Req-IDE-73] and [Req-IDE-74]). Note that this is very different from Java which is far more restrictive when checking overriding methods. As Java also supports method overloading: given two types $A,B$ with $B<:A$ and a super class method void m(B param), it is valid to override m as void m(A param) in N4JS but not in Java. In Java this would be handled as method overloading and therefore an @Override annotation on m would produce an error.

The upper bound of a function type $F$ is a function type with the lower bound types of the parameters and the upper bound of the return type:
$upper\left(\text{function}\left({P}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{P}_{n}\right):R\right):=\text{function}\left(lower\left({P}_{1}\right),.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},lower\left({P}_{n}\right)\right):upper\left(R\right)$

The lower bound of a function type $F$ is a function type with the upper bound types of the parameters and the lower bound of the return type:
$lower\left(\text{function}\left({P}_{1},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{P}_{n}\right):R\right):=\text{function}\left(upper\left({P}_{1}\right),.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},upper\left({P}_{n}\right)\right):lower\left(R\right)$

#### 6.1.3. Autoboxing of Function Type

Function types, compared to other types like String, come only in on flavour: the Function object representation. There is no primitive function type. Nevertheless, for function type expressions and function declarations, it is possible to call the properties of Function object directly. This is similar to autoboxing for strings.

Access of Function properties on functions
// function declaration
var param: number = function(a,b){}.length // 2

function a(x: number) : number { return x*x; }
// function reference
a.length; // 1

// function variable
var f = function(m,l,b){/*...*/};
f.length; // 3

class A {
s: string;
sayS(): string{ return this.s; }
}

var objA: A = new A();
objA.s = "A";

var objB = {s:"B"}

// function variable
var m = objA.sayS; // method as function, detached from objA
var mA: {function(any)} = m.bind(objA); // bind to objA
var mB: {function(any)} = m.bind(objB); // bind to objB

m()  // returns: undefined
mA() // returns: A
mB() // returns: B

m.call(objA,1,2,3);  // returns: A
m.apply(objB,[1,2,3]); // returns: B
m.toString(); // returns: function sayS(){ return this.s; }

#### 6.1.4. Arguments Object

A special arguments object is defined within the body of a function. It is accessible through the implicitly-defined local variable named , unless it is shadowed by a local variable, a formal parameter or a function named arguments or in the rare case that the function itself is called ’arguments’ [ECMA11a(p.S10.5, p.p.59)]. The argument object has array-like behavior even though it is not of type array:

• All actual passed-in parameters of the current execution context can be retrieved by $0-based$ index access.

• The length property of the arguments object stores the actual number of passed-in arguments which may differ from the number of formally defined number of parameters $fpars$ of the containing function.

• It is possible to store custom values in the arguments object, even outside the original index boundaries.

• All obtained values from the arguments object are of type any.

In non-strict ES mode the callee property holds a reference to the function executed [ECMA11a(p.S10.6, p.p.61)].

Req. IDE-81: Arguments.callee (ver. 1)

In N4JS and in ES strict mode the use of arguments.callee is prohibited.

Req. IDE-82: Arguments as formal parameter name (ver. 1)

In N4JS, the formal parameters of the function cannot be named arguments. This applies to all variable execution environments like field accessors (getter/setter, Field Accessors (Getter/Setter)), methods (Methods) and constructors (Constructor and Classifier Type), where FormalParameter type is used.

// regular function
function a1(s1: string, n2: number) {
var l: number = arguments.length;
var s: string = arguments[0] as string;
}

class A {
// property access
get s(): string { return ""+arguments.length; } // 0
set s(n: number) { console.log( arguments.length ); }  // 1
// method
m(arg: string) {
var l: number = arguments.length;
var s: string = arguments[0]  as string;
}
}

// property access in object literals
var x = {
a:5,
get b(): string {
return ""+arguments.length
}
}

// invalid:
function z(){
arguments.length // illegal, see next lines
// define arguments to be a plain variable of type number:
var arguments: number = 4;
}

### 6.2. ECMAScript 5 Function Definition

#### 6.2.1. Function Declaration

##### 6.2.1.1. Syntax

A function can be defined as described in [ECMA11a(p.S13, p.p.98)] and additional annotations can be specified. Since N4JS is based on [ECMA15a], the syntax contains constructs not available in [ECMA11a]. The newer constructs defined only in [ECMA15a] and proposals already implemented in N4JS are described in ECMAScript 2015 Function Definition and ECMAScript Proposals Function Definition.

 In contrast to plain JavaScript, function declarations can be used in blocks in N4JS. This is only true, however, for N4JS files, not for plain JS files.
Syntax Function Declaration and Expression
FunctionDeclaration <Yield>:
=> ({FunctionDeclaration}
annotations+=Annotation*
(declaredModifiers+=N4Modifier)*
-> FunctionImpl <Yield,Yield,Expression=false>
) => Semi?
;

fragment AsyncNoTrailingLineBreak *: (declaredAsync?='async' NoLineTerminator)?;

fragment FunctionImpl<Yield, YieldIfGenerator, Expression>*:
'function'
(
)
;

TypeVariables?
name=BindingIdentifier<Yield>?
StrictFormalParameters<Yield=Generator>
(-> ':' returnTypeRef=TypeRef)?
;

fragment FunctionBody <Yield, Expression>*:
<Expression> body=Block<Yield>
|   <!Expression> body=Block<Yield>?
;

Properties of the function declaration and expression are described in Function Type.

For this specification, we introduce a supertype $FunctionDefinition$ for both, $FunctionDeclaration$ and $FunctionExpression$. This supertype contains all common properties of these two subtypes, that is, all properties of $FunctionExpression$.

Example 64. Function Declaration with Type Annotation
// plain JS
function f(p) { return p.length }
// N4JS
function f(p: string): number { return p.length }
##### 6.2.1.2. Semantics

A function defined in a class’s method (or method modifier) builder is a method, see Methods for details and additional constraints. The metatype of a function definition is function type (Function Type), as a function declaration is only a different syntax for creating a Function object. Constraints for function type are described in Function Type. Another consequence is that the inferred type of a function definition $fdecl$ is simply its function type $F$.

$\frac{\left[\phantom{\rule{-0.167em}{0ex}}\left[fdecl\right]\phantom{\rule{-0.167em}{0ex}}\right]}{\left[\phantom{\rule{-0.167em}{0ex}}\left[F\right]\phantom{\rule{-0.167em}{0ex}}\right]}$

Note that the type of a function definition is different from its return type $f.decl$!

1. In plain JavaScript, function declarations must only be located on top-level, that is they must not be nested in blocks. Since this is supported by most JavaScript engines, only a warning is issued.

#### 6.2.2. Function Expression

A function expression [ECMA11a(p.S11.2.5)] is quite similar to a function declaration. Thus, most details are explained in ECMAScript 5 Function Definition.

##### 6.2.2.1. Syntax
FunctionExpression:
({FunctionExpression}
FunctionImpl<Yield=false,YieldIfGenerator=true,Expression=true>
)
;
##### 6.2.2.2. Semantics and Type Inference

In general, the inferred type of a function expression simply is the function type as described in Function Type. Often, the signature of a function expression is not explicitly specified but it can be inferred from the context. The following context information is used to infer the full signature:

• If the function expression is used on the right hand side of an assignment, the expected return type can be inferred from the left hand side.

• If the function expression is used as an argument in a call to another function, the full signature can be inferred from the corresponding type of the formal parameter declaration.

Although the signature of the function expression may be inferred from the formal parameter if the function expression is used as argument, this inference has some conceptual limitations. This is demonstrated in the next example.

Example 65. Inference Of Function Expression’s Signature

In general, {function():any} is a subtype of {function():void} (cf. Function Type). When the return type of a function expression is inferred, this relation is taken into account which may lead to unexpected results as shown in the following code snippet:

function f(cb: {function():void}) { cb() }
f(function() { return 1; });

No error is issued: The type of the function expression actually is inferred to {function():any}, because there is a return statement with an expression. It is not inferred to {function():void}, even if the formal parameter of f suggests that. Due to the previously-stated relation {function():any} <: {function():void} this is correct – the client (in this case function f) works perfectly well even if cb returns something. The contract of arguments states that the type of the argument is a subtype of the type of the formal parameter. This is what the inferencer takes into account!

### 6.3. ECMAScript 2015 Function Definition

#### 6.3.1. Formal Parameters

Parameter handling has been significantly upgraded in ECMAScript 6. It now supports parameter default values, rest parameters (variadics) and destructuring. Formal parameters can be modified to be either default or variadic. In case a formal parameter has no modifier, it is called normal. Modified parameters also become optional.

Modifiers of formal parameters such as default or rest are neither evaluated nor rewritten in the transpiler.

##### 6.3.1.1. Optional Parameters

An optional formal parameter can be omitted when calling a function/method. An omitted parameter has the value undefined. In case the omitted parameter is variadic, the value is an empty array.

Parameters can not be declared as optional explicitly. Instead, being optional is true when a parameter is declared as default or variadic. Note that any formal parameter that follows a default parameter is itself also a default thus an optional parameter.

##### 6.3.1.2. Default Parameters

A default parameter value is specified for a parameter via an equals sign (=). If a caller doesn’t provide a value for the parameter, the default value is used.

Default initializers of parameters are specified at a formal parameter of a function or method after the equal sign using an arbitrary initializer expression, such as var = "s". However, this default initializer can be omitted. When a formal parameter has a declared type, the default initializer is specified at the end, such as: var : string = "s". The initializer expression is only evaluated in case no actual argument is given for the formal parameter. Also, the initializer expression is evaluated when the actual argument value is undefined.

Formal parameters become default parameters implicitly when they are preceded by an explicit default parameter. In such cases, the default initializer is undefined.

Req. IDE-14501: Default parameters (ver. 1)

Any normal parameter which is preceded by a default parameter also becomes a default parameter. Its initializer is undefined.

When a method is overwritten, its default parameters are not part of the overwriting method. Consequently, initializers of default parameters in abstract methods are obsolete.

Variadic parameters are also called rest parameters. Marking a parameter as variadic indicates that method accepts a variable number of parameters. A variadic parameter implies that the parameter is also optional as the cardinality is defined as $\left[0..*\right]$. No further parameter can be defined after a variadic parameter. When no argument is given for a variadic parameter, an empty array is provided when using the parameter in the body of the function or method.

Req. IDE-16: Variadic and optional parameters (ver. 1)

For a parameter $p$, the following condition must hold: $p.var\to p.opt$.

A parameter can not be declared both variadic and with a default value. That is to say that one can either write $varName=$ (default) or $.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}varName$, but not $.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}varName=$.

Declaring a variadic parameter of type $T$ causes the type of the method parameter to become Array<T>. That is, declaring function(…​tags : string) causes tags to be an Array<string> and not just a scalar string value.

To make this work at runtime, the compiler will generate code that constructs the parameter from the arguments parameter explicitly passed to the function.

Req. IDE-17: Variadic at Runtime (ver. 1)

At runtime, a variadic parameter is never set to undefined. Instead, the array may be empty. This must be true even if preceding parameters are optional and no arguments are passed at runtime.

For more constraints on using the variadic modifier, see Function-Object-Type.

#### 6.3.2. Generator Functions

Generators come together with the yield expression and can play three roles: the role of an iterator (data producer), of an observer (data consumer), and a combined role which is called coroutines. When calling a generator function or method, the returned generator object of type Generator<TYield,TReturn,TNext> can be controlled by its methods (cf. [ECMA15a(p.S14.4)], also see [Kuizinas14a]).

##### 6.3.2.1. Syntax

Generator functions and methods differ from ordinary functions and methods only in the additional * symbol before the function or method name. The following syntax rules are extracted from the real syntax rules. They only display parts relevant to declaring a function or method as a generator.

GeneratorFunctionDeclaration <Yield>:
(declaredModifiers+=N4Modifier)*
'function' generator?='*'
FunctionBody<Yield=true,Expression=false>
;

GeneratorFunctionExpression:
'function' generator?='*'
FunctionBody<Yield=true,Expression=true>
;

GeneratorMethodDeclaration:
annotations+=Annotation+ (declaredModifiers+=N4Modifier)* TypeVariables?
generator?='*' NoLineTerminator LiteralOrComputedPropertyName<Yield>
MethodParamsReturnAndBody<Generator=true>
##### 6.3.2.2. Semantics

The basic idea is to make code dealing with Generators easier to write and more readable without changing their functionality. Take this example:

Example 66. Two simple generator functions
// explicit form of the return type
function * countTo(iMax:int) : Generator<int,string,undefined> {
for (int i=0; i<=iMax; i++)
yield i;
return "finished";
}
val genObj1 = countTo(3);
val values1 = [...genObj1]; // is [0,1,2,3]
val lastObj1 = genObj1.next(); // is {value="finished",done=true}

// shorthand form of the return type
function * countFrom(start:int) : int {
for (int i=start; i>=0; i--)
yield i;
return finished;
}
val genObj2 = countFrom(3);
val values2 = [...genObj2]; // is [3,2,1,0]
val lastObj2 = genObj2.next(); // is {value="finished",done=true}

In the example above, two generator functions are declared. The first declares its return type explicitly whereas the second uses a shorthand form.

Generator functions and methods return objects of the type Generator<TYield,TReturn,TNext> which is a subtype of the Iterable<TYield> and Iterator<TYield> interfaces. Moreover, it provides the methods throw(exception:any) and return(value:TNext?) for advanced control of the generator object. The complete interface of the generator class is given below.

The generator class
public providedByRuntime interface Generator<out TYield, out TReturn, in TNext>
extends Iterable<TYield>, Iterator<TYield> {
public abstract next(value: TNext?): IteratorEntry<TYield>
public abstract [Symbol.iterator](): Generator<TYield, TReturn, TNext>
public abstract throw(exception: any): IteratorEntry<TYield>;
public abstract return(value: TNext?): IteratorEntry<TReturn>;
}

Req. IDE-14370: Modifier * (ver. 1)

1. * may be used on declared functions and methods, and for function expressions.

2. A function or method f with a declared return type R that is declared * has an actual return type of Generator<TYield,TReturn,TNext>.

3. A generator function or method can have no declared return type, a shorthand form of a return type or an explicitly declared return type.

1. The explicitly declared return type is of the form Generator<TYield,TReturn,TNext> with the type variables:

1. TYield as the expected type of the yield expression argument,

2. TReturn as the expected type of the return expression, and

3. TNext as both the return type of the yield expression.

2. The shorthand form only declares the type of TYield which implicitly translates to Generator<TYield,TReturn,any> as the return type.

1. The type TReturn is inferred to either undefined or any from the body.

2. In case the declared type is void, actual return type evaluates to Generator<undefined,undefined,any>.

3. If no return type is declared, both TYield and TReturn are inferred from the body to either any or undefined. TNext is any.

4. Given a generator function or method f with an actual return type Generator<TYield,TReturn,TNext>:

1. all yield statements in f must have an expression of type TYield.

2. all return statements in f must have an expression of type TReturn.

5. Return statements in generator functions or methods are always optional.

1. yield and yield* may only be in body of generator functions or methods.

2. yield expr takes only expressions expr of type TYield in a generator function or methods with the actual type Generator<TYield,TReturn,TNext>.

3. The return type of the yield expression is TNext.

4. yield* fg() takes only iterators of type Iterator<TYield>, and generator functions or methods fg with the actual return type Generator<? extends TYield,? extends TReturn,? super TNext>.

5. The return type of the yield* expression is any, since a custom iterator could return an entry {done=true,value} and any value for the variable value.

Similar to async functions, shorthand and explicit form * function():int{}; and * function():Generator<int,TResult,any> are equal, given that the inferred TResult of the former functions equals to TResult in the latter function). In other words, the return type of generator functions or methods is wrapped when it is not explicitly defined as Generator already. Thus, whenever a nested generator type is desired, it has to be defined explicitly. Consider the example below.

Type variables with async methods.
class C<T> {
genFoo(): T{} // equals to genFoo(): Generator<T, undefined, any>;
// note that TResult depends on the body of genFoo()
}
function fn(C<int> c1, C<Generator<int,any,any>> c2) {
c1.genFoo();  // returns Generator<int, undefined, any>
c2.genFoo();  // returns Generator<Generator<int,any,any>, undefined, any>
}
##### 6.3.2.3. Generator Arrow Functions

As of now, generator arrow functions are not supported by EcmaScript 6 and also, the support is not planned. However, introducing generator arrow function in EcmaScript is still under discussion. For more information, please refer to ESDiscuss.org and StackOverflow.com.

#### 6.3.3. Arrow Function Expression

This is an ECMAScript 6 expression (see [ECMA15a(p.S14.2)]) for simplifying the definition of anonymous function expressions, a.k.a. lambdas or closures. The ECMAScript Specification calls this a function definition even though they may only appear in the context of expressions.

Along with Assignments, Arrow function expressions have the least precedence, e.g. they serve as the entry point for the expression tree.

Arrow function expressions can be considered syntactic window-dressing for old-school function expressions and therefore do not support the benefits regarding parameter annotations although parameter types may be given explicitly. The return type can be given as type hint if desired, but this is not mandatory (if left out, the return type is inferred). The notation @=> stands for an async arrow function (Asynchronous Arrow Functions).

##### 6.3.3.1. Syntax

The simplified syntax reads like this:

ArrowExpression returns ArrowFunction:
=>(
{ArrowFunction}
(
'('
( fpars+=FormalParameterNoAnnotations ( ',' fpars+=FormalParameterNoAnnotations )* )?
')'
(':' returnTypeRef=TypeRef)?
|   fpars+=FormalParameterNoType
)
'=>'
) (
(=> hasBracesAroundBody?='{' body=BlockMinusBraces '}') | body=ExpressionDisguisedAsBlock
)
;

FormalParameterNoAnnotations returns FormalParameter:
;
FormalParameterNoType returns FormalParameter: name=JSIdentifier;

BlockMinusBraces returns Block: {Block} statements+=Statement*;

ExpressionDisguisedAsBlock returns Block:
{Block} statements+=AssignmentExpressionStatement
;

AssignmentExpressionStatement returns ExpressionStatement: expression=AssignmentExpression;
##### 6.3.3.2. Semantics and Type Inference

Generally speaking, the semantics are very similar to the function expressions but the devil’s in the details:

• arguments: Unlike normal function expressions, an arrow function does not introduce an implicit arguments variable (Arguments Object), therefore any occurrence of it in the arrow function’s body has always the same binding as an occurrence of arguments in the lexical context enclosing the arrow function.

• this: An arrow function does not introduce a binding of its own for the this keyword. That explains why uses in the body of arrow function have the same meaning as occurrences in the enclosing lexical scope. As a consequence, an arrow function at the top level has both usages of arguments and this flagged as error (the outer lexical context doesn’t provide definitionsfor them).

• super: As with function expressions in general, whether of the arrow variety or not, the usage of super isn’t allowed in the body of arrow functions.

In N4JS, a top-level arrow function can’t refer to this as there’s no outer lexical context that provides a binding for it.

In N4JS, a top-level arrow function can’t include usages of arguments in its body, again because of the missing binding for it.

### 6.4. ECMAScript Proposals Function Definition

#### 6.4.1. Asynchronous Functions

To improve language-level support for asynchronous code, there exists an ECMAScript proposal [45] based on Promises which are provided by ES6 as built-in types. N4JS implements this proposal. This concept is supported for declared functions and methods (Asynchronous Methods) as well as for function expressions and arrow functions (Asynchronous Arrow Functions).

##### 6.4.1.1. Syntax

The following syntax rules are extracted from the real syntax rules. They only display parts relevant to declaring a function or method as asynchronous.

AsyncFunctionDeclaration <Yield>:
(declaredModifiers+=N4Modifier)*
declaredAsync?='async' NoLineTerminator 'function'
FunctionBody<Yield=false,Expression=false>
;

AsyncFunctionExpression:
declaredAsync?='async' NoLineTerminator 'function'
FunctionBody<Yield=false,Expression=true>
;

AsyncArrowExpression <In, Yield>:
declaredAsync?='async' NoLineTerminator '('
(fpars+=FormalParameter<Yield>
(',' fpars+=FormalParameter<Yield>)*)?
')' (':' returnTypeRef=TypeRef)? '=>'
(   '{' body=BlockMinusBraces<Yield> '}'
| body=ExpressionDisguisedAsBlock<In>
)
;

AsyncMethodDeclaration:
annotations+=Annotation+ (declaredModifiers+=N4Modifier)* TypeVariables?
declaredAsync?='async' NoLineTerminator LiteralOrComputedPropertyName<Yield>
MethodParamsReturnAndBody

’async’ is not a reserved word in ECMAScript and it can therefore be used either as an identifier or as a keyword, depending on the context. When used as a modifier to declare a function as asynchronous, then there must be no line terminator after the async modifier. This enables the parser to distinguish between using async as an identifier reference and a keyword, as shown in the next example.

Example 67. Async as keyword and identifier
async (1)
function foo() {}
// vs
async function bar(); (2)
 1 In this snippet, the async on line 1 is an identifier reference (referencing a variable or parameter) and the function defined on line 2 is a non-asynchronous function. The automatic semicolon insertion adds a semicolon after the reference on line 1. 2 In contrast, async on line 4 is recognized as a modifier declaring the function as asynchronous.
##### 6.4.1.2. Semantics

The basic idea is to make code dealing with Promises easier to write and more readable without changing the functionality of Promises. Take this example:

A simple asynchronous function using async/await.
// some asynchronous legacy API using promises
interface DB {}
interface DBAccess {
getDataBase(): Promise<DB,?>
}

var access: DBAccess;

// our own function using async/await
try {
var db: DB = await access.getDataBase();
var entry: string = await access.loadEntry(db, id);
}
catch(err) {
// either getDataBase() or loadEntry() failed
throw err;
}
}

The modifier async changes the return type of loadAddress() from string (the declared return type) to Promise<string,?> (the actual return type). For code inside the function, the return type is still string: the value in the return statement of the last line will be wrapped in a Promise. For client code outside the function and in case of recursive invocations, the return type is Promise<string,?>. To raise an error, simply throw an exception, its value will become the error value of the returned Promise.

If the expression after an await evaluates to a Promise, execution of the enclosing asynchronous function will be suspended until either a success value is available (which will then make the entire await-expression evaluate to this success value and continue execution) or until the Promise is rejected (which will then cause an exception to be thrown at the location of the await-expression). If, on the other hand, the expression after an await evaluates to a non-promise, the value will be simply passed through. In addition, a warning is shown to indicate the unnecessary await expression.

Note how method loadAddress() above can be implemented without any explicit references to the built-in type Promise. In the above example we handle the errors of the nested asynchronous calls to getDataBase() and loadEntry() for demonstration purposes only; if we are not interested in the errors we could simply remove the try/catch block and any errors would be forwarded to the caller of loadAddress().

Invoking an async function commonly adopts one of two forms:

• var p: Promise<successType,?> = asyncFn()

• await asyncFn()

These patterns are so common that a warning is available whenever both

1. Promise is omitted as expected type; and

2. await is also omitted.

The warning aims at hinting about forgetting to wait for the result, while remaining non-noisy.

1. async may be used on declared functions and methods as well as for function expressions and arrow functions.

2. A function or method that is declared async can have no declared return type, a shorthand form of a return type or an explicitly declared return type.

1. The explicitly declared return type is of the form Promise<R,E> where R is the type of all return statements in the body, and E is the type of exceptions that are thrown in the body.

2. The shorthand form only declares the type of R which implicitly translates to Promise<R,?> as the actual return type.

3. In case no return type is declared, the type R of Promise<R,?> is inferred from the body.

3. A function or method f with a declared return type R that is declared async has an actual return type of

1. R if R is a subtype of Promise<?,?>,

2. Promise<undefined,?> if R is type void.

3. Promise<R,?> in all other cases (i.e. the declared return type R is being wrapped in a Promise).

4. Return type inference is only performed when no return type is declared.

1. The return type R of Promise<R,?> is inferred either as void or as any.

5. Given a function or method f that is declared async with a declared return type R, or with a declared return type Promise<R,?>, all return statements in f must have an expression of type R (and not of type Promise<R,?>).

6. await can be used in expressions directly enclosed in an async function, and behaves like a unary operator with the same precedence as yield in ES6.

7. Given an expression expr of type T, the type of (await expr) is inferred to T if T is not a Promise, or it is inferred to S if T is a Promise with a success value of type S, i.e. T <: Promise<S,?> .

In other words, the return type R of async functions and methods will always be wrapped to Promise<R,?> unless R is a Promise already. As a consequence, nested Promises as a return type of a async function or method have to be stated explicitly like Promise<Promise<R,?>,?>.

When a type variable T is used to define the the return type of an async function or method, it will always be wrapped. Consider the example below.

Example 68. Type variables with async methods.
interface I<T> {
async foo(): T;  // amounts to foo(): Promise<T,?>
}
function snafu(i1: I<int>, i2: I<Promise<int,?>>) {
i1.foo();  // returns Promise<int,?>
i2.foo();  // returns Promise<Promise<int,?>,?>
}
##### 6.4.1.3. Asynchronous Arrow Functions

An await expression is allowed in the body of an async arrow function but not in the body of a non-async arrow function. The semantics here are intentional and are in line with similar constraint for function expressions.

### 6.5. N4JS Extended Function Definition

#### 6.5.1. Generic Functions

A generic function is a function with a list of generic type parameters. These type parameters can be used in the function signature to declare the types of formal parameters and the return type. In addition, the type parameters can be used in the function body, for example when declaring the type of a local variable.

In the following listing, a generic function foo is defined that has two type parameters S and T. Thereby S is used as to declare the parameter type Array<S> and T is used as the return type and to construct the returned value in the function body.

Generic Function Definition
function <S,T> foo(s: Array<S>): T { return new T(s); }

If a generic type parameter is not used as a formal parameter type or the return type, a warning is generated.

#### 6.5.2. Promisifiable Functions

In many existing libraries, which have been developed in pre-ES6-promise-API times, callback methods are used for asynchronous behavior. An asynchronous function follows the following conventions:

'function' name '(' arbitraryParameters ',' callbackFunction ')'

Usually the function returns nothing (void). The callback function usually takes two arguments,in which the first is an error object and the other is the result value of the asynchronous operation. The callback function is called from the asynchronous function, leading to nested function calls (aka ’callback hell’).

In order to simplify usage of this pattern, it is possible to mark such a function or method as @Promisifiable. It is then possible to ’promisify’ an invocation of this function or method, which means no callback function argument has to be provided and a will be returned. The function or method can then be used as if it were declared with async. This is particularly useful in N4JS definition files (.n4jsd) to allow using an existing callback-based API from N4JS code with the more convenient await.

Example 69. Promisifiable

Given a function with an N4JS signature

f(x: int, cb: {function(Error, string)}): void

This method can be annotated with Promisifiable as follows:

@Promisifiable f(x: int, cb: {function(Error, string)}): void

With this annotation, the function can be invoked in four different ways:

f(42, function(err, result1) { /* ... */ });            // traditional
var promise: Promise<string,Error> = @Promisify f(42);  // promise
var result3: string = await @Promisify f(42);           // long
var result4: string = await f(42);                      // short

The first line is only provided for completeness and shows that a promisifiable function can still be used in the ordinary way by providing a callback - no special handling will occur in this case. The second line shows how f can be promisified using the @Promisify annotation - no callback needs to be provided and instead, a Promise will be returned. We can either use this promise directly or immediately await on it, as shown in line 3. The syntax shown in line 4 is merely shorthand for await @Promisify, i.e. the annotation is optional after await.

Req. IDE-87: Promisifiable (ver. 1)

A function or method $f$ can be annotated with @Promisifiable if and only if the following constraints hold:

1. Last parameter of $f$ is a function (the $callback$).

2. The $callback$ has a signature of

• {function(E, T0, T1, …​, Tn): V}, or

• {function(T0, T1, …​, Tn): V}

in which $E$ is type Error or a subtype thereof, ${T}_{0},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{T}_{n}$ are arbitrary types except or its subtypes. $E$, if given, is then the type of the error value, and ${T}_{0},.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}},{T}_{n}$ are the types of the success values of the asynchronous operation.
Since the return value of the synchronous function call is not available when using @Promisify, $V$ is recommended to be void, but it can be any type.

3. The callback parameter may be optional.[46]

According to [Req-IDE-87], a promisifiable function or method may or may not have a non-void return type, and that only the first parameter of the callback is allowed to be of type Error, all other parameters must be of other types.

A promisifiable function $f$ with one of the two valid signatures given in [Req-IDE-87] can be promisified with Promisify or used with await, if and only if the following constraints hold:

1. Function $f$ must be annotated with @Promisifiable.

2. Using @Promisify f() without await returns a promise of type Promise<S,F> where

• $S$ is IterableN<T0,…​,Tn> if $n\ge 2$, T if $n=1$, and undefined if $n=0$.

• $F$ is E if given, undefined otherwise.

3. Using await @Promisify f() returns a value of type IterableN<T0,…​,Tn> if $n\ge 2$, of type T if $n=1$, and of type undefined if $n=0$.

4. In case of using an await, the annotation can be omitted.
I.e., await @Promisify f() is equivalent to await f().

5. Only call expressions using f as target can be promisified, in other words this is illegal:

var pf = @Promisify f; // illegal code!

## 7. Conversions and Reflection

### 7.1. Autoboxing and Coercing

Coercing is the ability to implicitly cast one (primitive) type to another. Autoboxing is a special kind of coercing in that is the ability to automatically convert a primitive value type, such as string, number, or boolean, to its corresponding Object type version String, Number, Boolean. The capital letters in the latter are an essential distinction.

Conversion between primitives and object-representations of a datatype are not automatic in N4JS. Only in the cases of object-method invocations on a primitive type (for string to call "abc".length, for example) automatic conversion is applied.

Note that N4JS specific primitive types pathselector and i18nkey are handled similarly to string.

#### 7.1.1. Coercing

In [ECMA11a], coercing is defined by means of the abstract specification method ToPrimitive [ECMA11a(p.S9.1)], also see [ECMA11a(p.S9.10)]). Other conversions, such as ToNumber, are not directly supported but reflected in the typing rules of expressions.

We express absence of automatic coercion here by means of subtype relations:

$\begin{array}{c}\frac{}{\Gamma ⊢\text{Boolean}\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}\text{boolean}}\phantom{\rule{3.0mm}{0ex}}\frac{}{\Gamma ⊢\text{boolean}\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}\text{Boolean}}\\ \frac{}{\Gamma ⊢\text{Number}\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}\text{number}}\phantom{\rule{3.0mm}{0ex}}\frac{}{\Gamma ⊢\text{number}\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}\text{Number}}\\ \frac{}{\Gamma ⊢\text{String}\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}\text{string}}\phantom{\rule{3.0mm}{0ex}}\frac{}{\Gamma ⊢\text{string}\phantom{\rule{1.0mm}{0ex}}\nless \text{:}\phantom{\rule{1.0mm}{0ex}}\text{String}}\end{array}$

and for the N4JS specific types:

$\frac{}{\Gamma ⊢\text{pathSelector}<\text{T}>\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\text{string}}$
$\frac{}{\Gamma ⊢\text{i18nKey}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\text{string}}$

If a conversion between primitive and object type is desired, we require the user of N4JS to actively convert the values. The reason for that is the notably different behavior of object- and primitive-variants of a type in expression evaluation:

var bool: boolean = false;
var Bool: Boolean = new Boolean( false );

console.log( bool ? "true" : "false"); // prints "false"
console.log( Bool ? "true" : "false"); // prints "true"!

Conversion between a primitive type to its object-variant is achieved by the new operator. The valueOf() method converts the object-variant back to a primitive value.

// objects from literals:
var bo: Boolean = new Boolean( true ); // typeof bo: object
var no: Number = new Number( 42 ); // typeof no: object
var so: String = new String( "foo" ); // typeof so: object

// to primitive
var b: boolean = bo.valueOf(); // typeof b: boolean -- true
var n: number = no.valueOf(); // typeof n: number -- 42
var s: string = so.valueOf(); // typeof s: string -- "foo"

// to object-type
bo = new Boolean( b );
no = new Number( n );
so = new String( s );

Conversion of variables of type Object or from one primitive type to another is expressed in terms of typing rules for expressions. That is, it is not possible to convert any Object to a primitive in general, but it is possible to do so in the context of certain expressions such as additive operator. The applied conversions are described in Auto-Conversion of Class Instances

#### 7.1.2. Autoboxing of Primitives

In [ECMA11a], autoboxing is defined by ToObject [ECMA11a(p.S9.9)].

Autoboxing is not directly supported in N4JS. Instead, primitive types virtually have the same members as their corresponding object types. It is then possible to use the Autoboxing feature when calling a member. In general, Autoboxing is only supported for accessing built-in read-only (immutable) properties. For example, "some string value".split(" "); is supported but "some string value".foo=1; will be rejected as String does not allow properties to be added (cf. String vs. String+, see Dynamic).

Autoboxing often leads to problems, in particular in combination with dynamic types – this is why it is not directly supported in N4JS.

var s: String+ = "Hello"; (1)

s.prop = 1;
console.log(s.prop); (2)
 1 will produce an error to prevent the following scenario: 2 prints "undefined"

#### 7.1.3. Autoboxing of Function Expressions and Declarations

Function expressions and declarations always define an object of type Function, thus coercing or Autoboxing is not required in case of functions:

It is always possible to use a function expression where a Function is required, and to use an object of type Function where a function expression is expected. This is only possible if the function signatures are subtype-compatible, see Function Type for details.

Still, it is always possible to call members of Function, e.g., function(){}.length().

### 7.2. Auto-Conversion of Objects

#### 7.2.1. Auto-Conversion of Class Instances

All classes defined in N4JS modules implicitly subclass N4Object, which is a plain JavaScript Object type. The same auto-conversion rules defined for JavaScript Object therefore apply to N4Object instances as well.

The basic conversion uses the abstract JavaScript function ToPrimitive [ECMA11a(p.S9.1)], which relays on the specification method Object [ECMA11a(p.S8.12.8)]. DefaultValue calls valueOf or toString methods if they are defined by the class (in the methods-builder).

Note that according to the [ECMA11a], in most cases, objects are first converted into primitives. That is, in most cases, no extra hint is passed to DefaultValue. Thus valueOf usually takes precedence over toString as demonstrated in the following example:

Example 70. Auto-Conversion

Assume some classes and corresponding instances defined as follows:

class A {}
class B{
@Override public toString(): string { return "MyB"}
}
class C{
@Override public valueOf(): any { return 10}
}
class D{
@Override public toString(): string { return "MyD"}
@Override public valueOf(): any { return 20}
}
var a = new A(), b = new B(), c = new C(), d = new D();

Instances of these classes will be converted as demonstrated as follows:

console.log(a+"");                      // [object Object]
console.log(a+1);                       // [object Object]1

console.log(""+b+"");                   // MyB
console.log(1+b+1);                     // 1MyB1

console.log(c+"");                      // 10
console.log(c+1);                       // 11

console.log(d+"");                      // 20
console.log(d+1);                       // 21
##### 7.2.1.1. Auto-Conversion of Interface Instances

Instances of interfaces actually are instances of classes at runtime. The auto-conversion rules described in Auto-Conversion of Class Instances are applied to instances declared as instances of interfaces as well.

#### 7.2.2. Auto-Conversion of Enum Literals

Enumeration values are objects and thus follow the behavior for ECMAScript Object and Function. They have a custom $toString$ method which returns the name of the enumeration value.

### 7.3. Type Cast and Type Check

#### 7.3.1. Type Cast

(IDEBUG-56): Casting to TypeVars

Type casts are expressed with the cast expression (as), see Cast (As) Expression for details.

We first define helper rules for the type cast constraints as follows:

Req. IDE-89: Cast Validation At Compile Time (ver. 1)

Given a type cast expression e in which $\Gamma ⊢e.expr:S$ and and target type T, the following constraints must hold:

1. T must be a classifier, enum, primitive, function type expression, classifier type, type variable, union or intersection type:

$\mu \left(T\right)\in \phantom{\rule{3.0mm}{0ex}}\left\{\text{any},\text{Class},\text{Interface},\text{Enum},\text{Primitive},\text{ObjectType},$
$\phantom{\rule{3.0mm}{0ex}}\text{FunctionTypeExpression},\text{ClassifierType},\text{TypeVariable},\text{Union},\text{Intersection}\right\}$

2. if S is a subtype of T, the cast is unnecessary and a warning will be generated.

3. if S and T are classes, enums or primitive types, then T must be a subtype of S. This is also true if T is an interface and the type of S cannot have subtypes, or vice versa.

$\left(isCPOE\left(T\right)$
$\phantom{\rule{2.0em}{0ex}}\wedge \left(isCPOE\left(S\right)$
$\phantom{\rule{4.0em}{0ex}}\vee \left(\mu \left(S\right)=\text{Intersection}\wedge \exists {S}^{\text{'}}\in S:isCPOE\left({S}^{\text{'}}\right)\right)\right)$
$\vee \left(isInterface\left(T\right)\wedge isFinalByType\left(S\right)\right)$
$\vee \left(isFinalByType\left(T\right)\wedge isInterface\left(S\right)\right)\right)\to \Gamma ⊢T<:S$

4. if S is a class, enum or primitive type and T is a type-variable, then for each given boundary ${T}_{i}^{up}$ of T of type class, enum or primitive S must be a member of the type hierarchy: [47]

$\left(isBoundTypeVar\left(T\right)\wedge isCPOE\left(S\right)\right)$
$\to {\forall }_{{T}_{i}^{up}\in T.upperBounds}\left(isCPOE\left({T}_{i}^{up}\right)\to \Gamma ⊢\left({T}_{i}^{up}<:S\vee {T}_{i}^{up}:>S\right)\right)$

5. if S is a union or intersection type, then the type cast is valid if it is valid for at least one element of S.

6. if S and T are generics, and if ${S}^{0}={T}^{0}$, a cast is possible if type arguments are sub- or supertypes of each other: [48]

$\mu \left(S\right)=\text{Classifier}\wedge \mu \left(T\right)=\text{Classifier}\wedge {S}^{0}={T}^{0}\to$

7. If T is a union type, then the type cast is valid if it is valid for at least one element of T.

8. If T is an intersection type, then the type cast is valid if it is valid for all elements of T.

 any is a supertype of all other types, thus it is always possible to cast a variable of type any to other (non-composed) types.

#### 7.3.2. Type Check

There are basically two ways of testing the type of a variable: typeof and instanceof. N4JS supports type comparison via the ECMAScript instanceof operator. The operator instanceof retains its standard ECMAScript behavior (e.g. checking whether a value is an instance of a constructor function), but has additional functionality when used with N4JS types.

When used with an N4JS class, instanceof also supports checking against an interface. For N4JS enumeration values, it can be used to check whether the value is part of a specific enumeration.

typeof only returns a string with the name of the ECMAScript type, which is Object for all class instances.

N4JS specific string types, that is pathSelector and i18nkey cannot be tested during runtime. These types, therefore, must not be used in instanceof expressions. The same is true for string-based enums and arrays which cannot be tested during runtime, thus string-based enum and array types are not permitted on the right-hand side of instancesof constructs. For all types for which the evaluation result of instanceof could be computed at compile time, the check is unnecessary and thus it is refused by the compiler. Using structural types on the right-hand side of instancesof constructs is also not permitted.

In order to avoid errors at runtime, the instanceof operator defines appropriate constraints, see Relational Expression for details.

Example 71. Type Check Example

Given the following classes and variable:

interface I{}
class S{}
class Sub extends S implements I{}

var x = new Sub();

typeof x will simply return object. The following table shows the difference between plain JavaScript instanceof and N4JS’s instanceof:

Check JavaScript N4JS

x instanceof Sub

true

true

x instanceof S

true

true

x instanceof I

false

true

### 7.4. Reflection meta-information

All N4JS classes, interfaces and enumerations provide meta-information that is used by the runtime and standard library. All classifiers (including enums) provide meta-information by means of a static getter n4type. Since it is static getter, it is actually an instance getter of the constructor (or classifier) of a type, which is the only way to retrieve that information in case of interfaces. For enums, this can be retrieved from instances as well.

This getter is of type N4Class which is a built-in type just like N4Object. It contains the following members:

fqn

The $FQN$ of the type.

n4superType

The N4Class of the supertype, may be null if supertype is a not an N4Class.

allImplementedInterfaces

List of The $FQN$ of implemented interfaces (transitively but without interfaces implemented by supertype)

get isClass

True if the type is an N4Class.

get isInterface

True if the type is an N4Interface.

#### 7.4.1. Reflection for Classes

The meta-information for classes is available by means of N4Object’s static getter n4type. Since it is static getter, it is actually an instance getter of the constructor of a type.

In addition, the static method of in N4Type is available to retrieve the meta-information for a given instance or constructor. This also allows to retrieve meta-information directly for an instance of some class C without having the constructor of C available, for example because the constructor is not accessible.

Example 72. Reflection with N4class

This example demonstrates how these reflective features are accessed:

class A {}
class B extends A {}
var b = new B();
console.log(B.n4type.fqn);
console.log(b.constructor.n4type.fqn);
console.log(b.constructor.n4type.n4superType.fqn);
console.log(N4Type.of(b));
console.log(N4Type.of(B.n4type).fqn);

Assuming this code is defined in file A, this will output

A.B
A.B
A.A
A.B
N4BuiltInClasses.N4Class

The built-in types N4Object and N4Class are also accessible. They are not defined in a module, thus their FQN returns only their simple name.

Example 73. Reflection with Built-In Types
console.log('N4Object.n4class.fqn:      ' + N4Object.n4class.fqn)
console.log('N4Class.n4class.fqn:       ' + N4Class.n4class.fqn)

class A {}
console.log('A.n4class.fqn:             ' + A.n4class.fqn)
console.log('A.n4class.n4superType.fqn: ' + A.n4class.n4superType.fqn)

Assuming this code is defined in file A, this will output

N4Object.n4class.fqn:      N4Object
N4Class.n4class.fqn:       N4Class
A.n4class.fqn:             A.A
A.n4class.n4superType.fqn: N4Object

Note that classes extending Object do not provide the static n4class getter, hat is

class B extends Object {}
console.log('B.n4class.fqn:             ' + B.n4class.fqn)

would issue an error as cannot be resolved.

Example 74. N4Class.of

The type has a method to retrieve the meta-information from instances (i.e. or enumeration literals using ) without using the constructor.

class C { }
interface I {}  class IImpl implements I {}
enum E { L }

var c: C = new C();
var i: I = new IImpl();
var e: E = E.L;

console.log(C.n4type.fqn);
console.log(N4Class.of(c).fqn);

console.log(I.n4type.fqn);
console.log(N4Class.of(i).fqn);

console.log(E.n4type.fqn);
console.log(N4EnumType.of(e).fqn);

#### 7.4.2. Reflection for Interfaces

The meta-information of an interface X is available via getter n4class defined in the type{X}. This field is of type N4Class as well. Since an interface cannot have a super classs, the property n4superTypes will always be empty. Calling isInterface respectively on the returned N4Class instance will return true.

#### 7.4.3. Reflection for Enumerations

var n: number; var b: boolean; var s: string;

The meta-information for enumerations is available by means of the getter n4class, either statically by using the enumeration type or (in terms of an instance getter) via a literal. Calling isEnum on the returned N4Class instance will return true.

### 7.5. Conversion of primitive types

Conversion between primitives is given as follows:

var n: number; var b: boolean; var s: string;
From To Conversion Example

string

number

Number…​

n = Number("42");//42

string

boolean

N4Primitives.parseBoolean(…​)

 b=N4Primitives.parseBoolean("false");

number

boolean

Boolean(…​)

b=Boolean(17.5); //true

number

string

Number.toString()

s=42.toString(); //"42"

boolean

number

N4Primitives.toNumber(…​)

n=N4Primitives.toNumber(true);

boolean

string

Boolean.toString()

 s=true.toString();//"true" }

Remarks:

1. ECMAScript doesn’t define explicit conversion from string content. Implicit handling states all strings with $>0==true$. N4Primitives.parseBoolean(x) yields true for x.trim().toLowerCase().equals("true")

2. The call to Boolean(..) for the arguments 0, -0, null, false, NaN, undefined and "" evaluate to false. All other values evaluate to true.

3. Number has several methods for converting a value to string [ECMA11a(p.S15.7.4)]: toExponential(), to Fixed(), toPrecision().

4. ECMAScript doesn’t define explicit conversion from boolean to number. Implicit handling states true $\to$ 1 and false $\to$ 0, which N4Primitives.toNumber() yields.

## 8. Expressions

For all expressions, we define the following pseudo properties:

containingExpression

The parent expression, in which an expression is contained, may be null.

containingStatement

The statement in which the expression is (indirectly) contained.

containingFunctionOrAccessor

The function, method, getter or setter in which the expression is (indirectly) contained, may be null.

containingClass

The class in which the expression is (indirectly) contained, may be null.

probableThisTarget

The potential target of a this keyword binding, this is not necessarily the containing class or object literal. In case of instance methods of a class T, this usually is the classifier T; in case of static methods, it is the classifier type type{type}.

container

The direct owner of the expression. z

The expressions and statements are ordered, describing first the constructs available in the 5th edition of ECMA-262, referred to as [ECMA11a] in the following. It is worth noting that the grammar snippets already use newer constructs in some cases.

### 8.1. ECMAScript 5 Expressions

N4JS supports the same expressions as ECMAScript. The semantics are described in [ECMA11a(p.S11)]. In N4JS, some expressions are extended for supporting the declaration of types, annotations, or parameterized usages. These extensions and type-related aspects as well as specific N4JS constraints are described in this section.

Some operators come in different ’flavors’, that is as binary operator, unary pre- or postfix operators, or assignment operators. For these operators, type constraints are only defined for the binary operator version and the other variants are deduced to that binary version. E.g., ++ and += are deduced to + (and simple assignment).

#### 8.1.1. The this Literal

This section describes the this literal and the semantics of the @This annotation, the type this is described in This Type.

##### Semantics

Semantics are similar to the original ECMAScript this keyword, see [ECMA11a(p.11.1.1, p.p.63)]) Also see [West06a] and MozillaJSRef

Regarding the location where this may be used, the following restrictions apply:

Req. IDE-173: Valid location for this literal (ver. 1)

The literal may not be used in

1. the initializer expression of static data fields in classes.

2. the initializer expression of data fields in interfaces (applies to both static and non-static).

3. static methods of interfaces and static field accessors of interfaces.

Note: [Req-IDE-173] also applies for this literals inside arrow expressions in initializers.

The use of this is illustrated with some examples as it can often be confusing. Type inference heuristics and explanations are provided in the next section.

Example 75. This in Unrestricted Mode

In unrestricted mode, this is bound to the receiver. If there is no receiver it is bound to the global object, however, we often do not know exactly what the global object would be.

var name = "global a"; // assume the top level is similar to the global object
this.name; // <-- "global a"
function f() {
return this.name; // <-- depends on call, usually "global a"
}
var ol1 = {
name: "John",
greeting: "Hello " + this.name, // "Hello global a" -- we do not greet John!
}
var ol2 = {
name: "John",
f: function() {
this.name; // usually "John", as we assume f is called like ol2.f()
var g = function() {
return this.name; // "global a"
}
return g(); // no receiver, this in nested function g will be global scope
}
}
Example 76. This in strict mode

In strict mode, this is bound to the receiver. If there is no receiver, it is bound to undefined. Thus, we will probably get a lot of errors:

"use strict"
var name = "global a"; // assume the top level is similar to the global object
this.name; // <-- error, this is undefined, there is no receiver
function f() {
return this.name; // <-- depends on call, usually this produces an error as this is undefined
}
var ol1 = {
name: "John",
greeting: "Hello " + this.name, // will produce an error, as this is undefined
}
var ol2 = {
name: "John",
f: function() {
this.name; // usually "John", as we assume f is called like ol2.f()
var g = function() {
this.name; // an error, see call below:
}
return g(); // no receiver, this in nested function g is undefined
}
}
Example 77. This in N4JS mode

As in strict mode, this is bound to the receiver and if there is no receiver, it is bound to undefined. So the example above is also true for N4JS mode. Classes behave slightly differently:

class A {
name = "John";
greeting  = "Hello " + this.name; // works, in N4JS classes, greeting is "Hello John"

f() {
return this.name; // this usually is instance object, similar to object literals.
}

g() {
var h = function() {
return this.name; // as in object literals: no receiver, no this.
}
return h();
}
}
 In N4JS classes, this is always bound to the instance when used in field initialization.
##### Type Inference

The type is inferred from the this type is bound to. The inference, therefore, has to consider the original semantics as described in [ECMA11a(p.10.4., p.10.4.3, p.p.58)]. In ECMAScript the type of this is unfortunately determined by the function call and not by the function definition:

• By default, this is bound to the global object [ECMA11a(p.10.4.1.1)]. Unfortunately it is often unknown what the global object will be at run time (e.g., node.js differs from browsers).

• If a function is called without a receiver, this is bound to

• the global object or

• to undefined in strict mode.

• If a function is called with a receiver,this is bound to the receiver object.

Actually, this is bound to the newly created object if a function is called with the new operator. If a function is known to be invoked with an explicit $thisArg$ (apply() etc.), the @This annotation can be used to explicitly set the this type. This annotation has precedence over otherwise inferred bindings.

In general, the actual this target can not be inferred from the context of the this keyword. A heuristic is defined, however, to compute the probable this type:

1. If the this keyword is used in some function annotated with an annotation @This, the type specified in the annotation is used. The inferred type is always nominal.

$f=\text{"this"}.containingFunctionOrAccessor$
$\frac{f.hasAnnotation\left(\text{"@This"}\right)\phantom{\rule{3.0mm}{0ex}}T=f.annotation\text{["@This"]}}{\Gamma ⊢\text{"this"}:\nsim T}$

2. If the this keyword is used in some instance method of a classifier or in an instance field initializer,this is bound to the T itself. If the this keyword is used in some static method of a classifier T or in a static field initializer, the prototype type (or constructor) of the classifier is used, that is type[T]. In both cases, the target is determined by using the expressions’s pseudo property probableThisTarget. If the this keyword is used in a function expression assigned to an property of an object literal, the type of the object literal is used. Note that usually this is the this type in instance methods, and the this type in static methods.

$\frac{T=\text{"this"}.probableThisTarget\phantom{\rule{3.0mm}{0ex}}T\ne \text{null}}{\Gamma ⊢\text{"this"}:\nsim T}\text{}$
3. In all other cases: Non-strict mode:

$\frac{mode=\text{unrestricted}}{\Gamma ⊢\text{"this"}:\text{global}}\text{}$

Strict mode and N4JS mode:

$\frac{mode\ne \text{unrestricted}}{\Gamma ⊢\text{"this"}:\text{global}\text{undefined}}\text{}$

If the actual this type is defined as a structural type, the structural type information is moved to the this type itself. This is transparent to the user in general but maybe visible in case of error messages. That is to say that the actual this type is always a nominal type. This is indicated by the nominal modifier $\nsim$ (cf. [Req-IDE-90] constraints 1 and 2.).

1. The @This annotation is only allowed on declared functions, function expressions (including arrow functions), methods, and field accessors, i.e. getters and setters, except static members of interfaces.

2. The type declared by way of @This(..) an annotation of a method or field accessor must be a subtype of the member’s containing classifier.

Req. IDE-92: Single @This Annotation (ver. 1)

It is not allowed to use more then one @This(..) annotation on an element.

Example 78. Effect of Nominal This Type

Given the following declaration

@This(~Object with {a: string;}) f() {}

Since the this type is always nominal, ~ Object becomes Object. In case of method call, however, the returned value becomes structural again. In case of error messages the type of the return type is then

~this[Object] with {a: string;}

For the sake of simplicity, additional structural members are usually omitted in error messages, leading to

~this[Object]

this[~Object]
Example 79. This and Function Declaration

This example demonstrates the usage of functions annotated with @This. By using the argument union{A,B} it is possible to have two completely unrelated classes as the receiver type of the function logger. To pass an actual object the apply() method of the function is used.

class A {
log: string() { return "A was logged"; }
}

class B {
log: string() { return "B was logged"; }
}

@This(union{A,B})
function logger() { console.log("~ "+this.log()+" ~"); }

var a: A = new A();
logger.apply(a,[]); // prints "~ A was logged ~"
logger.apply( new B(),[]) // prints "~ B was logged ~"
Example 80. This and Function Expressions

In this example a function is created via a function expression. The function is then assigned to member field of class B. Via annotating the expression with @This(B), access to the receiver of type B is enabled.

class B {
log(): string { return "B was logged"; }     // method
logMe : {@This(B) function():void}; // reference to a function
}

var b: B = new B();
b.logMe = @This(B) function() { console.log("*>"+this.log()+"<*"); }
b.logMe(); // prints "*>B was logged<*"

Note that if a function is called as a constructor function with new, the type of this can be declared via annotation @This(..), as shown in the following snippet:

@This(
~Object with {
w: number; h: number;
area: {function():number};
})
function Box(w: number w, h: number) {
this.w = w;
this.h = h;
this.area = @This(
~Object with {
w: number; h: number;
area: {function():number};
}) function() { return this.w * this.h }
}
var bError = Box(1,2)
var bOK = new Box(1,2)

Inside the constructor function Box, this is bound to the structural type definition due to the annotation.

Inside the nested function area, this is bound to the receiver object (if the function is called like bOk.area()). Again, this depends on the way the nested function is called, which can usually not be determined at the declaration location. The nested function must then be annotated accordingly.

When calling this function, the type of this is checked against the declared this type, which would cause an error in the first case.

The use of the @This annotation is not allowed on methods.

 Using constructor functions is not recommended and an error or warning will be created. This is only useful for adapting third-party library code. Even in the latter case, it would probably make more sense to declare a (library) class Rectangle rather then defining the constructor function.

#### 8.1.2. Identifier

##### Syntax

Identifiers as expressions are identifier references. They are defined as follows:

IdentifierRef <Yield>:
id=[types::IdentifiableElement|BindingIdentifier<Yield>]
;

BindingIdentifier <Yield>:
IDENTIFIER
| <!Yield> 'yield'
| N4Keyword
;
##### Semantics

The type of an identifier $i$ is resolved depending on its binding and scope respectively (cf. [ECMA11a(p.10.2.2.1GetIdentifierReference, p.p.56)]. The following scopes (aka Lexical Environments) are defined:

• function local; local variables, parameters

• zero or more function closure in case of nested functions

• module

• global

These scope are nested as illustrated in Scopes.

Note that classes definitions and object literal do not define a scope: members of a class or properties of an object literal are to be accessed via this. Identifier references always reference declared elements, that is to say either variable, function, or class declarations. Properties of object literals or members of a class are referenced via $PropertyAccess-Expression.property$ (see Property Accessors).

Figure 7. Scopes

An identifier may be bound to a variable (global or local variable, parameter, variable defined in a function’s closure), or to a property of an object. The latter case is known as property access as further described in Property Accessors.

If an identifier $i$ is accessed, the bound declared element $D$ must be readable if it is not used on the left-hand side of an assignment expression.

$\phantom{\rule{3.0mm}{0ex}}bind\left(i,D\right)$

$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{3.0em}{0ex}}ae.left=i$
$\phantom{\rule{3.0mm}{0ex}}\phantom{\rule{4.0em}{0ex}}\vee \left(\mu \left(ae.left\right)=\text{PropertyAccessExpression}\wedge ae.left.property=i\right):$
$\phantom{\rule{3.0mm}{0ex}}⇒D.readable$

##### Type Inference

An identifier reference $i$ is bound to an identifiable element $i.id$, which is expressed with the function $bind\left(i,i.id\right)$. The type of the reference is then inferred as follows:

#### 8.1.3. Literals

##### Type Inference

The type of a literal can directly be derived from the grammar. The following axioms are defined for literals:

$\phantom{\rule{13.0em}{0ex}}\frac{}{\text{NullLiteral}:\text{null}}$
$\phantom{\rule{13.0em}{0ex}}\frac{}{\text{BooleanLiteral}:\text{boolean}}$
$\phantom{\rule{13.0em}{0ex}}\frac{}{\text{NumericLiteral}:\text{int}or\text{number}}$
$\phantom{\rule{13.0em}{0ex}}\frac{}{\text{StringLiteral}:\text{string}}$
$\phantom{\rule{13.0em}{0ex}}\frac{}{\text{RegularExpressionLiteral}:\text{RegExpr}}$

Note that there are no literals specific for pathSelector or i18nkey.

##### 8.1.3.1. Integer Literals

Numeric literals representing integers in the range of JavaScript’s int32 are inferred to the built-in primitive type int instead of number. The following rules apply:

Req. IDE-94: Numeric literals (ver. 1)

• Numeric literals with a fraction or using scientific notation, e.g. 2.0 and 2e0, respectively, are always inferred to number, even if they represent integers in the range of int32.

• Numeric literals that represent integers in the range of JavaScript’s int32, i.e. from ${-2}^{31}$ to ${2}^{31}-1$, are inferred to int.

• Hexadecimal and octal literals are always interpreted as positive numbers, so all values above 0x7fffffff and 017777777777 lie outside the range of int32 and will thus be inferred to number; this is an important difference to Java. See below for further elaboration.

There are differences to numeric literals in Java:

Java JavaScript N4JS

Literal

Value

Type

Value

Type

2147483648

-2147483648

int

-2147483648

int

2147483647

2147483647

int

2147483647

int

0x7fffffff

2147483647

int

2147483647

int

0x80000000

-2147483648

int

+2147483648

number

0xffffffff

-1

int

4294967295

number

0x100000000

n/a

4294967296

number

017777777777

2147483647

int

2147483647

int

020000000000

-2147483648

int

+2147483648

number

037777777777

-1

int

4294967295

number

040000000000

0

int

4294967296

number

0100000000000

n/a

8589934592

number

The literals 0x100000000 and 0100000000000 produce a syntax error in Java.

Until IDE-1881 is complete, all built-in operations always return a number even if all operands are of type int. For the time being, we therefore interpret -1 as a negative integer literal (inferred to int), but -(1) as the negation of a positive integer literal (inferred to number).

#### 8.1.4. Array Literal

##### Syntax
ArrayLiteral <Yield> returns ArrayLiteral:
{ArrayLiteral} '['
elements+=ArrayElement<Yield>
)?
']'
;

/**
* This array element is used to pad the remaining elements, e.g. to get the
* length and index right
*/

ArrayElement <Yield> returns ArrayElement: {ArrayElement} spread?='...'? expression=AssignmentExpression<In=true,Yield>;
##### Type Inference

In general, an array literal is inferred as Array<T> (similar to the type of new Array()). The interesting question is the binding of the type variable $T$.

The type of an array padding p is inferred as follows:

$\frac{}{\Gamma ⊢p:\text{undefined}}\text{}$

The element type of an array literal is simply inferred as the (simplified) union of the type elements of the array. Thus, the type of an array literal $a$ is inferred as follows:

$\frac{\Gamma ⊢a.\overline{elements}:\overline{{T}_{e}}T=\bigcup \overline{{T}_{e}}}{\Gamma ⊢\left(a\right):Array}$

In other languages not supporting union types, the element type is often inferred as the join (LCST) of the element types. Using a union type here preserves more information (as the actual types are still known). For many use cases the behavior is similar though, as the members of a union type are the members of the join of the elements of the union.

Note that typeof [1,2,3] does not return Array<number> (as ECMAScript is not aware of the generic array type), but Object.

Example 81. Array Type Inference

The type for all variables declared in this example is inferred to Array<string>:

var names1          = ["Walter", "Werner"];
var names2          = new Array("Wim", "Wendelin");
var names3          = new Array<string>(3); // length is 3
var names4: Array<string>;

Empty array literals are inferred to any, by default. We are not using Array<?> here because then a typical JavaScript pattern would no longer be supported:

var a = [];
a.push('hello'); (1)
 1 This would fail if a and thus [] were inferred to Array
 An important exception; if a type expectation exists for the empty array literal and the expected type is Array, this will be used as the type of the array literal.

Req. IDE-95: Empty array literal (ver. 1)

An empty array literal will be inferred as follows:

• If there is a type expectation for the empty array literal and the expected type is Array<T>, for any type T, then the type of the empty array literal will be inferred to Array<T>.

• Otherwise, the type of the empty array literal will be inferred to Array<any>.

#### 8.1.5. Object Literal

##### Syntax

Cf. [ECMA11a(p.S11.1.5, p.p.65ff)] The syntax of an object literal is given by:

ObjectLiteral <Yield>: {ObjectLiteral}
'{'
( propertyAssignments+=PropertyAssignment<Yield>
(',' propertyAssignments+=PropertyAssignment<Yield>)* ','?
)?
'}'
;

PropertyAssignment <Yield>:
PropertyNameValuePair<Yield>
| PropertyGetterDeclaration<Yield>
| PropertySetterDeclaration<Yield>
| PropertyMethodDeclaration<Yield>
| PropertyNameValuePairSingleName<Yield>
;

PropertyMethodDeclaration <Yield>:
=> ({PropertyMethodDeclaration}
annotations+=Annotation*
TypeVariables? returnTypeRef=TypeRef?
(
generator?='*'  LiteralOrComputedPropertyName<Yield> ->MethodParamsAndBody<Generator=true>
| LiteralOrComputedPropertyName<Yield> ->MethodParamsAndBody <Generator=false>
)
)
';'?
;

PropertyNameValuePair <Yield>:
=> (
{PropertyNameValuePair}
annotations+=Annotation*
declaredTypeRef=TypeRef? LiteralOrComputedPropertyName<Yield> ':'
)
expression=AssignmentExpression<In=true,Yield>
;

/*
* Support for single name syntax in ObjectLiteral (but disallowed in actual object literals by ASTStructureValidator
* except in assignment destructuring patterns)
*/
PropertyNameValuePairSingleName <Yield>:
declaredTypeRef=TypeRef?
identifierRef=IdentifierRef<Yield>
('=' expression=AssignmentExpression<In=true,Yield>)?
;

PropertyGetterDeclaration <Yield>:
=>(
{PropertyGetterDeclaration}
annotations+=Annotation*
)
body=Block<Yield=false>
;

PropertySetterDeclaration <Yield>:
=>(
{PropertySetterDeclaration}
annotations+=Annotation*
'set'
->LiteralOrComputedPropertyName <Yield>
)
'(' fpar=FormalParameter<Yield> ')' body=Block<Yield=false>
;
import Address from "my/Address";
var simple = {name: "Walter", age: 72, address: new Address()};
##### 8.1.5.1. Properties

PropertyAssignments have common properties of PropertyNameValuePair, PropertyGetterDeclaration, and PropertySetterDeclaration:

annotations

The annotations of the property assignment.

name

The name of the property. This may be an identifier, a string or a numeric literal. When comparing names, we implicitly assume the name to be converted to an identifier, even if this identifier is not a valid ECMAScript identifier.

declaredType

The declared type of the property which may be null. This property is a pseudo property for PropertySetterDeclaration, in this case it is derived from the declared type of the setter’s formal parameter.

Additionally, we introduce the following pseudo properties to simplify constraints:

isAccessor

The read-only boolean property. This is true if the property assignment is a setter or getter declaration. This is comparable to ECMAScript’s spec function IsAccessoprDescriptor. For a given property assignment p this is semantically equivalent to $\mu \left(p\right)=\text{PropertyGetterDeclaration}\vee \mu \left(p\right)=\text{PropertySetterDeclaration}$.

isData

The read-only boolean property. This is true if the property assignment is a name value pair. For a given property assignment p this is semantically equivalent to $\mu \left(p\right)=\text{PropertyNameValuePair}$. It is comparable to ECMAScript’s spec function isDataDescriptor. The equation $isAccessor=¬isData$ is always true.

##### Semantics

Req. IDE-96: Object literal (ver. 1)

For a given object literal $ol$ the following constraints must hold (cf. [ECMA11a(p.p.66)]:

• the name of each property is given as an identifier, a string literal, a numeric literal, or as a computed property name with a compile-time expression (see Compile-Time Expressions). In particular, string literals, e.g. ['myProp'], built-in symbols, e.g. [Symbol.iterator], and literals of @StringBased enums are all valid computed property names.

• Object literal may not have two PropertyNameValuePairs with the same name in strict mode (cf. 4.a [ECMA11a(p.p.66)]):

$mode=\text{strict}\to \phantom{\rule{3.0mm}{0ex}}\forall pa\in ol.propertyAssignments,pa.isData:$
$\phantom{\rule{3.0mm}{0ex}}\nexists p{a}^{\text{'}}\in ol.propertyAssignments:$
$\phantom{\rule{3.0mm}{0ex}}p{a}^{\text{'}}.isAccessor\wedge p{a}^{\text{'}}.name=pa.name$

• Object literal may not have PropertyNameValuePair and PropertyGetterDeclaration/PropertySetterDeclaration with the same name (cf. 4.b/c [ECMA11a(p.p.66)]):

$\forall \phantom{\rule{3.0mm}{0ex}}pa\in ol.propertyAssignments,pa.isData:$
$\nexists \phantom{\rule{3.0mm}{0ex}}pgsd\in ol.propertyAssignments:$
$\mu \left(pgsd\right)\ne \text{PropertyNameValuePair}\wedge pgsd.name=pa.name$

• Object literal may not have multiple PropertyGetterDeclaration or PropertySetterDeclaration with the same name (cf. 4.d [ECMA11a(p.p.66)]):

$\forall \phantom{\rule{3.0mm}{0ex}}pg\in ol.propertyAssignments,pg.isAccessor:$
$\nexists \phantom{\rule{3.0mm}{0ex}}p{g}^{\text{'}}\in ol.propertyAssignments\left\{pg\right\}:$
$\phantom{\rule{3.0mm}{0ex}}\mu \left(p{g}^{\text{'}}\right)=\mu \left(pg\right)\wedge p{g}^{\text{'}}.name=pg.name$

It is a SyntaxError if the Identifier eval or the Identifier arguments occurs as the Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code or if its FunctionBody is strict code. [ECMA11a(p.p.66)]
• If two or more property assignments have the same name (and the previous conditions hold), then the types of these assignments must conform. That is to say that the inferred (but not declared) type of all assignments must be type of probably declared types and if the types are explicitly declared, they must be equal.

• In N4JS mode, the name of a property must be a valid N4JSIdentifier:

$mode=\text{n4js}\to \phantom{\rule{3.0mm}{0ex}}\forall pa\in ol.propertyAssignments:$
$\phantom{\rule{3.0mm}{0ex}}\mu \left(pa.name\right)=\text{N4JSIdentifier}$

Let $E$ be the expected type of an object literal $O$ as defined by the context in which $O$ is used. If $E$ is not type Object and not dynamic, then the compiler creates a warning $O$ contains properties not found in $E$.

This is true in particular for object literals passed in as arguments of a spec-constructor.

var p = {
f: function() {
console.log("p´s f");
},
b: function() {
this.f();
},
o: {
nested: "Hello"
}
};
p.b();
p.o.nested;
• Other properties within an object literal property can be accessed using this. In the expression of property name value pairs, however, this is not be bound to the containing object literal, but usually to undefined or global.

• The properties of an object literal are accessible from outside.

• Nested properties of an object literal are also accessible from outside.

##### Type Inference

An object literal implicitly extends ~Object, therefore, object literal types use structural typing. For details see Structural Typing. From a type systems point of view, the two variables ol and st below have the same type.

var ol = {
s: "hello",
n: 42
}
var st: ~Object with { s: string; n: number;};

#### 8.1.6. Parenthesized Expression and Grouping Operator

The grouping operator is defined here as a parenthesized expression.

##### Syntax
ParenExpression <Yield>: '(' expression=Expression<In=true,Yield> ')';
##### Type Inference

The type of the grouping operator simply is the type of its nested expression. The type if a parenthesized expression $pe$ is inferred as follows:

$\frac{\Gamma ⊢e:T}{\Gamma ⊢\text{’(’}e\text{’)’}:T}$
Example 83. Parenthesized Expression Type Examples

In the following listing, the type of the plain expressions is equivalent to the parenthesized versions:

class A{} class B extends A{}
var f: boolean; var a: A a; var b: B;

/* simple       <->     parenthesized */
10;                     (10);
"hello";                ("hello");
true;                   (true);
a;                      (a);
10-5;                   (10-5);
f?a:b                   (f?a:b);

#### 8.1.7. Property Accessors

##### Syntax

Property accessors in N4JS are based on [ECMA11a(p.S11.2.1, p.p.67ff)]. They cannot only be used for accessing properties of an object, but also for accessing members of a class instance. In order to support parameterized calls, the syntax is extended to optionally allow type arguments.

ParameterizedPropertyAccessExpression:
target=PrimaryExpression<Yield> ParameterizedPropertyAccessExpressionTail<Yield>
;

IndexedAccessExpression:
target=PrimaryExpression<Yield> IndexedAccessExpressionTail<Yield>
;

fragment IndexedAccessExpressionTail <Yield>*:
'[' index=Expression<In=true,Yield> ']'
;

fragment ParameterizedPropertyAccessExpressionTail <Yield>*:
'.' TypeArguments? property=[types::IdentifiableElement|IdentifierName]
;

Note that in [ECMA11a], the index access is called bracket notation.

##### Direct Property Access

We define a special case of property access as follows:

A property access expression is called direct, iff

• its target is an identifier reference to a class, interface, enum, or the built-in object Symbol, and

• its property name denotes an owned member of the target classifier (not an inherited, consumed, or polyfilled member) or a literal if the target is an enum.

As a consequence, a direct property access can only refer to static members.

The first requirement of the above definition rules out property access expressions that do not directly point to their target classifier or enum, as shown in the following example:

class C {
const field = 'hello';
}
let ctor = C;
ctor.field;  // *not* a direct property access to 'field'

Direct property access is the only form of property access allowed in compile-time expressions, cf. Compile-Time Expressions.

##### 8.1.7.1. Properties

We define the following properties:

target

The receiver of the property access.

index

The index expression in case of an IndexedAccessExpression (returns $\text{null}$ otherwise).

property

The name of the property in case of non-indexed-access expressions (returns $\text{null}$ otherwise, although the index may be interpreted as property name).

We define the following pseudo properties:

isDotAccess

Read-only boolean property, returns true for non-index access expression (similar to $\mu \left(p\right)\ne \text{IndexedAccessExpression}$).

isIndexAccess

Read-only boolean property, returns true for index access expression (similar to $\mu \left(p\right)=\text{IndexedAccessExpression}$.
The equation $p.isDotAccess=¬p.isIndexAccess$ is always true.

name

Returns the name of the property. This is either the $property$ converted to a simple name or the index converted to a name (where possible) if it is an indexed-accessed expression.

##### Semantics

The parameterization is part of the property access in case of generic methods. For generic functions, a parameterized function call is introduced (cf. Function Calls). The constraints are basically similar.

Req. IDE-97: Property Access and Dot Notation (ver. 1)

1. If dot notation is used in N4JS mode, the referenced property must exist unless receiver is a dynamic type:

$\phantom{\rule{3.0mm}{0ex}}pae.isDotAccess\wedge ¬R.dyn\to \text{}\phantom{\rule{3.0mm}{0ex}}\exists m\in pae.target.type.properties:m.name=pae.name$
2. If dot notation is used and the referenced property exists, then the property must be accessible:

$\phantom{\rule{3.0mm}{0ex}}pae.isDotAccess\wedge ¬R.dyn\to \text{}\phantom{\rule{3.0mm}{0ex}}\left(\exists m\in pae.target.type.properties:m.name=pae.name\right)\to \alpha \left(pae,m\right)$
3. If dot notation is used and the referenced property exists and this property is a member with a declared @This type (only possible for methods or field accessors), then the receiver must be a subtype of the declared @This type.

Req. IDE-98: Index Access (ver. 1)

An index access expression is valid iff one of the following cases applies:

1. the receiver is of a dynamic type. In this case, the index may be any expression (need not be a compile-time expression).

2. the receiver is an immediate instance of Object, i.e. it is a subtype of Object and its super types but not of any other type including ~Object and ~~Object.

3. the receiver is of type Array, ArgumentType, string, or String (including their subtypes) and the index is an expression of type number.

4. the index expression is a compile-time expression

• and the receiver type defines a member with a name equal to the string representation of the index expression’s compile-time value

• and the receiver is not an enum.

Although index access is very limited, it is still possible to use immediate instances of Object in terms of a map (but this applies only to index access, not the dot notation):

Example 84. Object as Map
var map: Object = new Object();
map["Kant"] = "Imperative";
map["Hegel"] = "Dialectic";
map.spinoza = "Am I?";  // error: Couldn't resolve reference to IdentifiableElement 'spinoza'.

Req. IDE-99: Parameterized Property Access (ver. 1)

For a parameterized property access expression $pae$, the following constraints must hold:

1. The receiver or target must be a function or method:
$pae.target.type\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\text{Function}$

2. The number of type arguments must match the number of type parameters of the generic function or method:
$|pae.typeArgs|=|pae.target.typeVars|$

3. The type arguments of a parameterized property access expression must be subtypes of the boundaries of the parameters of the called generic method.

Also see constraints on read ([Req-IDE-93]) and write ([Req-IDE-121]) access.

##### Type Inference

We define the following type inferencing rules for property accessors:

• The type of an indexed-access expression p is inferred as follows:

$\begin{array}{c}\frac{¬p.target.dyn\vee p.index.type\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\left[number\right]\phantom{\rule{3.0mm}{0ex}}\Gamma ⊢p.target:\text{Array}<\text{T}>}{\Gamma ⊢p:T}\\ \frac{else}{\Gamma ⊢p:\text{any}}\end{array}$
• The type of a property access expression is inferred as follows:

• The type of a parameterized access expression p is inferred as follows:

$\begin{array}{c}\frac{\exists m\in p.target:m.name=p.name\phantom{\rule{3.0mm}{0ex}}\Gamma ⊢m:T}{\Gamma ⊢p:T}\\ \frac{}{\Gamma ⊢p:\text{any}}\end{array}$

#### 8.1.8. New Expression

##### Syntax
NewExpression: 'new' callee=MemberExpression<Yield> (-> TypeArguments)?
(=> withArgs?='(' Arguments<Yield>? ')' )?
import Address from "my/Address";

class C<T> {
constructor(param: T) {}
}
var c = new C<string>("hello");
##### Semantics

Req. IDE-100: New expression (ver. 1)

Let $ne$ be a new expression, with $\Gamma ⊢ne.callee:C$. The following constraints must hold:

1. The callee must be a constructor type: $C<:\text{constructor}\left\{?\right\}$ or a constructable type.

2. Let $O$ be the type argument of $C$, that is $C=constructor\left\{O\right\}$. In that case,

1. $O$ must not be an interface or enum: $\mu \left(C\right)\notin \left\{\text{Interface},\text{Enum}\right\}$

2. $O$ must not contain any wildcards.

3. $O$ must not be a type variable.

3. If $C$ is not a constructor type, it must be a constructable type, that is one of the following:

$\left\{\begin{array}{c}\text{Object, Function, String, Boolean,}\\ \text{Number, Array, Date, RegExp, Error}\end{array}\right\}$

In particular, it must not refer to a primitive type or a defined functions (i.e., subtypes of Function) cannot be used in new-expressions in N4JS.

Remarks:

to 1 The type of an abstract class A is $type\left\{A\right\}$. Or in other words: Only instantiable classes have an inferred type of $constructor\left\{.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}.\phantom{\rule{1.0mm}{0ex}}\right\}$.

to 2 Even though it is possible to use the constructor type of an abstract class – concrete subclasses with override compatible constructor signature will be subclasses of this constructor.

to 3 It is not possible to refer to union or intersection at that location. So this is not explicitly denied here since it is not possible anyway.

Example 85. Abstract classes and construction

The following examples demonstrates the usage of abstract classes and constructor types, to make the first two constraints more clearer:

/* XPECT_SETUP org.eclipse.n4js.spec.tests.N4JSSpecTest END_SETUP */

abstract class A {}
class B extends A {}

// XPECT errors --> "Cannot instantiate abstract class A." at "A"
var x = new A();
// XPECT noerrors -->
var y = new B();

function foo(ctor : constructor{A}) {
// XPECT noerrors -->
return new ctor();
}

// XPECT errors --> "type{A} is not a subtype of constructor{A}." at "A"
foo(A);
// XPECT noerrors -->
foo(B);
##### Type Inference

The type of a new expression $ne$ is inferred as follows:

$\frac{\Gamma ⊢ne.callee:\text{constructor}\text{C}}{\Gamma ⊢ne:C}$

For classes, constructors are described in Constructor and Classifier Type.

In N4JS it is not allowed to call new on a plain function. For example:

function foo() {}
var x = new foo();

will issue an error.

#### 8.1.9. Function Expression

See Functions for details.

#### 8.1.10. Function Calls

In N4JS, a function call [ECMA11a(p.S11.2.3)] is similar to a method call. Additionally to the ECMAScript’s CallExpression, a ParameterizedCallExpression is introduced to allow type arguments passed to plain functions.

##### Syntax
[[function-calls-syntax]]

Similar to [ECMA11a(p.S11.2.3, p.p.68ff)], a function call is defined as follows:

CallExpression <Yield>:
target=IdentifierRef<Yield>
ArgumentsWithParentheses<Yield>
;

ParameterizedCallExpression <Yield>:
TypeArguments
target=IdentifierRef<Yield>
ArgumentsWithParentheses<Yield>
;

fragment ArgumentsWithParentheses <Yield>*:
'(' Arguments<Yield>? ')'
;

fragment Arguments <Yield>*:
arguments+=AssignmentExpression<In=true,Yield> (',' arguments+=AssignmentExpression<In=true,Yield>)* (',' spread?='...' arguments+=AssignmentExpression<In=true,Yield>)?
;
##### Semantics

Req. IDE-101: Function Call Constraints (ver. 1)

For a given call expression $f$ bound to a method or function declaration $F$, the following constraints must hold:

• If less arguments are provided than formal parameters were declared, the missing formal parameters must have been declared optional:
$|f.args|<|F.pars|\to \forall |f.args|

• If more arguments are provided than formal parameters were declared, the last formal parameter must have been declared variadic:
$|f.args|>|F.pars|\to F.par{s}_{|F.pars|-1}.variadic$

• Types of provided arguments must be subtypes of the formal parameter types:
$\forall 0

• If more arguments are provided than formal parameters were declared, the type of the exceeding arguments must be a subtype of the last (variadic) formal parameter type:
$\forall |F.pars|

• The number of type arguments in a parameterized call expression must be equal to the number of type parameters of the generic function / method and the type arguments must be subtypes of the corresponding declared upper boundaries of the type parameters of the called generic function.

Note that (for a limited time), constraints [Req-IDE-101] and [Req-IDE-102] are not applied if the the type of $F$ is Function. See Function-Object-Type.

##### Type Inference

A call expression $expr$ is bound to a method (Methods) or function declaration (which may be part of a function definition (Function Declaration or specified via a function type Function Type) $F$ (via evaluation of MemberExpression. The type of the call is inferred from the function declaration or type $F$ as follows:

$\frac{bind\left(expr.target,F\right)\phantom{\rule{3.0mm}{0ex}}F.returnType:T}{\Gamma ⊢expr:T}$

A generic method invocation may be parameterized as well. This is rarely required as the function argument types are usually inferred from the given arguments. In some cases, for instance with pathSelectors, this is useful. In that case, the type variable defined in the generic method declaration is explicitly bound to types by using type arguments. See Property Accessors for semantics and type inference.

Example 86. Generic Method Invocation

This examples demonstrate how to explicitly define the type argument in a method call in case it cannot be inferred automatically.

class C {
static <T> foo(p: pathSelector<T>): void {..}
};
C.<my.Address>foo("street.number");

Note that in many cases, the type inferencer should be able to infer the type automatically. For example, for a method

function <T> bar(c: T, p: pathSelector<T>): void {..};

and a function call

bar(context, "some.path.selector");
[source,n4js]

the type variable T can be automatically bound to the type of variable context.

#### 8.1.11. Postfix Expression

##### Syntax
PostfixExpression returns Expression: LeftHandSideExpression
(=>({PostfixExpression.expression=current} /* no line terminator here */ op=PostfixOperator))?
;
enum PostfixOperator: inc='++' | dec='--';
##### Semantics and Type Inference

The type inference and constraints for postfix operators ++ and --, cf. [ECMA11a(p.S11.3.1, p.p.70)], [ECMA11a(p.S11.3.1, p.p.70)], are defined similarly to their prefix variants (unary expressions), see Unary Expression.

Req. IDE-103: Postfix Expression Constraints (ver. 1)

For a given postfix expression $u$ $u$ with $u.op\in \left\{++,--\right\}$ and $u.expression.type:T$, the following constraints must hold:

• In N4JS mode, the type $T$ of the expression must be a number.

• If $u.expression=PropertyAccess\phantom{\rule{0.278em}{0ex}}pa\left(p\right)\wedge pa.isDotAccess\to$ both $get$ p and $set$ p must be defined.

#### 8.1.12. Unary Expression

##### Syntax

We define the following unary operators and expression, similar to [ECMA11a(p.p.70ff)]:

UnaryExpression returns Expression:
PostfixExpression
| ({UnaryExpression} op=UnaryOperator expression=UnaryExpression);
enum UnaryOperator: delete | void | typeof | inc='++' | dec='--' | pos='+' | neg='-' | inv='$\sim$' | not='!';
##### Semantics

Req. IDE-104: Delete Operator Constraints (ver. 1)

For a given unary expression $u$ with $u.op=\text{delete}$, the following constraints must hold:

• In strict mode, $u.expression$ must be a reference to a property of an object literal, a member of a class type, or to a property of the global type (i.e., the reference must be bound, and the bound target must not be a variable).

• In N4JS mode, the referenced property or member must not be declared in the containing type and the containing type reference must be declared dynamic.

Req. IDE-105: Void Operator Constraints (ver. 1)

There are no specific constraints defined for with $u.op=\text{void}$

Req. IDE-106: Typeof Operator Constraints (ver. 1)

There are no specific constraints defined for unary expression $u$ with $u.op=\text{typeof}$.

Req. IDE-107: Increment/Decrement Constraints (ver. 1)

For a given unary expression $u$ $u$ with $u.op\in \left\{++,--\right\}$ and $u.expression.type:T$, the following constraints must hold:

• If mode is N4JS, the type $T$ of the expression must be a number

$\frac{}{\Gamma ⊢\text{UnaryExpression}⊲\text{Expression}:\text{number}}$
• If $u.expression=PropertyAccess\phantom{\rule{0.278em}{0ex}}pa\left(p\right)\wedge pa.isDotAccess$ $\to$ both $get$ p and $set$ p must be defined.

For a given unary expression $u$ $u$ with $u.op\in \left\{+,-,\sim \right\}$ and $u.expression.type:T$, the following constraints must hold:

• In N4JS mode, the type T of the expression must be a number:

$\frac{}{\Gamma ⊢\text{UnaryExpression}⊲\text{Expression}:\text{number}}$

Req. IDE-109: Logical Not Operator Constraints (ver. 1)

There are no specific constraints defined for with $u.op=\text{!}$.

##### Type Inference

The following operators have fixed types independent of their operand types:

#### 8.1.13. Multiplicative Expression

##### Syntax
MultiplicativeExpression returns Expression: UnaryExpression
(=>({MultiplicativeExpression.lhs=current} op=MultiplicativeOperator) rhs=UnaryExpression)*;
enum MultiplicativeOperator: times='*' | div='/' | mod='%';
##### Semantics

Req. IDE-110: Multiplicative Expression Constraints (ver. 1)

For a given multiplicative expression the following constraints must hold in N4JS mode :

• The types of the operands may be any type:

$\frac{}{\Gamma ⊢\text{MultiplicativeExpression}⊲\text{Expression}:\text{any}}$

If a non-numeric operand is used, the result may be NaN which actually is a number as well.

##### Type Inference
[[type-inference-9]]

The inferred type of a multiplicative expression always is number:

$\frac{}{\Gamma ⊢\text{MultiplicativeExpression}:\text{number}}$

##### Syntax
AdditiveExpression returns Expression: MultiplicativeExpression
enum AdditiveOperator: add='+' | sub='-';
##### Semantics

Req. IDE-111: Additive Expression Constraints (ver. 1)

For a given additive expression the following constraints must hold in N4JS mode:

• The type of the operand can be any type:

In JavaScript it is possible to subtract two non-numerics, leading to NaN. Also undefined or null may be used. The real difference is what type is to be returned (string or number, see below).

##### 8.1.14.1. Type Inference

The type of an additive expression is usually inferred to number, except for addition which may lead to string as well. The result for the addition operator is only be a number if both operands are numbers, booleans, null, or undefined. Using undefined in an additive expression leads to NaN which actually is a number from the type system’s point of view. Additional analysis may create errors in the latter case though.

We first define two helper rules to simplify the addition operator condition:

The type of an additive expression $e$ is inferred as follows:

$\begin{array}{c}\frac{e.op{=}^{\text{'}}{+}^{\text{'}}\phantom{\rule{3.0mm}{0ex}}¬toNum\left(e\right)\phantom{\rule{3.0mm}{0ex}}¬mayNum\left(e\right)}{\Gamma ⊢e:\text{string}}\\ \frac{e.op{=}^{\text{'}}{+}^{\text{'}}\phantom{\rule{3.0mm}{0ex}}¬toNum\left(e\right)\phantom{\rule{3.0mm}{0ex}}mayNum\left(e\right)}{\Gamma ⊢e:union\left\{number,string\right\}}\\ \frac{e.op{=}^{\text{'}}{+}^{\text{'}}\phantom{\rule{3.0mm}{0ex}}toNum\left(e\right)}{\Gamma ⊢e:\text{number}}\\ \frac{e.op{\le }^{\text{'}}{+}^{\text{'}}}{\Gamma ⊢e:\text{number}}\end{array}$

That is, if both operands are number, int, boolean, null, or even undefined, then the 'plus' is interpreted as mathematical addition and the result is a number. In other cases the 'plus' is interpreted as string concatenation and the result is a string. In case of union types, the result may be a union of number and string.

Adding two integers (int) leads to a number, since the result may not be represented as an (JavaScript) int anymore.

Example 87. Type of addition expression
1+2;            // number 3
"1"+"2";        // string "12"
"1"+2;          // string "12"
1+true;         // number 2
false+1;        // number 1
"1"+true;       // string "1true"
"1"+null;       // string "1null"
1+null;         // number 1
1+undefined;    // number NaN
"1"+undefined;  // string "1undefined"

Support new Symbol.toPrimitive.

#### 8.1.15. Bitwise Shift Expression

##### Syntax
Cf. +[+<<ECMA11a,ECMA11a(p.p.76f)>>+]+
ShiftExpression returns Expression: AdditiveExpression
;

ShiftOperator returns ShiftOperator:
'>' '>' '>'? // SHR, USHR
| '<' '<'  // SHL
;
##### Semantics

Req. IDE-112: Bitwise Shift Expression Constraints (ver. 1)

For a given bitwise shift expression $e$ the following constraints must hold in N4JS mode: * The types of the operands can be any.

##### Type Inference

The type returned by a bitwise shift expression is always number:

A non-numeric operand is interpreted as 0, except for true which is interpreted as 1; or objects implementing the symbol toPrimitive.

#### 8.1.16. Relational Expression

##### Syntax
RelationalExpression returns Expression: ShiftExpression
(=>({RelationalExpression.lhs=current} op=RelationalOperator) rhs=ShiftExpression)*;

RelationalExpressionNoIn returns Expression: ShiftExpression
(=>({RelationalExpression.lhs=current} op=RelationalOperatorNoIn) rhs=ShiftExpression)*;

enum RelationalOperator:
lt='<' | gt='>' | lte='<=' | gte='>=' | instanceof | in;
RelationalOperatorNoIn returns RelationalOperator:
'<' | '>' | '<=' | '>=' | 'instanceof';
##### Semantics

For a given relational expression $e$ with $e.op\in \left\{<,>,<=,>=\right\}$ in N4JS mode, the following constraints must hold:

• The operands must have the same type and the type must be either a number, string, or boolean:

Req. IDE-114: Instanceof Operator Constraints (ver. 1)

For a given relational expression $e$ with $e.op=\text{instanceof}$, the following constraints must hold:

• The right operand of the instanceof operator must be a Function [49]

In other words,

is contained in the the first type rule, an object type reference [50] or an enum type reference.

The type of a definition site structural classifier $C$ is not of type C. Thus, the instanceof operator cannot be used for structural types. Use-site structural typing is also not possible since ~ would be interpreted (by the parser) as a binary operator.

Req. IDE-115: Operator Constraints (ver. 1)

For a given relational expression $e$ with $e.op=\text{in}$, the following constraints must hold:

1. The right operand of the in operator must be an Object:

2. In N4JS mode, the left operand is restricted to be of type string or number:

A special feature of N4JS is support for interface type references in combination with the instance of operator. The compiler rewrites the code to make this work.

Example 88. instanceof with Interface

The following example demonstrates the use of the operator with an interface. This is, of course, not working in pure ECMAScript.

interface I {}

class A implements I {}
class B extends A {}
class C {}

function f(name: string, p: any) {
if (p instanceof I) {
console.log(name + " is instance of I");
}
}

f("A", new A())
f("B", new B())
f("C", new C())

This will print out

A is instance of I
B is instance of I
##### Type Inference

The type of a relational expression always is boolean;

#### 8.1.17. Equality Expression

##### Syntax
EqualityExpression returns Expression: RelationalExpression
(=>({EqualityExpression.lhs=current} op=EqualityOperator) rhs=RelationalExpression)*;

EqualityExpressionNoIn returns Expression: RelationalExpressionNoIn
(=>({EqualityExpression.lhs=current} op=EqualityOperator) rhs=RelationalExpressionNoIn)*;

enum EqualityOperator: same='===' | nsame='!==' | eq='==' | neq='!=';
##### Semantics

There are no hard constraints defined for equality expressions.

In N4JSmode, a warning is created if for a given expression $lhs\text{(’===’—’!==’)}rhs$, neither $\Gamma ⊢lhs.upper<:rhs.upper$ nor $\Gamma ⊢rhs.upper<:lhs.upper$ and no interface or composed type is involved as the result is constant in these cases.

Note that a warning is only created if the upper bounds do not match the described constraints. This is necessary for wildcards. For example in

// with
class A{} class B extends A{}
function isFirst(ar: Array<? extends A>, b: B): boolean {
return b === ar[0]
}

the type of array elements is ? extends A.
Neither $\text{? extends A}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\text{B}$ nor $\text{B}\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\text{? extends A}$ is true. This is why the upper bounds are to be used.

##### Type Inference

The inferred type of an equality expression always is boolean.

#### 8.1.18. Binary Bitwise Expression

##### Syntax
BitwiseANDExpression returns Expression: EqualityExpression
(=> ({BitwiseANDExpression.lhs=current} '&') rhs=EqualityExpression)*;

BitwiseANDExpressionNoIn returns Expression: EqualityExpressionNoIn
(=> ({BitwiseANDExpression.lhs=current} '&') rhs=EqualityExpressionNoIn)*;

BitwiseXORExpression returns Expression: BitwiseANDExpression
(=> ({BitwiseXORExpression.lhs=current} '^') rhs=BitwiseANDExpression)*;

BitwiseXORExpressionNoIn returns Expression: BitwiseANDExpressionNoIn
(=> ({BitwiseXORExpression.lhs=current} '^') rhs=BitwiseANDExpressionNoIn)*;

BitwiseORExpression returns Expression: BitwiseXORExpression
(=> ({BitwiseORExpression.lhs=current} '|') rhs=BitwiseXORExpression)*;

BitwiseORExpressionNoIn returns Expression: BitwiseXORExpressionNoIn
(=> ({BitwiseORExpression.lhs=current} '|') rhs=BitwiseXORExpressionNoIn)*;
##### Semantics

For a given bitwise bitwise expression $e$ the following constraints must hold in N4JS mode:

• The types of the operands must be both number.

##### Type Inference

The type returned by a binary bitwise expression is always $number$:

#### 8.1.19. Binary Logical Expression

##### Syntax
LogicalANDExpression returns Expression: BitwiseORExpression
(=> ({LogicalANDExpression.lhs=current} '&&') rhs=BitwiseORExpression)*;
LogicalANDExpressionNoIn returns Expression: BitwiseORExpressionNoIn
(=> ({LogicalANDExpression.lhs=current} '&&') rhs=BitwiseORExpressionNoIn)*;

LogicalORExpression returns Expression: LogicalANDExpression
(=> ({LogicalORExpression.lhs=current} '||') rhs=LogicalANDExpression)*;
LogicalORExpressionNoIn returns Expression: LogicalANDExpressionNoIn
(=> ({LogicalORExpression.lhs=current} '||') rhs=LogicalANDExpressionNoIn)*;
##### Semantics

Req. IDE-117: Binary Logical Expression Constraints (ver. 1)

For a given binary logical expression $e$ with $e.lhs.type:L$ and $e.rhs.type:R$ the following constraints must hold:

• In N4JS mode $L$ must not be undefined or null.

##### Type Inference

The evaluation relies on ECMAScript’s abstract operation ToBoolean [ECMA11a(p.p.43)]. A short-circuit evaluation strategy is used so that depending on the types of the operands, different result types may be inferred. In particular, the inferred type usually is not boolean ((cf. [ECMA11a(p.S11.11., p.p.83ff)] ). The type inference does not take this short-circuit evaluation strategy into account, as it will affect the result in case one of the types is null either or undefined, which is not allowed in N4JS mode.

$\frac{}{\Gamma ⊢lhs\text{’}&&\text{’—’——’}rhs:union\left\{\Gamma ⊢lhs,\Gamma ⊢rhs\right\}}$

#### 8.1.20. Conditional Expression

##### Syntax
ConditionalExpression returns Expression: LogicalORExpression
(=> ({ConditionalExpression.expression=current} '?') trueExpression=AssignmentExpression  ':' falseExpression=AssignmentExpression)?;

ConditionalExpressionNoIn returns Expression: LogicalORExpressionNoIn
(=> ({ConditionalExpression.expression=current} '?') trueExpression=AssignmentExpression  ':' falseExpression=AssignmentExpressionNoIn)?;
##### Semantics

Req. IDE-118: Conditional Expression Constraints (ver. 1)

For a given conditional expression $e$ with

$e.expression.type:C,$
$e.trueExpression.type:T,$
$e.false-Expression.type:F$

the following constraints must hold:

• A warning will be issued in N4JSmode if $e.expression$ evaluates to a constant value. That is to say
$e.expression\in \left\{false,true,null,undefined\right\}$ or $C\in \left\{\text{void},\text{undefined}\right\}$.

There are no specific constraints defined for the condition. The ECMAScript operation ToBoolean [ECMA11a(p.S9.2, p.p.43)] is used to convert any type to boolean.

##### Type Inference

The inferred type of a conditional expression is the union of the true and false expression (cf. [ECMA11a(p.S11.12, p.p.84)] ():

Example 89. Type of Conditional Expressions

Given the following declarations:

class A{}       class B extends A{}
class C{}       class D extends A{}
class G<T> { field: T; }

var ga: G<A>, gb: G<B>;
a: A, b: B, c: C, d: D;
var boolean cond;

Then the type of the following conditional expression is inferred as noted in the comments:

cond ? a : a;                           // A
cond ? a : b;                           // union{A,B}
cond ? a : c;                           // union{A,C}
cond ? b : d;                           // union{B,D}
cond ? (cond ? a : b) : (cond ? c : d); // union{A,B,C,D}
cond ? (cond ? a : b) : (cond ? b : d); // union{A,B,D}
cond ? ga : gb;                         // union{G<A>,G<B>}

#### 8.1.21. Assignment Expression

##### Syntax
AssignmentExpression <In, Yield>:
lhs=Expression op=AssignmentOperator rhs=AssignmentExpression<In,Yield>
;
AssignmentOperator:
'='
| '*=' | '/=' | '%=' | '+=' | '-='
| '<<=' | '>>=' | '>>>='
| '&=' | '^=' | '|='
;
##### Semantics

Req. IDE-119: Simple Assignment (ver. 1)

For a given assignment $assignment$ with

$assignment.op=\text{’=’}$

the following constraints must hold:

1. $\left[\phantom{\rule{-0.167em}{0ex}}\left[assignment.lhs\right]\phantom{\rule{-0.167em}{0ex}}\right]\phantom{\rule{1.0mm}{0ex}}<\text{:}\phantom{\rule{1.0mm}{0ex}}\left[\phantom{\rule{-0.167em}{0ex}}\left[assignment.rhs\right]\phantom{\rule{-0.167em}{0ex}}\right]$

In the following inference rule and the constraint, ’@’ is to be replaced with the right part of one of the assignment operators listed above, that is,

Req. IDE-120: Compound Assignment (ver. 1)

For a given assignment , with $op=\text{’@=’}$ but not +=, both, left and right must be subtypes of number.
For operator +=,

• if the left-hand side is a number, then must return a number as well. The right-hand side must, in fact, be a number (and not a boolean) here in order to avoid unexpected results.

• if the left-hand side is a string, then $left\text{’+’}right$ must return a string as well. That means that the right-hand side can be of any type.

The expected type for the left-hand side is union{number,string}.

The basic idea behind these constraints is that the type of the left-hand side is not to be changed by the compound assignment.

Req. IDE-121: Write Acccess (ver. 1)

For a given assignment expression $assignExpr$, the left-hand side must be writeable or a final data field and the assignment must be in the constructor. Let $v$ be the bound variable (or field) with $bind\left(assignExpr.left,v\right)$

$\begin{array}{c}v.writeable\vee v.final\wedge \phantom{\rule{3.0mm}{0ex}}\phantom{\rule{2.0em}{0ex}}v.expr=\text{null}\\ \phantom{\rule{3.0mm}{0ex}}\phantom{\rule{2.0em}{0ex}}\wedge assignExpr.containingFunction=v.owner.constructor\\ \phantom{\rule{3.0mm}{0ex}}\phantom{\rule{2.0em}{0ex}}\wedge \mu \left(assignExpr.left\right)=\text{PropertyAccess}\\ \phantom{\rule{3.0mm}{0ex}}\phantom{\rule{4.0em}{0ex}}\wedge assignExpr.left.target=\text{"this"}\end{array}$

The value of writeable is true for setters and usually for variables and data fields. Assignability of variables and data fields can be restricted via const or the @Final annotation. See Assignment Modifiers(data fields) and Const (const variables) for details.

Also see [Req-IDE-93] for read access constraint.

The left-hand side of an assignment expression may be an array or object literal and the assignment expression is then treated as a destructuring assignment. See Array and Object Destructuring for details.

##### Type Inference

Similarly to [ECMA11a(p.S11.1, p.p.84ff)], we define type inference for simple assignment (=) and compound assignment (op=) individually.

The type of the assignment is simply the type of the right-hand side:

Compound assignments are reduced to the former by splitting an operator @=, in which @ is a simple operator, into a simple operator expression with operator @ and a simple assignment =. Since the type of the latter is the right-hand side, we can define:

#### 8.1.22. Comma Expression

##### Syntax
CommaExpression <In, Yield>:
exprs+=AssignmentExpression<In,Yield> ',' exprs+=AssignmentExpression<In,Yield>
(','    exprs+=AssignmentExpression<In,Yield>)*
;
##### Semantics

All expressions will be evaluated even though only the value of the last expression will be the result.

Example 90. Comma Expression

Assignment expressions preceed comma expressions:

var b: boolean;
b = (12, 34, true); // ok, b=true
b =  12, 34, true ; // error, b=12 is invalid
##### Type Inference

The type of a comma expression $cexpr$ is inferred to the last expression:

$\frac{n=|cexpr.exprs|,\Gamma ⊢cexpr.expr{s}_{n}:T}{\Gamma ⊢cexpr:T}$

### 8.2. ECMAScript 6 Expressions

#### 8.2.1. The super Keyword

SuperLiteral: {SuperLiteral} 'super';

Ap