-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose a noop implementation for each interface in API that can be embedded #3865
Comments
I think this is a good idea. I think we will need to continue commenting our interface, but this allows implementers nervous of the accretion causing panics to embedded the no-op and inserted default to dropping. I'll put together a PR tomorrow. |
This issue touches on two ideas:
In discussing this during last week's SIG meeting the synopsis was that (2) is desirable even without (1), but there is hesitation around (1). The main concern was that by requiring all implementations to embed an implementation or the interface itself it changed the compatibility problem where a user would get a compile time error to one of a runtime panic or a runtime ignoring. Add private methods to all exported API interfaces
Do not add private methods to all exported API interfaces
@Aneurysm9 please feel free to edit this or comment below with things I missed |
Open alternatives to look intoProvide an implementation similar No-Op but it logs an error if an unimplemented method is called. |
Another idea could be: type MeterProviderKey interface {
meterProvider()
}
type MeterProvider interface {
MeterProviderKey
// All the exported methods ...
}
type MeterKey interface {
meter()
}
type Meter interface {
MeterKey
// All the exported methods ...
}
type InstrumentKey interface {
instrument()
}
type Int64Counter interface {
InstrumentKey
// All the exported methods ...
}
// All the other instruments ... This would separate the unexported method from the usable interface. This means that SDK authors could embed say The (rather large) downside here is that there will need to be all these |
This actually isn't too bad if the "key" types are contained in their own package. Here is the proof-of-concept. It provides an option that means SDK authors will still need to make an explicit choice (not embedding a type will not compile), but they can choose to embed a type from |
Would we have this same problem if only the SDK were to embed the NoOp implementation of the Interface in question? In theory, when we add a method to the interface and the NoOp, being part of the API package would get updated, makes the SDK not break. This would mean that if an API user (library author) uses the new API they won't get any data. But I think this is better than an SDK user (application author) getting a cryptic message about &meterProvider not being a metric.MeterProvider when they update some unrelated dependency. We could leave a warning to SDK authors (both us and others) that they should do the same to avoid breaking SDKs when the API updates. |
I'm not sure I follow. Yes, the intention of adding a private method is to make SDK authors choose how they want unimplemented methods to be handled and embedding the No-Op in their implementation is an option. Is this what you mean? |
Don't change the API interface; create in the API package a public NoOp implementation. In the SDK, embed that implementation. When a new method is added, and you use an old SDK, it will fall back to the NoOp. This doesn't solve for a different SDK author not embedding, but we don't need to. What this will solve is someone updating an dependency, which updates the API, and the application not compiling because |
Sure, this is the option broken down in the "Do not add private methods to all exported API interfaces" section of #3865 (comment) and using the No-Op from idea (1). The question is do we want to signal to SDK authors that they need to make this choice by including a private method. |
Possibly superseded by #3920 |
Looking at the metrics API, looks like we made lots of progress in terms of the "scary" messages around the interfaces "this can be extended".
I see this in the API (even though the comment on
Synchronous
is related to grouping also allows you to extend the interface, since every implementation MUST embed the interface):API:
SDK:
This is good "on paper" since you somehow achieve the goal to be able to extend the interface (based on your implementation only instrument.Synchronous can be extended) and still compile but not necessary able to run successfully the binary. This problem was present in Java versions before Java 1.8 when interfaces could not have default implementation for funcs, and you will hit the same problem, if a new func is added to the interface and someone calls it but the implementation does not override it you will get a panic.
The solution in Java < 1.8 was to use abstract classes, which we can/should implement here as well. We will ask the users to embed the "abstract class" instead of the struct.
The suggestion would be to do:
API
This way every func added to Float64Counter will have a "no-op" or default behavior in any impl, even not updated.
The text was updated successfully, but these errors were encountered: