Workflow Interface Hierarchy - Reuse methods

I remember legacy documentation for java-sdk had an example showing the use of interface inheritance hierarchy to reuse code. I see it for php though, guess the behavior is the same - Workflows in PHP | Legacy documentation for Temporal SDKs

I think general summary is we can reuse Signal & Query methods from the parent, but not @WorkflowMethod.

I have a few workflows, which call the same childWorkflow. what is the best way to reuse the call to childWorkflow.

I am thinking of creating a simple base interface, which has a normal default method to call childworkflow and other workflows simply extend it. so when other workflows call the method they are essentially calling from their workflow method context. Hope this is a correct approach.

You can define a base interface without annotating the interface and then create two subinterfaces that are annotated.

 public interface WorkflowBase {
    @WorkflowMethod
    String execute(String arg);
  }

  @WorkflowInterface
  public interface WorkflowA extends WorkflowBase {}

  @WorkflowInterface
  public interface WorkflowB extends WorkflowBase {}

  public static class WorkflowBImpl implements WorkflowB {
    @Override
    public String execute(String arg) {
      return "WorkflowBImpl" + arg;
    }
  }

  public static class WorkflowAImpl implements WorkflowA {
    @Override
    public String execute(String arg) {
      return "WorkflowAImpl" + arg;
    }
  }

See the testPolymortphicStart unit test from the java-sdk.

I was initially thinking of using simple inheritance to call a common child workflow like this:

public class InheritanceStartTest {

  @Rule
  public SDKTestWorkflowRule testWorkflowRule =
      SDKTestWorkflowRule.newBuilder()
          .setWorkflowTypes(WorkflowAImpl.class, WorkflowBImpl.class)
          .build();

  @Test
  public void testInheritanceStart() {

    final WorkflowA workflowA = testWorkflowRule.newWorkflowStubTimeoutOptions(WorkflowA.class);
    final WorkflowB workflowB = testWorkflowRule.newWorkflowStubTimeoutOptions(WorkflowB.class);

    String results = workflowA.execute("0") + ", " + workflowB.execute("1");
    Assert.assertEquals("WorkflowAImpl0, WorkflowBImpl1", results);
  }

  public interface WorkflowBase {
    default String callCommonChildWorkflow(String arg) {
      return "Calling callCommonChildWorkflow from:" + arg;
    }
  }

  @WorkflowInterface
  public interface WorkflowA extends WorkflowBase {
    @WorkflowMethod
    String execute(String arg);
  }

  @WorkflowInterface
  public interface WorkflowB extends WorkflowBase {
    @WorkflowMethod
    String execute(String arg);
  }

  public static class WorkflowBImpl implements WorkflowB {
    @Override
    public String execute(String arg) {
      System.out.println(callCommonChildWorkflow(this.getClass().getName()));
      return "WorkflowBImpl" + arg;
    }
  }

  public static class WorkflowAImpl implements WorkflowA {
    @Override
    public String execute(String arg) {
      System.out.println(callCommonChildWorkflow(this.getClass().getName()));
      return "WorkflowAImpl" + arg;
    }
  }
}

but with your example I can do the same with polymorphism(for workflow abstraction) like this:

public class PolymorphicStartTest {

  @Rule
  public SDKTestWorkflowRule testWorkflowRule =
      SDKTestWorkflowRule.newBuilder()
          .setWorkflowTypes(WorkflowAImpl.class, WorkflowBImpl.class)
          .build();

  @Test
  public void testPolymorphicStart() {
    WorkflowBase[] stubs =
        new WorkflowBase[] {
          testWorkflowRule.newWorkflowStubTimeoutOptions(WorkflowA.class),
          testWorkflowRule.newWorkflowStubTimeoutOptions(WorkflowB.class)
        };
    String results = stubs[0].execute("0") + ", " + stubs[1].execute("1");
    Assert.assertEquals("WorkflowAImpl0, WorkflowBImpl1", results);
  }

  public interface WorkflowBase {
    @WorkflowMethod
    default String execute(String arg) {
      return "Calling child workflow from: " + arg;
    }
  }

  @WorkflowInterface
  public interface WorkflowA extends WorkflowBase {}

  @WorkflowInterface
  public interface WorkflowB extends WorkflowBase {}

  public static class WorkflowBImpl implements WorkflowB {
    @Override
    public String execute(String arg) {
      System.out.println(WorkflowB.super.execute(this.getClass().getName()));
      return "WorkflowBImpl" + arg;
    }
  }

  public static class WorkflowAImpl implements WorkflowA {
    @Override
    public String execute(String arg) {
      System.out.println(WorkflowA.super.execute(this.getClass().getName()));
      return "WorkflowAImpl" + arg;
    }
  }
}

@maxim both of them are valid?

I think both are valid. Including the default implementation into the RPC interface definition looks like an anti-pattern.