Is it possible to define a partial typespec with the return type delegated to the return type other function?

Hi,

The return type of Ecto.transaction/2 is quite elaborate:

  {:ok, any()}
  | {:error, any()}
  | {:error, Ecto.Multi.name(), any(), %{required(Ecto.Multi.name()) => any()}}

Now, I have this function with runs some Ecto.Multi actions and finally executes in a transaction:

@spec persist(type1, type2) :: ???
def persist(instance1, instance2) do
  Multi.new()
  |> action_for_type1(instance1)
  |> action_for_type2(instance2)
  |> Repo.transaction()
end

Now I don’t want to copy paste the Ecto.transaction/2 return type in the persist/2 typespec. That seems too elaborate. But I do want to define type1 and type2 as the params.

How would one approach this?

Simply stating any as return type leads to loss if information in the typespec. It would be nice if I could somehow partially define the typespec: defining the input params, but leaving the return type automatically derived. Or somehow reference the return type of the Ecto.transaction/2 method.

Generally when I use Multi, the transaction call is immediately followed by a case that unpacks the result into more-specific types for both OK and error cases. IMO the “step names” used in the multi are an implementation detail that shouldn’t be leaked to callers.

1 Like

Yes, that is probably the better approach. Thanks!