From 7ad5e5ee1b8b29451c501845bf6de7be3d76fcae Mon Sep 17 00:00:00 2001 From: jmacd Date: Wed, 11 Sep 2019 08:20:43 -0700 Subject: [PATCH 01/13] Create WIP PR --- text/0005-global-init.md | 1 + 1 file changed, 1 insertion(+) diff --git a/text/0005-global-init.md b/text/0005-global-init.md index e68c4a51e..948049e6b 100644 --- a/text/0005-global-init.md +++ b/text/0005-global-init.md @@ -1,6 +1,7 @@ # Global SDK initialization *Status: proposed* +*Updated: 07/30/2019* Specify the behavior of OpenTelemetry APIs and implementations at startup. From 3476dc7b63cf3fa6905c2a2466a5dccfcf9934be Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 14 Oct 2019 14:50:00 -0700 Subject: [PATCH 02/13] Update to 0005 based on https://github.com/open-telemetry/opentelemetry-go/issues/198 --- text/0005-global-init.md | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/text/0005-global-init.md b/text/0005-global-init.md index 948049e6b..48648d14a 100644 --- a/text/0005-global-init.md +++ b/text/0005-global-init.md @@ -1,7 +1,6 @@ # Global SDK initialization -*Status: proposed* -*Updated: 07/30/2019* +*Status: accepted* Specify the behavior of OpenTelemetry APIs and implementations at startup. @@ -52,10 +51,12 @@ party libraries to use the global SDK before it is installed, which is addressed in a requirement stated below. The explicit initializer method should take independent `Tracer` and -`Meter` objects (e.g., `opentelemetry.Init(Tracer, Meter)`). The SDK -may be installed no more than once. After the first SDK installed, -subsequent calls to the explicit initializer shall log console -warnings. +`Meter` factories (e.g., `opentelemetry.Init(TracerFactory, +MeterFactory)`), factories because they facility explicitly named +`Tracer` and `Meter` instances. The SDK must not be installed more +than once. After the first SDK installed, subsequent calls to the +explicit initializer shall log console warnings but not replace the +active SDK. In common language, uses of the global SDK instance (i.e., the Tracer and Meter) must "begin working" once the SDK is installed, with the @@ -72,9 +73,8 @@ they continue as No-op spans. There may be loss of metrics at startup. -Metric SubMeasure objects (i.e., metrics w/ predefined labels) -initialized before the SDK is installed will redirect to the global -SDK after it is installed. +Metric instruments and handles initialized before the SDK is installed +will redirect to the global SDK after it is installed. ### Concrete types @@ -86,9 +86,13 @@ not depend on the SDK being installed. ### Testing support -Testing should be performed without depending on the global SDK. - -### Synchronization +Testing should be performed without depending on the global SDK, if +possible. If it is necessary to install a global `Tracer` or `Meter` +factory for code that explicitly relies on the global factories for +testing, test libraries should provide a compatible SDK that can be +registered once with support for dynamically adding and removing +exporters. The use of named `Tracer` and `Meter` instances will help +avoid test interference in this case. Since the global Tracer and Meter objects are required to begin working once the SDK is installed, there is some implied From 90e5c59d44192837f7d226c27e0c6694eda321f7 Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 14 Oct 2019 16:19:07 -0700 Subject: [PATCH 03/13] Typo --- text/0005-global-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0005-global-init.md b/text/0005-global-init.md index 48648d14a..5507fd2df 100644 --- a/text/0005-global-init.md +++ b/text/0005-global-init.md @@ -52,7 +52,7 @@ addressed in a requirement stated below. The explicit initializer method should take independent `Tracer` and `Meter` factories (e.g., `opentelemetry.Init(TracerFactory, -MeterFactory)`), factories because they facility explicitly named +MeterFactory)`), factories because they construct explicitly named `Tracer` and `Meter` instances. The SDK must not be installed more than once. After the first SDK installed, subsequent calls to the explicit initializer shall log console warnings but not replace the From 4952a5b4c1512c57958f52235b404fe212ccd2ac Mon Sep 17 00:00:00 2001 From: jmacd Date: Tue, 15 Oct 2019 09:23:30 -0700 Subject: [PATCH 04/13] Remove sentence --- text/0005-global-init.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/text/0005-global-init.md b/text/0005-global-init.md index 5507fd2df..fe39e9408 100644 --- a/text/0005-global-init.md +++ b/text/0005-global-init.md @@ -91,8 +91,7 @@ possible. If it is necessary to install a global `Tracer` or `Meter` factory for code that explicitly relies on the global factories for testing, test libraries should provide a compatible SDK that can be registered once with support for dynamically adding and removing -exporters. The use of named `Tracer` and `Meter` instances will help -avoid test interference in this case. +exporters. Since the global Tracer and Meter objects are required to begin working once the SDK is installed, there is some implied From 413081b348ea5c04ca4daf1b9e902142ecf38e5c Mon Sep 17 00:00:00 2001 From: jmacd Date: Wed, 16 Oct 2019 16:51:49 -0700 Subject: [PATCH 05/13] Add motivation --- text/0005-global-init.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/text/0005-global-init.md b/text/0005-global-init.md index fe39e9408..11f670302 100644 --- a/text/0005-global-init.md +++ b/text/0005-global-init.md @@ -10,7 +10,8 @@ OpenTelemetry is designed with a separation between the API and the SDK which implements it, allowing an application to configure and bind any compatible SDK at runtime. OpenTelemetry is designed to support "zero touch" instrumentation for third party libraries through the use -of a global instance. +of a global Tracer and Meter factory instances. This OTEP proposes a +specification for how to initialize the global factory instances. In many programming environments, it is possible for libraries of code to auto-initialize, allowing them to begin operation concurrently with @@ -19,6 +20,19 @@ presents a set of opposing requirements: (1) the API supports a configurable SDK; (2) third party libraries may use OpenTelemetry without configuration. +Without specifying at-most-once initialization for these global +factory instances, any module of code could conceivably re-install a +new SDK at any time during program execution. This proposal ensures +that only the application main() function, or a suitable framework, +has explicit control over when the SDK is installed; further, it is +able to check whether the operation succeeded and abort if the SDK +could not be installed properly. After initialization, the operator +can be sure the intended SDK was installed and will remain installed. + +This OTEP also specifies the behavior of the global instances when +they are used before an SDK is installed, which is a problem in some +languages. + ## Explanation There are several acceptable ways to address this situation. The From e22ba90cd189cf71d75e292dd6bd8a2a324f3e79 Mon Sep 17 00:00:00 2001 From: jmacd Date: Fri, 20 Dec 2019 15:06:12 -0800 Subject: [PATCH 06/13] Update and revise --- text/0005-global-init.md | 242 +++++++++++++++++++++++---------------- 1 file changed, 142 insertions(+), 100 deletions(-) diff --git a/text/0005-global-init.md b/text/0005-global-init.md index 11f670302..a66416d63 100644 --- a/text/0005-global-init.md +++ b/text/0005-global-init.md @@ -1,128 +1,170 @@ # Global SDK initialization -*Status: accepted* - Specify the behavior of OpenTelemetry APIs and implementations at startup. ## Motivation OpenTelemetry is designed with a separation between the API and the -SDK which implements it, allowing an application to configure and bind -any compatible SDK at runtime. OpenTelemetry is designed to support -"zero touch" instrumentation for third party libraries through the use -of a global Tracer and Meter factory instances. This OTEP proposes a -specification for how to initialize the global factory instances. - -In many programming environments, it is possible for libraries of code -to auto-initialize, allowing them to begin operation concurrently with -the main program, e.g., while initializing static program state. This -presents a set of opposing requirements: (1) the API supports a -configurable SDK; (2) third party libraries may use OpenTelemetry -without configuration. - -Without specifying at-most-once initialization for these global -factory instances, any module of code could conceivably re-install a -new SDK at any time during program execution. This proposal ensures -that only the application main() function, or a suitable framework, -has explicit control over when the SDK is installed; further, it is -able to check whether the operation succeeded and abort if the SDK -could not be installed properly. After initialization, the operator -can be sure the intended SDK was installed and will remain installed. +SDK, allowing an application to configure and bind an SDK at runtime. +OpenTelemetry is designed to support "zero touch" instrumentation for +third party libraries through the use of a global Tracer and Meter +provider (factory) instances. This OTEP proposes a specification for how to +initialize the global provider (factory) instances. + +In some programming environments, it is possible for libraries of code +to auto-initialize static variables, allowing them to begin operation +concurrently with the main program, while initializing static program +state. This presents a set of opposing requirements: (1) the API +supports a configurable SDK; (2) third party libraries can use +OpenTelemetry before the SDK is configured. + +The current specification discusses a global provider (factory) for +named Tracers and Meters as well as a global Propagators instance for +injectors and extractors, but does not discuss how these are +initialized or whether their values can be modified during the process +lifetime. + +Global variables face significant opposition from some developers, +which forces the question: "why support globals at all?". In +languages with automatic dependency injection support, then +conceivably we do not need global variables. In languges without +automatic dependency injection, without globals we could not have the +"zero touch" instrumentation [given as a requirement for the +project](https://github.com/open-telemetry/oteps/blob/master/text/0001-telemetry-without-manual-instrumentation.md). +If a third-party library is to be instrumented and integrated without +modification into an application, either dependency injection or +global variables are the solution. + +Global variables **are a dangerous programming pattern**, but they +also enable easy integration in languages without automatic dependency +injection. To address this risk, this proposal specifies strict +limits on their initialization. We propose at-most-once +initialization for the three global variables in OpenTelemetry. +Specifically, this specification says that the global Tracer provider, +the global Meter provider, and the global Propagators instance can +only be initialized once per process lifetime (except possibly in +test-only scenarios). This OTEP also specifies the behavior of the global instances when -they are used before an SDK is installed, which is a problem in some -languages. +they are used before the SDK is configured and installed, in case this +cannot be performed by automatic dependency injection. ## Explanation -There are several acceptable ways to address this situation. The -feasibility of each approach varies by language. The implementation -must select one of the following strategies: +There are two acceptable ways to provide default instances in +OpenTelemetry: (1) through dependency injection, (2) through global +variables initialized at most once. The feasibility of each approach +varies by language. The implementation MUST select one of the +following strategies. ### Service provider mechanism Where the language provides a commonly accepted way to inject SDK -components, it should be preferred. The Java SPI supports loading and -configuring the global SDK before it is first used, and because of -this property the service provider mechanism case leaves little else -to specify. - -### Explicit initializer - -When it is not possible to ensure the SDK is installed and configured -before the API is first used, loading the SDK is handed off to the -user "at the right time", as stated in [Ruby issue -19](https://github.com/open-telemetry/opentelemetry-ruby/issues/19). -In this case, a number of requirements must be specified, as discussed -next. - -## Requirements: Explicit initializer - -OpenTelemetry specifies that the default implementation is -non-operational (i.e., a "no-op"), requiring that API method calls -result in effectively zero instrumentation overhead. We expect third -party libraries to use the global SDK before it is installed, which is -addressed in a requirement stated below. - -The explicit initializer method should take independent `Tracer` and -`Meter` factories (e.g., `opentelemetry.Init(TracerFactory, -MeterFactory)`), factories because they construct explicitly named -`Tracer` and `Meter` instances. The SDK must not be installed more -than once. After the first SDK installed, subsequent calls to the -explicit initializer shall log console warnings but not replace the -active SDK. - -In common language, uses of the global SDK instance (i.e., the Tracer -and Meter) must "begin working" once the SDK is installed, with the -following stipulations: - -### Tracer +components, it should be preferred. The Java SPI (Service Provider +Interface) supports loading and configuring the SDK before it is first +used. This kind of support is the preferred choice in languages with +common support for automatic dependency injection. -There may be loss of spans at startup. +In this case, there is no use-before-configuration question to +address, as there is in some languages with support for static +initialization. -Spans that are started before the SDK is installed are not recovered, -they continue as No-op spans. +### Explicit initializer mechanism -### Meter - -There may be loss of metrics at startup. - -Metric instruments and handles initialized before the SDK is installed -will redirect to the global SDK after it is installed. - -### Concrete types - -Keys, tags, attributes, labels, resources, span context, and -distributed context are specified as pure API objects, therefore do -not depend on the SDK being installed. +When it is not possible to ensure the SDK is installed and configured +before the API is first used, initializing the default, global SDK +instances becomes the user's responsibility. + +Methods to set the global instances shall be independent, allowing +each SDK component to be intialized separately when the process +starts. The methods shall be declared in a separate API package, +e.g., named `global`: + +```golang +package global + +import ( + "go.opentelemetry.io/otel/api/context/propagation" + "go.opentelemetry.io/otel/api/metric" + "go.opentelemetry.io/otel/api/trace" +) + +// SetMeterProvider initializes the global Meter provider. May only +// be called once per process lifetime. Subsequent calls will panic. +// +// Prior to setting the global Meter provider, the default global +// Meter provider acts as a "forwarding" SDK. The default global +// Meter provider will begin forwarding to the installed Meter +// provider once this is called. +func SetMeterProvider(metric.Provider) { ... } + +// SetPropagators initializes the global Propagators instance. May only +// be called once per process lifetime. Subsequent calls will panic. +// +// Prior to setting the global Meter provider, the default global +// Propagators instance performs pass-through W3C Traceparent and +// Correlation-Context propagation. +func SetPropagators(propagation.Propagators) { ... } + +// SetPropagators initializes the global Tracer provider. May only +// be called once per process lifetime. Subsequent calls will panic. +// +// Prior to setting the global Tracer provider, the default global +// Tracer provider acts as a "forwarding" SDK. The default global +// Tracer provider will begin forwarding to the installed Tracer +// provider once this is called. +func SetTraceProvider(trace.Provider) { ... } +``` + +#### Requirements + +We anticipate third party libraries using the global instances before +they are installed, and we wish for references obtained through these +instances to become functional once the corresponding implementation +is initialized. The default instances returned by the global getters +for Tracer provider, Meter provider, and Propagators must "forward" to +the real SDK implementation once it is installed. + +#### Tracer + +Tracers obtained through the provider will become functional when the +user's Tracer SDK is installed as the global instance. + +Spans started prior to installing the Tracer SDK will be No-op spans. +Installing a Tracer SDK after starting a span via the default global +instance does not change this behavior. + +#### Meter + +Meters obtained through the provider will become functional when the +users's Meter SDK is installed as the global instance. + +Metric events will be dropped until the Meter SDK is installed. + +#### Propagators + +The default global Propagators instance will by default perform +pass-through W3C Traceparent and Correlation-Context propagation. + +The default global Propagators instance will begin forwarding to the +user's Propagators when it is installed as the global instance. ## Trade-offs and mitigations ### Testing support Testing should be performed without depending on the global SDK, if -possible. If it is necessary to install a global `Tracer` or `Meter` -factory for code that explicitly relies on the global factories for -testing, test libraries should provide a compatible SDK that can be -registered once with support for dynamically adding and removing -exporters. - -Since the global Tracer and Meter objects are required to begin -working once the SDK is installed, there is some implied -synchronization overhead at startup, overhead we expect to fall after -the SDK is installed. We recommend explicitly installing a No-op SDK -to fully disable instrumentation, as this approach will have a lower -overhead than leaving the OpenTelemetry library uninitialized. - -## Prior art and alternatives - -As an example that does not qualify as "commonly accepted", see [Go -issue 52](https://github.com/open-telemetry/opentelemetry-go/issues/52) -which demonstrates using the Go `plugin` package to load a -configurable SDK prior to first use. +possible. A convenience method may be provided for tests to reset the +global state to the initial, default conditions. -## Open questions +### Efficiency concern -What other options should be passed to the explicit global initializer? +Since the global instances are required to begin working once the real +implementations are installed, there is some implied synchronization +overhead and cost. This overhead SHOULD be minimal. -Is there a public test for "is the SDK installed; is it a no-op"? +We recommend to explicitly install a No-op instance to lower the cost +of instrumentation when no SDK will be installed, as opposed to +leaving the default global instances in place, perpetually waiting to +begin forwarding. True No-op instances will be slightly less +expensive than the default global instances. From a1e3a33e328dd1e341cefc67399178e5cb3f17c8 Mon Sep 17 00:00:00 2001 From: jmacd Date: Fri, 20 Dec 2019 15:07:22 -0800 Subject: [PATCH 07/13] Rename 74 --- text/{0005-global-init.md => 0074-global-init.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{0005-global-init.md => 0074-global-init.md} (100%) diff --git a/text/0005-global-init.md b/text/0074-global-init.md similarity index 100% rename from text/0005-global-init.md rename to text/0074-global-init.md From b4b7c2e75d647ed45452c3ce1d2394c1ee993f99 Mon Sep 17 00:00:00 2001 From: jmacd Date: Fri, 20 Dec 2019 15:10:27 -0800 Subject: [PATCH 08/13] Typo --- text/0074-global-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0074-global-init.md b/text/0074-global-init.md index a66416d63..990bea855 100644 --- a/text/0074-global-init.md +++ b/text/0074-global-init.md @@ -27,7 +27,7 @@ lifetime. Global variables face significant opposition from some developers, which forces the question: "why support globals at all?". In languages with automatic dependency injection support, then -conceivably we do not need global variables. In languges without +conceivably we do not need global variables. In languages without automatic dependency injection, without globals we could not have the "zero touch" instrumentation [given as a requirement for the project](https://github.com/open-telemetry/oteps/blob/master/text/0001-telemetry-without-manual-instrumentation.md). From 15186990cfb92fcb9994f1365f78f422206d56bd Mon Sep 17 00:00:00 2001 From: jmacd Date: Fri, 20 Dec 2019 15:12:39 -0800 Subject: [PATCH 09/13] Refer to the Go PR --- text/0074-global-init.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/0074-global-init.md b/text/0074-global-init.md index 990bea855..f646ee327 100644 --- a/text/0074-global-init.md +++ b/text/0074-global-init.md @@ -168,3 +168,9 @@ of instrumentation when no SDK will be installed, as opposed to leaving the default global instances in place, perpetually waiting to begin forwarding. True No-op instances will be slightly less expensive than the default global instances. + +## Implemented prototype + +See the [OTel-Go +prototype](https://github.com/open-telemetry/opentelemetry-go/pull/392) +which implements forwarding for the global Meter instance. \ No newline at end of file From 565d71f7df675bc3b1590c4e969aaab7103e16af Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 23 Dec 2019 16:35:21 -0800 Subject: [PATCH 10/13] Add prior art --- text/0074-global-init.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/text/0074-global-init.md b/text/0074-global-init.md index f646ee327..1b8d7ee31 100644 --- a/text/0074-global-init.md +++ b/text/0074-global-init.md @@ -173,4 +173,16 @@ expensive than the default global instances. See the [OTel-Go prototype](https://github.com/open-telemetry/opentelemetry-go/pull/392) -which implements forwarding for the global Meter instance. \ No newline at end of file +which implements forwarding for the global Meter instance. + +## Prior art + +The [OpenTracing global Tracer instance did similar +forwarding](https://github.com/opentracing/opentracing-java/blob/master/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java). + +An [early prototype for injecting an initialized SDK in Golang using +the `plugin` +package](https://github.com/jmacd/opentelemetry-go/pull/1) showed how +to avoid use-before-initialization in that langauge. It was not well +received. + From 7309796d4bda190660332ac81091dbb3628f6c4e Mon Sep 17 00:00:00 2001 From: jmacd Date: Mon, 23 Dec 2019 16:36:23 -0800 Subject: [PATCH 11/13] Typo --- text/0074-global-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0074-global-init.md b/text/0074-global-init.md index 1b8d7ee31..5a2271d68 100644 --- a/text/0074-global-init.md +++ b/text/0074-global-init.md @@ -106,7 +106,7 @@ func SetMeterProvider(metric.Provider) { ... } // Correlation-Context propagation. func SetPropagators(propagation.Propagators) { ... } -// SetPropagators initializes the global Tracer provider. May only +// SetTraceProvider initializes the global Tracer provider. May only // be called once per process lifetime. Subsequent calls will panic. // // Prior to setting the global Tracer provider, the default global From cdfebec03e6d57071e8f9239013672e5d19dd77b Mon Sep 17 00:00:00 2001 From: jmacd Date: Tue, 21 Jan 2020 15:17:03 -0800 Subject: [PATCH 12/13] Feedback: clarify option to use explicitly set globals in addition to DI --- text/0074-global-init.md | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/text/0074-global-init.md b/text/0074-global-init.md index 5a2271d68..f9088bb0a 100644 --- a/text/0074-global-init.md +++ b/text/0074-global-init.md @@ -27,7 +27,7 @@ lifetime. Global variables face significant opposition from some developers, which forces the question: "why support globals at all?". In languages with automatic dependency injection support, then -conceivably we do not need global variables. In languages without +conceivably we may not need global variables. In languages without automatic dependency injection, without globals we could not have the "zero touch" instrumentation [given as a requirement for the project](https://github.com/open-telemetry/oteps/blob/master/text/0001-telemetry-without-manual-instrumentation.md). @@ -54,8 +54,8 @@ cannot be performed by automatic dependency injection. There are two acceptable ways to provide default instances in OpenTelemetry: (1) through dependency injection, (2) through global variables initialized at most once. The feasibility of each approach -varies by language. The implementation MUST select one of the -following strategies. +varies by language. The implementation MUST support at least one of +the following strategies. ### Service provider mechanism @@ -65,9 +65,13 @@ Interface) supports loading and configuring the SDK before it is first used. This kind of support is the preferred choice in languages with common support for automatic dependency injection. -In this case, there is no use-before-configuration question to -address, as there is in some languages with support for static -initialization. +There may be cases where dependency injection is not universally +preferred or simply not as convenient as explicitly setting a +configured SDK. Languages with support for dependency injection MAY +elect to support both mechanisms, provided they are consistent each +other and satisfy the rules: (1) functionality accessed through the +global Tracer and Meter should begin functioning when a configured SDK +is installed, and (2) each global may only be configured once. ### Explicit initializer mechanism @@ -163,17 +167,15 @@ Since the global instances are required to begin working once the real implementations are installed, there is some implied synchronization overhead and cost. This overhead SHOULD be minimal. -We recommend to explicitly install a No-op instance to lower the cost -of instrumentation when no SDK will be installed, as opposed to -leaving the default global instances in place, perpetually waiting to -begin forwarding. True No-op instances will be slightly less -expensive than the default global instances. - ## Implemented prototype -See the [OTel-Go -prototype](https://github.com/open-telemetry/opentelemetry-go/pull/392) -which implements forwarding for the global Meter instance. +The OTel-Go SDK has implemented this feature for both the global +Tracer and Meter instances. It does not support dependency injection. + +The OTel-Java SDK supports the Java SPI mechanism to inject a +configured SDK. [OTel-Java also has a pending +PR](https://github.com/open-telemetry/opentelemetry-java/pull/724) +to implement explicit initializer support. ## Prior art From 8ab6441810cc115d48a824b605c9f917a5f57677 Mon Sep 17 00:00:00 2001 From: jmacd Date: Tue, 21 Jan 2020 15:23:37 -0800 Subject: [PATCH 13/13] Typo --- text/0074-global-init.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0074-global-init.md b/text/0074-global-init.md index f9088bb0a..e7ad5f679 100644 --- a/text/0074-global-init.md +++ b/text/0074-global-init.md @@ -185,6 +185,6 @@ forwarding](https://github.com/opentracing/opentracing-java/blob/master/opentrac An [early prototype for injecting an initialized SDK in Golang using the `plugin` package](https://github.com/jmacd/opentelemetry-go/pull/1) showed how -to avoid use-before-initialization in that langauge. It was not well +to avoid use-before-initialization in that language. It was not well received.