Extra Providence Features
Providence has some extra features that not only does not work in standard thrift, it will break thrift syntax, or the thrift compiler in some way.
Interfaces
Thrift does not have the concept of interfaces, but providences does. Interfaces are declared as any other struct is, but does not support assigning field IDS.
Interfaces has two main uses, being implemented by a struct, and used by a union for generality. E.g.:
interface Person {
required string name;
}
struct Employee implements Person {
1: required string name;
2: required i32 employee_id;
3: optional double salary;
}
struct Customer implements Person {
1: required i32 customer_id;
2: required string name;
3: optional i32 purchases;
}
union Entity of Person {
1: optional Employee employee;
2: optional Customer customer;
}
This contains two struct each implementing the Person interface. Note that the two uses a different field ID for the required 'name' field. The interface type will generate an interface or abstract class in the languages that support this, and essentially only be validated as having common fields otherwise. This will generate:
- The
Person
interface with the commongetName()
andhasName()
methods. - The
Employee
andCustomer
message classes will inherit or extend thePerson
interface. This is equivalent to thejava.implements
annotation, but is completely encompassed in providence. - The
Entity
union has more edits. It will have anasPerson()
method that returns the current union field as thePerson
interface. And it will mirror all the methods ofPerson
(that it itself implements) and forward these calls to the current union value. Note that aunion .. of
requires that all fields implements the given interface.
Circular Containment
This feature is not explicitly supported or not in thrift, but does not work well in Apache Thrift, meaning that a single struct may contain a field of it's own type, but you may not have two structs each containing the other. This is simply a result of the way Apache Thrift parses the thrift file.
In providence
you may have circular containment if (and only if) all
of the types referring to each other is in the same thrift definition
file. E.g.:
- struct A contains struct B contains struct A.
namespace java net.morimekta.test.calculator
enum Operator {
IDENTITY = 1,
ADD,
SUBTRACT,
MULTIPLY,
DIVIDE
}
union Operand {
1: Operation operation;
2: double number;
}
struct Operation {
1: Operator operator;
2: list<Operand> operands;
}
This makes model structures like the calculator possible. Since the model objects are immutable and created with builders, it is not possible to create a circular instance containment.
Service Sub Methods
Services also support service stub methods, which are declared in a similar
fashion to protobuf
, meaning it will only be declared with a
request and response struct (both must be structs), and no individual parameter
fields.
struct MyRequest {
1: optional string request_field;
}
struct MyResponse {
1: optional string response_field;
}
service MyService {
MyResponse myMethod(MyRequest);
}
This is structurally equivalent to declare the request struct's fields as the method parameters, but may generate different interfaces for using it:
struct MyResponse {
1: optional string response_field;
}
service MyService {
MyResponse myMethod(1: optional string request_field);
}