ballerina-platform / ballerina-spec

Ballerina Language and Platform Specifications
Other
168 stars 53 forks source link

Allow service types to have methods that do not have to be implemented #1320

Open jclark opened 2 hours ago

jclark commented 2 hours ago

A service declaration allows a type-descriptor to be specified for the type of the constructed service object. When declaring a service for an async API, it would be natural to use this to refer to a service type describing the async API, so that the compiler can check that the declared service is consistent with the async API.

This is not useful at the moment because a service object has to provide an implementation of every method declared in the service type, but often an implementation only needs to implement a few of these methods.

This contrasts with the situation with record types and mapping constructors: a mapping constructor does not to have to specify values for those fields that the record type declares as optional or provides a default for.

jclark commented 2 hours ago

One possible solution to this is to allow service object types to declare remote methods as optional. The natural syntax is to use a ? after the method name ((TypeScript uses a similar syntax) e.g.

remote function onError?(string msg);

The semantics are as expected: a service object can belong to the service type even if it does not define a remote method onError. But if it does define this method, the type of the method must be the same requirements as if the service type remote method was not optional.

jclark commented 2 hours ago

There's one significant problem. The user might make a mistake in the name of the method, for example they might declare the method as onErr rather than onError. Since the onError method is optional and since object types are always open (in the sense that additional methods are always allowed), this would not be an error.

There is a similar problem with optional fields in records. The way that Ballerina solves this is to require the field name to be specified as a literal string rather than an identifier in certain cases: specifically, when the inherent type is an optional record type with specific fields, but the mapping constructor is specifying an field name that is not in the record type, then you have to specify the name of the field as a literal string.

One could do something similar by saying requiring the use of quoted method names for remote methods not in the service type, when the service type includes optional remote methods. In this case, to bring consistency between method names and fields names, one could extend the handling of record field names to treated quoted identifiers similarly to literals, or one could allow remote method names to be specified as strings. I don't feel very enthusiastic about this solution, though.

In this case, I think I would prefer to rely on an annotation on the service type to say that this type is being used in an exhaustive way, and it doesn't make sense for the service declaration to define remote methods not in the service type. (Or could this be an annotation on listener types that are intended for async use?)

jclark commented 2 hours ago

It would also be possible to extend this to allow objects to have optional methods generally. But in this case we would need a syntax to call optional methods. The natural thing would be to extend the existing ?. syntax to do method calls.

We would also need a more general solution to the problem in the previous comment.