# Dependency injection - use a specific implementation of one function within another

Consider...

f[x_]:=Body containing h[some args]...
g[x_]:=Body containing h[some args]...


However I want to define something like...

The h to use inside f has this definition h[args___]:=f specific definition.
The h to use inside g has this definition h[args___]:=g specific definition.


I know I can do this using Block wrapped around the call to f and g but I was curious if some cunning extension of UpValues would work; more like a dependency injector pattern. My experience of using UpValues is very limited and reading the documentation for UpValues it would appear to be appropriate only when the precise pattern of h within f or g is known.

Added 26/08/2014 10:11 (London) The specific problem I was trying to apply this to concerned two very similar functions that produce some graphics. Those graphics required different scaling functions to produce their results. What I wanted to do was attach in some way the specific scaling to the relevant function but separate from the plotting functions themselves. Block comes closest to what I was trying to achieve. I may go with this.

Many thanks to all who answered.

-
I think this question would benefit if you described the purpose of doing this. –  Pickett Aug 23 at 9:57

You are correct here:

it would appear to be appropriate only when the precise pattern of h within f or g is known.

The reason for this is that the pattern engine generally moves outside-in as it is rewriting expressions. A simple example is this:

a[b[c[d]]] /. s_Symbol :> (Sow@s; s) // Reap


{a[b[c[d]]], {{a, b, c, d}}}

By contrast, actual evaluation occurs inside-out:

a@x_:=(Sow@a;x)
b@x_:=(Sow@b;x)
c@x_:=(Sow@c;x)
a[b[c[d]]] // Reap


{d, {{c, b, a}}}

Rewrite rules don't generally look outside the current expression being scanned, as otherwise the pattern engine would be very inefficient. Hence, Mathematica will not allow definitions like this:

d /: a[w___, b[x___, c[y___, d[z_]]]] := {w, x, y}^z


TagSetDelayed::tagpos: Tag d in a[w___,b[x___,c[y___,d[z_Integer]]]] is too deep for an assigned rule to be found. >>

So technically the limitations on this type of definition are even narrower than you supposed, since this fails despite being a specific pattern description. You can only look at the head immediately surrounding the head you are attaching a definition to, like this:

b /: a[x___, b[y_], z___] := {x, z}^y


In other words, per the documentation for TagSet:

The symbol f in f/:lhs=rhs must appear in lhs as the head of lhs, the head of the head, one of the elements of lhs, or the head of one of the elements.

So Block is indeed the way to go about this. It supplies a temporary definition for the rewrite rules that applies to everything within the Block expression but does not alter the global rules. This way, Mathematica does not have to walk potentially all the way up the expression tree (which could be very big) as it tries to apply rewrite rules.

ClearAll @ "Global*";
a[x_]:=Block[{d=1},x];
a[b[c[d]]]


b[c[1]]

These can of course be nested, too:

b[x_]:=Block[{d=2},x];
a[b[c[d]]]


c[2]

-
I posted without reading prior answers. Please tell me if you feel that my answer is redundant. (and +1 of course) –  Mr.Wizard Aug 23 at 3:43
@Mr.Wizard Your angle is a bit different and you touch on points I did not address, so in my opinion it is complementary. –  mfvonh Aug 23 at 8:53

It is not clear to me what you desire. You wrote:

I know I can do this using Block wrapped around the call to f and g

Yet you did not articulate why this is not the solution that you want. Rather than wrapping the call to (use of) f and g I would put Block inside those functions:

f[x_] := Block[{h = Plus}, h[5, x]]
g[x_] := Block[{h = Power}, h[5, x]]

f[3]
g[3]

8

125


UpValues definitions require a specific head to attach them to so you cannot affect f[x] via x where x is arbitrary. What I mean is that you cannot attach a rule to h in the definition of ff[x_] := h[5, x] because h does not appear as the head of an argument of ff.

If you explain what you are actually trying to do and why the direct use of Block I illustrated above does not accomplish it I shall attempt to give you solutions.

-

I am not sure I completely understand, but perhaps something like (using TagSetDelayed):

h /: f[h[s_]] := f[s^2 + a]
h /: g[h[s_]] := g[s^3 + b]


or perhaps more simply (but I personally find harder to "read")

f[h[s_]] ^:= f[s^2 + a]
g[h[s_]] ^:= f[s^3 + b]


now h has been defined as follows:

f[h[x]]
(* f[a + x^2] *)


and

g[h[x]]
(* g[b + x^3] *)


So when h[x] is "inside" f its definition is to square its argument and add a, and when h[x] is "inside" g its definition is to cube its argument and add b.

Furthermore, if you define f

f[x_] := Sin[x]


then

f[h[x]]
(* Sin[a + x^2] *)
`
-