Type-safe two-step computational pipelines

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
0
down vote

favorite












I have several "computation pipelines" that share the same purpose and number of steps, even if the step implementations and the classes of the the intermediate values that are passed between them are different for each pipeline. For example, they might be



$$
newcommandptr[1]oversetmathtt#1longrightarrow
textttRequest ptrstep 1 A ptrstep 2 textttResponse
$$



or



$$
textttRequest ptrstep 1 B ptrstep 2 textttResponse
$$



The start and end of the pipelines are always the same.



I want to avoid duplicating the common "interstitial code" between the steps,
which may do things like logging or error handling. I also want to ensure that:



  • Implementation inheritance is not used. This appears to rule out the "template method" pattern.

  • Type safety is maintained, in the sense that step implementations should not have to downcast an intermediate value at any point.

I came up with the following solution. First, a generic Pipeline interface, parameterized with the type of the intermediate values and with one method for each step:



public interface Pipeline<A> 

A step1(Request request);

Response step2(A intermediate);



Second, a Runner class that is ignorant of the exact type of the intermediate steps:



public final class Runner 

private final Pipeline<?> pipeline;

public Runner(Pipeline<?> pipeline)
super();
this.pipeline = pipeline;


public Response runPipeline(Request request)
// This doesn't fly, wildcard trouble
// return pipeline.step2(pipeline.step1(request));

// With the helper it works
return runPipeline(request,pipeline);


// wildcard capture helper
public static <A> Response runPipeline(Request request, Pipeline<A> pipeline)
A intermediate = pipeline.step1(request);
//
// shared interstitial code here
//
return pipeline.step2(intermediate);




Is there a better way of doing this? Does this type of solution have a name, is it used anywhere else?







share|improve this question





















  • This seems related softwareengineering.stackexchange.com/questions/267037/… but it's not exactly what I want, because in my case I have common Request and Response classes and I want the different pipelines to be of the same type.
    – Daniel Díaz Carrete
    Mar 4 at 8:09
















up vote
0
down vote

favorite












I have several "computation pipelines" that share the same purpose and number of steps, even if the step implementations and the classes of the the intermediate values that are passed between them are different for each pipeline. For example, they might be



$$
newcommandptr[1]oversetmathtt#1longrightarrow
textttRequest ptrstep 1 A ptrstep 2 textttResponse
$$



or



$$
textttRequest ptrstep 1 B ptrstep 2 textttResponse
$$



The start and end of the pipelines are always the same.



I want to avoid duplicating the common "interstitial code" between the steps,
which may do things like logging or error handling. I also want to ensure that:



  • Implementation inheritance is not used. This appears to rule out the "template method" pattern.

  • Type safety is maintained, in the sense that step implementations should not have to downcast an intermediate value at any point.

I came up with the following solution. First, a generic Pipeline interface, parameterized with the type of the intermediate values and with one method for each step:



public interface Pipeline<A> 

A step1(Request request);

Response step2(A intermediate);



Second, a Runner class that is ignorant of the exact type of the intermediate steps:



public final class Runner 

private final Pipeline<?> pipeline;

public Runner(Pipeline<?> pipeline)
super();
this.pipeline = pipeline;


public Response runPipeline(Request request)
// This doesn't fly, wildcard trouble
// return pipeline.step2(pipeline.step1(request));

// With the helper it works
return runPipeline(request,pipeline);


// wildcard capture helper
public static <A> Response runPipeline(Request request, Pipeline<A> pipeline)
A intermediate = pipeline.step1(request);
//
// shared interstitial code here
//
return pipeline.step2(intermediate);




Is there a better way of doing this? Does this type of solution have a name, is it used anywhere else?







share|improve this question





















  • This seems related softwareengineering.stackexchange.com/questions/267037/… but it's not exactly what I want, because in my case I have common Request and Response classes and I want the different pipelines to be of the same type.
    – Daniel Díaz Carrete
    Mar 4 at 8:09












up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have several "computation pipelines" that share the same purpose and number of steps, even if the step implementations and the classes of the the intermediate values that are passed between them are different for each pipeline. For example, they might be



$$
newcommandptr[1]oversetmathtt#1longrightarrow
textttRequest ptrstep 1 A ptrstep 2 textttResponse
$$



or



$$
textttRequest ptrstep 1 B ptrstep 2 textttResponse
$$



The start and end of the pipelines are always the same.



I want to avoid duplicating the common "interstitial code" between the steps,
which may do things like logging or error handling. I also want to ensure that:



  • Implementation inheritance is not used. This appears to rule out the "template method" pattern.

  • Type safety is maintained, in the sense that step implementations should not have to downcast an intermediate value at any point.

I came up with the following solution. First, a generic Pipeline interface, parameterized with the type of the intermediate values and with one method for each step:



public interface Pipeline<A> 

A step1(Request request);

Response step2(A intermediate);



Second, a Runner class that is ignorant of the exact type of the intermediate steps:



public final class Runner 

private final Pipeline<?> pipeline;

public Runner(Pipeline<?> pipeline)
super();
this.pipeline = pipeline;


public Response runPipeline(Request request)
// This doesn't fly, wildcard trouble
// return pipeline.step2(pipeline.step1(request));

// With the helper it works
return runPipeline(request,pipeline);


// wildcard capture helper
public static <A> Response runPipeline(Request request, Pipeline<A> pipeline)
A intermediate = pipeline.step1(request);
//
// shared interstitial code here
//
return pipeline.step2(intermediate);




Is there a better way of doing this? Does this type of solution have a name, is it used anywhere else?







share|improve this question













I have several "computation pipelines" that share the same purpose and number of steps, even if the step implementations and the classes of the the intermediate values that are passed between them are different for each pipeline. For example, they might be



$$
newcommandptr[1]oversetmathtt#1longrightarrow
textttRequest ptrstep 1 A ptrstep 2 textttResponse
$$



or



$$
textttRequest ptrstep 1 B ptrstep 2 textttResponse
$$



The start and end of the pipelines are always the same.



I want to avoid duplicating the common "interstitial code" between the steps,
which may do things like logging or error handling. I also want to ensure that:



  • Implementation inheritance is not used. This appears to rule out the "template method" pattern.

  • Type safety is maintained, in the sense that step implementations should not have to downcast an intermediate value at any point.

I came up with the following solution. First, a generic Pipeline interface, parameterized with the type of the intermediate values and with one method for each step:



public interface Pipeline<A> 

A step1(Request request);

Response step2(A intermediate);



Second, a Runner class that is ignorant of the exact type of the intermediate steps:



public final class Runner 

private final Pipeline<?> pipeline;

public Runner(Pipeline<?> pipeline)
super();
this.pipeline = pipeline;


public Response runPipeline(Request request)
// This doesn't fly, wildcard trouble
// return pipeline.step2(pipeline.step1(request));

// With the helper it works
return runPipeline(request,pipeline);


// wildcard capture helper
public static <A> Response runPipeline(Request request, Pipeline<A> pipeline)
A intermediate = pipeline.step1(request);
//
// shared interstitial code here
//
return pipeline.step2(intermediate);




Is there a better way of doing this? Does this type of solution have a name, is it used anywhere else?









share|improve this question












share|improve this question




share|improve this question








edited Mar 4 at 3:44









200_success

123k14142399




123k14142399









asked Mar 4 at 0:25









Daniel Díaz Carrete

29817




29817











  • This seems related softwareengineering.stackexchange.com/questions/267037/… but it's not exactly what I want, because in my case I have common Request and Response classes and I want the different pipelines to be of the same type.
    – Daniel Díaz Carrete
    Mar 4 at 8:09
















  • This seems related softwareengineering.stackexchange.com/questions/267037/… but it's not exactly what I want, because in my case I have common Request and Response classes and I want the different pipelines to be of the same type.
    – Daniel Díaz Carrete
    Mar 4 at 8:09















This seems related softwareengineering.stackexchange.com/questions/267037/… but it's not exactly what I want, because in my case I have common Request and Response classes and I want the different pipelines to be of the same type.
– Daniel Díaz Carrete
Mar 4 at 8:09




This seems related softwareengineering.stackexchange.com/questions/267037/… but it's not exactly what I want, because in my case I have common Request and Response classes and I want the different pipelines to be of the same type.
– Daniel Díaz Carrete
Mar 4 at 8:09















active

oldest

votes











Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188759%2ftype-safe-two-step-computational-pipelines%23new-answer', 'question_page');

);

Post as a guest



































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes










 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188759%2ftype-safe-two-step-computational-pipelines%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Python Lists

Aion

JavaScript Array Iteration Methods