Wormholes

R

Roedy Green

I run into this sort of problem fairly often.

I have a method x that calls method y through a long chain of
intermediate calls.

I decide to add a feature. Method x has access to information to
decide if the feature should be implemented. Method y is where the
implementation is.

Somehow I must pass information down the long chain from x to y. This
means changing the signatures of all the intermediate methods, and
adjusting code to the new way. This can cause ripples incommensurate
with the triviality of the change.

I imagined some sort of wormhole to allow information in one place to
simply be known somewhere else without the excess exposure of public
variables or tediously arranging transport. I read about Eiffel a
long time ago. IIRC you could provide a list of precisely who could
see any given information.

I wondered if anyone had thoughts on ways of tackling such a problem.
 
E

EricF

I run into this sort of problem fairly often.

I have a method x that calls method y through a long chain of
intermediate calls.

I decide to add a feature. Method x has access to information to
decide if the feature should be implemented. Method y is where the
implementation is.

Somehow I must pass information down the long chain from x to y. This
means changing the signatures of all the intermediate methods, and
adjusting code to the new way. This can cause ripples incommensurate
with the triviality of the change.

I imagined some sort of wormhole to allow information in one place to
simply be known somewhere else without the excess exposure of public
variables or tediously arranging transport. I read about Eiffel a
long time ago. IIRC you could provide a list of precisely who could
see any given information.

I wondered if anyone had thoughts on ways of tackling such a problem.

Having a long chain of intermediate calls sounds like a bad idea, lots of
coupling. Can you refactor to get rid of or at least prune the chain?

Eric
 
A

Arne Vajhøj

I run into this sort of problem fairly often.

I have a method x that calls method y through a long chain of
intermediate calls.

I decide to add a feature. Method x has access to information to
decide if the feature should be implemented. Method y is where the
implementation is.

Somehow I must pass information down the long chain from x to y. This
means changing the signatures of all the intermediate methods, and
adjusting code to the new way. This can cause ripples incommensurate
with the triviality of the change.

I imagined some sort of wormhole to allow information in one place to
simply be known somewhere else without the excess exposure of public
variables or tediously arranging transport. I read about Eiffel a
long time ago. IIRC you could provide a list of precisely who could
see any given information.

I wondered if anyone had thoughts on ways of tackling such a problem.

If you pass a single big object instead of multiple simple types values,
then there should not really be any impact down the chain.

Arne
 
M

markspace

I run into this sort of problem fairly often.

I have a method x that calls method y through a long chain of
intermediate calls.


I think I'm with Eric F. on this. Given some long chain of calls: X, A,
B, C D, ... Y, can that be refactored so that X calls Y directly?

void methodX() {
A();
}

to

void methodX() {
AResult result = A();
X( result, otherData );
}

I'm thinking that if your methods have to pass data through a long chain
of calls, then the code is badly structured period. You might as well
use the opportunity to refactor rather than trying to invent a "wormhole."

I can think of at least one way to implement a wormhole. I'm just not
going to go there because it's a terrible idea.
 
R

Robert Klemme

That sounds like a warning sign for the way you structure code.
I'm thinking that if your methods have to pass data through a long chain
of calls, then the code is badly structured period. You might as well
use the opportunity to refactor rather than trying to invent a "wormhole."

If there are public library methods involved the situation is much
worse: then Roedy probably cannot refactor but has to add functionality...
I can think of at least one way to implement a wormhole. I'm just not
going to go there because it's a terrible idea.

I am pretty confident I know what you mean. I would even go as far as
to calling usage of that "opening a can of worms". There are also
negative side effects on testability...

Kind regards

robert
 
Z

Zermelo

Roedy Green said:
Somehow I must pass information down the long chain from x to y. This
means changing the signatures of all the intermediate methods, and
adjusting code to the new way. This can cause ripples incommensurate
with the triviality of the change.

Add a static variable to x accessible to y.
 
S

Stuart

If you pass a single big object instead of multiple simple types values,
then there should not really be any impact down the chain.

Arne

+1

I had to write some generic measurement routines that would be the same
for almost all of our measurement machines (strategy pattern). However,
some machines would acquire additional data on the way, so I had to pass
this additional information to the internal measurement routines and the
additional measurement data back to the calling routines. I turned all
parameters and results into objects that could be subclassed as needed.
I think that this is nothing too unusual and scales pretty well.

Regards,
Stuart
 
S

Steven Simpson

Somehow I must pass information down the long chain from x to y. This
means changing the signatures of all the intermediate methods, and
adjusting code to the new way. This can cause ripples incommensurate
with the triviality of the change.

Assuming that you can't improve your structure or refactor, a
ThreadLocal might be appropriate as your wormhole.

I've had to do this lately. The intermediate steps were recursive calls
through a hierarchy. y was a custom implementation of a node nested in
that hierarchy. x started off the recursive call.

If I was only using the hierarchy once, for one call by x, I would have
simply embedded the context in y. But the hierarchy was to be re-used,
and y needed a different context for each call by x. Also, calls by x
could be concurrent.

However, I could guarantee that any single call by x would invoke y by
the same thread. That allowed the context to be passed by a
ThreadLocal, set by x just before the call.

I suppose you could do something similar without threads, e.g.:

class Context {
Map<ContextLocal<?>, Object> items = new IdentityHashMap<>();
}

class ContextLocal<T> {
void set(Context ctxt, T val) {
ctxt.put(this, val);
}

T get(Content ctxt) {
return (T) ctxt.get(this);
}
}

Then you'd refactor once to pass Context through the chain. x creates a
static ContextLocal<MyContext> myContext, and one Context ctxt for each
call, and sets up myContext.set(ctxt, value) before the call. y calls
myContext.get(ctxt) to get the value.
 
G

Gene Wirchenko

Because a static variable is accessible from every methods. The same is
not true for an instance variable.

The horror of global variables raises its head.

[snip]

Sincerely,

Gene Wirchenko
 
N

Nigel Wade

I run into this sort of problem fairly often.

I have a method x that calls method y through a long chain of
intermediate calls.

I decide to add a feature. Method x has access to information to
decide if the feature should be implemented. Method y is where the
implementation is.

What about Properties? They might provide a suitably "global" solution
without too much coupling. A class with its own internal static
Properties variable, and static methods to set/get the properties. Then
method x can set any property it likes, and method y can attempt to read
any property it likes. Unset properties return null, or a default value
if you implement a getProperty(key, default) method.
 
D

Daniel Pitts

I run into this sort of problem fairly often.

I have a method x that calls method y through a long chain of
intermediate calls.

I decide to add a feature. Method x has access to information to
decide if the feature should be implemented. Method y is where the
implementation is.

Somehow I must pass information down the long chain from x to y. This
means changing the signatures of all the intermediate methods, and
adjusting code to the new way. This can cause ripples incommensurate
with the triviality of the change.

I imagined some sort of wormhole to allow information in one place to
simply be known somewhere else without the excess exposure of public
variables or tediously arranging transport. I read about Eiffel a
long time ago. IIRC you could provide a list of precisely who could
see any given information.

I wondered if anyone had thoughts on ways of tackling such a problem.

If you arrange to pass-through a Parameter Object instead of a bunch of
related parameters, this could solve your problem in many (not all) cases.

The primary benefit of a Parameter Object is that you can add new fields
(if they have sensible defaults) without a rippling change to all
existing users of the method which takes the Parameter Object.

There are other potential benefits as well. Your Parameter Object might
have a nice "Builder" counterpart which makes it easier to specify
optional parameters (using call-chaining for example).

A special case of the Parameter Object is often called the Context.
Many types of frameworks pass around a Context object to all methods.
The HttpServletRequest object is such an example (a.k.a The Request
Context). This is a more generic form than Parameter Object, and I don't
suggest it for most usages, as you can end up with name-collisions, type
problems, and other problems that can't be diagnosed at compile time.
 
D

Daniel Pitts

Without substantial refectoring I don't see any other solution.
The solution is substantial refactoring. Global variables introduce all
kinds of problems, including but not limited to: Packratting,
concurrency issues, debugging problems, "action at a distance" problems,
etc...
 
R

Roedy Green

Having a long chain of intermediate calls sounds like a bad idea, lots of
coupling. Can you refactor to get rid of or at least prune the chain?

I think I misdescribed this. x knows a detail of how the
implementation should work. The code that uses that detail in y is at
the end of a long chain, not the implementation itself. The
implementation is quite complicated, so if I shortened the chain, I
woulds have to increase the size of the methods on the way there.
 
L

Lew

Because a static variable is accessible from every methods. The same is
not true for an instance variable.

Yes, it is, if the OP follows the advice given by other respondents to pass
around a data object.

And static variables carry grave risks.
I think the OP can reach this solution by himself.

Perhaps, but it's not what you recommended.
The OP seems unwilling to restructure his code.

So you recommend a land-mine strategy to what, punish him
for that?
 
R

Roedy Green

Add a static variable to x accessible to y.

it would have to have default scope. I hoping there was a technique
that would behave like that, but which would not expose the variable
to the entire package, when really only one method should use that
variable.

The techniques that I can think of are default scope variable or pass
value down call chain to where it is used. Are there any others?
 
D

David Lamb

I run into this sort of problem fairly often.

I have a method x that calls method y through a long chain of
intermediate calls.

I decide to add a feature. Method x has access to information to
decide if the feature should be implemented. Method y is where the
implementation is.

Are these methods in many separate classes and objects, or just one? If
x, y, and all the intermediate c1..cN methods are in the same class,
it's pretty easy to create a private (or protected) variable to be set
by x and used by y (and presumably other equivalents of y if x has to
invoke a different long chain of intermediate calls). Though this isn't
thread-safe if multiple threads can call x.

If y is a method of a separate class, there ought to be some way to
return the object z on which y would be invoked and have x invoke
z.y(...). But perhaps for some reason you can't revise the code that way.
 
A

Arne Vajhøj

Because a static variable is accessible from every methods. The same is
not true for an instance variable.


I think the OP can reach this solution by himself.

If one decide to go the "global route", then a singleton with
a non static getter seems to be a much nicer solution than a
directly accessible static field.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top