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 common getName() and hasName() methods.
  • The Employee and Customer message classes will inherit or extend the Person interface. This is equivalent to the java.implements annotation, but is completely encompassed in providence.
  • The Entity union has more edits. It will have an asPerson() method that returns the current union field as the Person interface. And it will mirror all the methods of Person (that it itself implements) and forward these calls to the current union value. Note that a union .. 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);
}