Stage 3 Draft / February 21, 2021

ECMAScript class static initialization blocks

Introduction

This proposal defines new syntax to perform privleged static initialization of a class.

See the proposal repository for background material and discussion.

1 ECMAScript Data Types and Values

1.1 ECMAScript Specification Types

1.1.1 ClassStaticBlockDefinition Records

A ClassStaticBlockDefinition Record is a Record value used to encapsulate the executable code for a class static initialization block.

ClassStaticBlockDefinition Records have the fields listed in Table 1.

Table 1: ClassStaticBlockDefinition Record Fields
Field Name Value Meaning
[[Body]] An function object. The function object to be called during static initialization of a class.

2 Abstract Operations

2.1 Operations on Objects

2.1.1 EvaluateStaticBlock ( receiver , blockRecord )

  1. Assert: Type(receiver) is Object.
  2. Assert: blockRecord is a ClassStaticBlockDefinition Record.
  3. Perform ? Call(blockRecord.[[Body]], receiver).

3 ECMAScript Language: Expressions

3.1 Identifiers

3.1.1 Static Semantics: Early Errors

BindingIdentifier : Identifier
  • It is a Syntax Error if the code matched by this production is contained in strict mode code and the StringValue of Identifier is "arguments" or "eval".
  • It is a Syntax Error if the code matched by this production is nested, directly or indirectly (but not crossing function or static initialization block boundaries), within a ClassStaticBlock and the StringValue of Identifier is "await".
LabelIdentifier : Identifier
  • It is a Syntax Error if the code matched by this production is nested, directly or indirectly (but not crossing function or static initialization block boundaries), within a ClassStaticBlock and the StringValue of Identifier is "await".
IdentifierReference : Identifier
  • It is a Syntax Error if the code matched by this production is nested, directly or indirectly (but not crossing function or static initialization block boundaries), within a ClassStaticBlock and the StringValue of Identifier is "arguments" or "await".

4 ECMAScript Language: Statements and Declarations

4.1 The continue Statement

4.1.1 Static Semantics: Early Errors

ContinueStatement : continue ; ContinueStatement : continue LabelIdentifier ;
  • It is a Syntax Error if this ContinueStatement is not nested, directly or indirectly (but not crossing function or static initialization block boundaries), within an IterationStatement.

4.2 The break Statement

4.2.1 Static Semantics: Early Errors

BreakStatement : break ;

5 ECMAScript Language: Functions and Classes

5.1 Class Definitions

Syntax

ClassElement[Yield, Await] : MethodDefinition[?Yield, ?Await] static MethodDefinition[?Yield, ?Await] FieldDefinition[?Yield, ?Await] ; static FieldDefinition[?Yield, ?Await] ; ClassStaticBlock ; ClassStaticBlock : static { ClassStaticBlockBody } ClassStaticBlockBody : ClassStaticBlockStatementList ClassStaticBlockStatementList : StatementList[~Yield, ~Await, ~Return]opt

5.1.1 Static Semantics: Early Errors

ClassStaticBlock : static { ClassStaticBlockBody } ClassStaticBlockBody : ClassStaticBlockStatementList

5.1.2 Static Semantics: ClassElementKind

ClassElement : ClassStaticBlock
  1. Return NonConstructorMethod.

5.1.3 Static Semantics: Contains

ClassStaticBlock : static { ClassStaticBlockBody }
  1. Return false.
Note
Static semantic rules that depend upon substructure generally do not look into static initialization blocks.

5.1.4 Static Semantics: ContainsDuplicateLabels

With parameter labelSet.

ClassStaticBlockStatementList : [empty]
  1. Return false.

5.1.5 Static Semantics: ContainsUndefinedBreakTarget

With parameter labelSet.

ClassStaticBlockStatementList : [empty]
  1. Return false.

5.1.6 Static Semantics: ContainsUndefinedContinueTarget

With parameters iterationSet and labelSet.

ClassStaticBlockStatementList : [empty]
  1. Return false.

5.1.7 Static Semantics: HasDirectSuper

ClassStaticBlock : static { ClassStaticBlockBody }
  1. Return ClassStaticBlockBody Contains SuperCall.

5.1.8 Static Semantics: PropName

ClassElement : ClassStaticBlock
  1. Return empty.

5.1.9 Static Semantics: LexicallyDeclaredNames

ClassBlockStatementList : [empty]
  1. Return a new empty List.
ClassBlockStatementList : StatementList
  1. Return the TopLevelLexicallyDeclaredNames of StatementList.

5.1.10 Static Semantics: VarDeclaredNames

ClassBlockStatementList : [empty]
  1. Return a new empty List.
ClassBlockStatementList : StatementList
  1. Return the TopLevelVarDeclaredNames of StatementList.

5.1.11 Static Semantics: VarScopedDeclarations

ClassBlockStatementList : [empty]
  1. Return a new empty List.
ClassBlockStatementList : StatementList
  1. Return the TopLevelVarScopedDeclarations of StatementList.

5.1.12 Runtime Semantics: ClassStaticBlockDefinitionEvaluation

With parameter homeObject.

ClassStaticBlock : static { ClassStaticBlockBody }
  1. Let lex be the running execution context's LexicalEnvironment.
  2. Let privateScope be the running execution context's PrivateEnvironment.
  3. Let body be OrdinaryFunctionCreate(Method, « », ClassStaticBlockBody, lex, privateScope).
  4. Perform MakeMethod(body, homeObject).
  5. Return the ClassStaticBlockDefinition Record { [[Body]]: body }.

5.1.13 Runtime Semantics: ClassElementEvaluation

With parameters object and enumerable.

ClassElement : ClassStaticBlock
  1. Return ClassStaticBlockDefinitionEvaluation of ClassStaticBlock with argument object.
Note
DRAFT NOTE: See ClassElementEvaluation in the Static Class Features proposal for more information.

5.1.14 Runtime Semantics: ClassDefinitionEvaluation

Note
DRAFT NOTE: This algorithm is a delta from the Static Class Features proposal.

With parameter className.

ClassTail : ClassHeritageopt { ClassBodyopt }
  1. Let lex be the LexicalEnvironment of the running execution context.
  2. Let classScope be NewDeclarativeEnvironment(lex).
  3. Let classScopeEnvRec be classScope's EnvironmentRecord.
  4. If className is not undefined, then
    1. Perform classScopeEnvRec.CreateImmutableBinding(className, true).
  5. Let outerPrivateEnvironment be the PrivateEnvironment of the running execution context.
  6. Let classPrivateEnvironment be NewDeclarativeEnvironment(outerPrivateEnvironment).
  7. Let classPrivateEnvRec be classPrivateEnvironment's EnvironmentRecord.
  8. If ClassBodyopt is present, then
    1. For each element dn of the PrivateBoundIdentifiers of ClassBodyopt,
      1. Perform classPrivateEnvRec.CreateImmutableBinding(dn, true).
  9. If ClassHeritageopt is not present, then
    1. Let protoParent be the intrinsic object %ObjectPrototype%.
    2. Let constructorParent be the intrinsic object %FunctionPrototype%.
  10. Else,
    1. Set the running execution context's LexicalEnvironment to classScope.
    2. NOTE: The running execution context's PrivateEnvironment is outerPrivateEnvironment when evaluating ClassHeritage.
    3. Let superclass be the result of evaluating ClassHeritage.
    4. Set the running execution context's LexicalEnvironment to lex.
    5. ReturnIfAbrupt(superclass).
    6. If superclass is null, then
      1. Let protoParent be null.
      2. Let constructorParent be the intrinsic object %FunctionPrototype%.
    7. Else if IsConstructor(superclass) is false, throw a TypeError exception.
    8. Else,
      1. Let protoParent be ? Get(superclass, "prototype").
      2. If Type(protoParent) is neither Object nor Null, throw a TypeError exception.
      3. Let constructorParent be superclass.
  11. Let proto be ObjectCreate(protoParent).
  12. If ClassBodyopt is not present, let constructor be empty.
  13. Else, let constructor be ConstructorMethod of ClassBody.
  14. If constructor is empty, then
    1. If ClassHeritageopt is present and protoParent is not null, then
      1. Let constructor be the result of parsing the source text
        constructor(... args){ super (...args);}
        using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
    2. Else,
      1. Let constructor be the result of parsing the source text
        constructor( ){ }
        using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
  15. Set the running execution context's LexicalEnvironment to classScope.
  16. Set the running execution context's PrivateEnvironment to classPrivateEnvironment.
  17. Let constructorInfo be the result of performing DefineMethod for constructor with arguments proto and constructorParent as the optional functionPrototype argument.
  18. Assert: constructorInfo is not an abrupt completion.
  19. Let F be constructorInfo.[[Closure]].
  20. If ClassHeritageopt is present and protoParent is not null, then set F.[[ConstructorKind]] to "derived".
  21. Perform MakeConstructor(F, false, proto).
  22. Perform MakeClassConstructor(F).
  23. Perform CreateMethodProperty(proto, "constructor", F).
  24. If ClassBodyopt is not present, let elements be a new empty List.
  25. Else, let elements be NonConstructorMethodDefinitions of ClassBody.
  26. Let instanceFields be a new empty List.
  27. Let staticFieldsstaticElements be a new empty List.
  28. For each ClassElement e in order from elements, do
    1. If IsStatic of e is false, then
      1. Let fieldelement be the result of performing ClassElementEvaluation for e with arguments proto and false.
    2. Else,
      1. Let fieldelement be the result of performing ClassElementEvaluation for e with arguments F and false.
    3. If fieldelement is an abrupt completion, then
      1. Set the running execution context's LexicalEnvironment to lex.
      2. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
      3. Return Completion(fieldelement).
    4. If fieldelement is a ClassFieldDefinition Record, then
      1. If IsStatic of e is false, append fieldelement to instanceFields.
      2. Else, append fieldelement to staticFieldsstaticElements.
    5. If element is a ClassStaticBlockDefinition Record, then
      1. Append element to staticElements.
  29. Set the running execution context's LexicalEnvironment to lex.
  30. If className is not undefined, then
    1. Perform classScopeEnvRec.InitializeBinding(className, F).
  31. Set F.[[Fields]] to instanceFields.
  32. If PrivateBoundIdentifiers of ClassBody contains a Private Name P such that P.[[Kind]] is either "method" or "accessor" and P.[[Brand]] is proto, then
    1. Set F.[[PrivateBrand]] to proto.
  33. If PrivateBoundIdentifiers of ClassBody contains a Private Name P such that P.[[Kind]] is either "method" or "accessor" and P.[[Brand]] is F, then
    1. Perform ? PrivateBrandAdd(F, F).
  34. For each element fieldRecordelementRecord of staticFieldsstaticElements in List order, do
    1. Perform ? DefineField(F, fieldRecord).
    2. If elementRecord is a ClassFieldDefinition Record, then
      1. Let status be the result of performing DefineField(F, elementRecord).
    3. Else,
      1. Assert: fieldRecord is a ClassStaticBlockDefinition Record.
      2. Let status be the result of performing EvaluateStaticBlock(F, elementRecord).
    4. If status is an abrupt completion, then
      1. Set the running execution context's LexicalEnvironment to lex.
      2. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
      3. Return Completion(status).
  35. Set the running execution context's LexicalEnvironment to lex.
  36. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
  37. Return F.

A Copyright & Software License

Copyright Notice

© 2021 Ron Buckton, Ecma International

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.