5
$\begingroup$

I want to include multiple sub functions:

$b(x) = 10x$

$w(x) = s + b(x)$

$c(x) = x^2$

into two main functions:

$ua(x) = w(x)-c(x)$

$ub(x) = w(x)-c(x)^2$

As a reaction to this answer, I wrote the following in mathematica:

b[x_] := 10 x
w[b_, x_] := s + b[x]
c[x_] := x^2

ua[w_,b_,c_,x_] := w[b,x] - c[x]
ub[w_,b_,c_,x_] := w[b,x] - (c[x])^2

My intention is to have those main functions that can be called with just x values (e.g. Plot functions with x as the dependent variable)

I want subfunctions building my main function because:

  • Easier control of the sub functions
  • Main function looks "cleaner"
  • No code duplication

Q: What is the right way to achieve the desired behavior?

$\endgroup$
3
  • $\begingroup$ Now that you've clarified the question: You're overcomplicating this! You can just write it the way you wrote it in math: b[x_] := 10 x; w[x_] := s + b[x]; c[x_] := x^2; u[x_] := w[x] - c[x] $\endgroup$
    – user484
    Jul 17, 2014 at 10:42
  • $\begingroup$ @Rahul Narain : Ok I think my initial mistake was due to my prior research for functions dependent on other functions that led me to a wrong start. So my initial approach was just wrong, thank you. $\endgroup$
    – Jan
    Jul 17, 2014 at 10:51
  • 1
    $\begingroup$ I'm sorry about the effort I caused, when I rewrote the question. I think because I overcomplicated my approach, the answers where not what I wanted to know. Lesson learned that I should think about my basic intentions and ask question about that, rather than writing my "solution" and ask if it's wrong or inefficient... $\endgroup$
    – Jan
    Jul 17, 2014 at 10:57

3 Answers 3

7
$\begingroup$

It comes down to the DRY principle:

The DRY principle is stated as "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system."

The content management system Wordpress doesn't use object oriented paradigms and so for that reason it looks exactly like your code. Tens of thousands of lines of code like this. Its slogan is, appropriately, "code is poetry" - and as you know there aren't and rules carved in stone when it comes to art.

Consider giving a piece of code its own function if the piece of code is going to be used in many different places and it says something important in itself. If you can think of a semantic name for the function that indicates that you should do it. You can start by using as few functions as possible and then when you notice that you want to use a piece of code that you already have somewhere else, you can refactor by putting that piece of code in its own function.

Your functions shouldn't in my opinion be written like that because you don't reuse code and the names of your functions don't make your code more semantic.

For example, I would refactor

drawPlot[hexColor1_, hexColor2_] := Plot[
  {Sin[x], Cos[x]},
  {x, 0, 4 Pi},
  PlotStyle -> {
    RGBColor @@ (IntegerDigits[ToExpression@StringReplace[#, "#" -> "16^^"], 256, 3]/255.) &@hexColor1, 
    RGBColor @@ (IntegerDigits[ToExpression@StringReplace[#, "#" -> "16^^"], 256, 3]/255.) &@hexColor2
    }
  ]

into

hexToRGB[hex_] := RGBColor @@ (IntegerDigits[ToExpression@StringReplace[#, "#" -> "16^^"], 256, 3]/255.) &@hex

drawPlot[hexColor1_, hexColor2_] := Plot[
  {Sin[x], Cos[x]},
  {x, 0, 4 Pi},
  PlotStyle -> {
    hexToRGB[hexColor1],
    hexToRGB[hexColor2]
    }
  ]

  (* Usage example: drawPlot["#66cccc", "#ff3232"] *)

Because hexToRGB is semantic and helps the reader of the code to understand what it does, and because it helps me avoid duplication of code. It's not always as obvious as this, but your reasons for additional "dependencies" should in my opinion be some version of this.

The hex to RGB function was taken from this Q&A.

$\endgroup$
5
$\begingroup$

I find using Module the easiest way to keep track of things when it comes to these kinds of situations.

plot[x_, s_] := Module[{b, w, c, ua, ub},
  b = 10 x;
  w = s + b;
  c = x^2;
  ua = w - c;
  ub = w - c^2;
  Plot[{ua, ub}, {x, -5, 5}]]
plot[randomVar, 5]

Mathematica graphics

$\endgroup$
4
$\begingroup$

Initial problem

There is, in my opinion, nothing wrong with "multidependences" in the way I think you mean, but there is a more fundamental problem here (I believe). Consider these definitions:

w[b_, x_] := fixed + b[x]
u[w_, b_, x_] := Sqrt[w[b, x]]

I presume that you expect to call u with three arguments and have it in turn call w but this does not happen (in general) because you used the same Symbol name for both a function and a parameter:

u[1, 2, 3]
Sqrt[1[2, 3]]

Please clarify your intent regarding this and if necessary correct this aspect of your example.


Update

Responding now to your updated question I largely agree with seismatica's answer, which I just voted for. However I'll give you an answer in my own words.

First, as described above under most circumstances you should not be passing function names as well, reducing your code to the same form as your declared functions:

b[x_] := 10 x
w[x_] := s + b[x]
c[x_] := x^2

ua[x_] := w[x] - c[x]
ub[x_] := w[x] - c[x]^2

There are two potential issues I see here. The first is that the "namespace" is "poluted" with b, w, c which as I understand are never to be called outside of ua and ub. The second is that you introduce a longer than necessary evaluation chain for the functions ua and ub. Consider this Trace:

ub[3] // Trace
{ub[3], w[3] - c[3]^2, {w[3], s + b[3], {b[3], 10 3, 30}, s + 30, 30 + s},
 {{{c[3], 3^2, 9}, 9^2, 81}, -81, -81}, (30 + s) - 81,
  -81 + (30 + s), -81 + 30 + s, -51 + s}

When the formula is merely:

ub[x]
s + 10 x - x^4

It is a good time to note that ub is not merely a function of x but also of s, and I do recommend making that an explicit parameter rather than relying on a global value. Also, as seismatica showed you can also make these simple expression definitions rather than functions. Combining all this I would instead write:

Block[{s, x, b, w, c},
  b = 10 x;
  w = s + b;
  c = x^2;
  ua[s_][x_] = w - c;
  ub[s_][x_] = w - c^2;
]

Note the Block a the use of Set (=) rather than SetDelayed (:=) in the definitions of ua and ub. These work in harmony: the Block prevents unwanted assignments from interfering with the evaluation that results from Set. Let's look at the definitions we created:

?ua
?ub

Global`ua

ua[s_][x_] = s + 10 x - x^2

Global`ub

ub[s_][x_] = s + 10 x - x^4

Note that the simplified definitions are used. Despite the fact that these definitions were made using Set they are now safe from global assignments to s or x as arguments will be substituted into the right-hand-side before further evaluation.

Compare this Trace:

ub[s][3] // Trace
{ub[s][3], s + 10 3 - 3^4, {10 3, 30}, {{3^4, 81}, -81, -81}, s + 30 - 81, -51 + s}

Note that I chose to use SubValues syntax for the definitions. This is not necessary but it allows you to treat ub[s] as a function that can e.g. be mapped:

ub[3] /@ {2, 4, 6}
{7, -213, -1233}

(For this particular function it would be better to use ub[3][{2, 4, 6}] -- see Case #4 of this self-Q&A.)

$\endgroup$
6
  • $\begingroup$ I have overslept 100k, congratulations! :) $\endgroup$
    – Kuba
    Jul 17, 2014 at 9:48
  • $\begingroup$ I think, as being a beginner with mathematica, I got a little confused about the meaning of functions. I would rather call w[b_,x_] just with the x-value. But as I read in this post: Function of a function , I need to include function names into the dependencies. $\endgroup$
    – Jan
    Jul 17, 2014 at 9:48
  • $\begingroup$ @Jan That's alright. It's a complex system with a style unlike most others. Thanks for taking the time to write a well formatted question. Frequently it will be helpful (here) to explain what you are actually trying to do to open the door for suggestions of alternate approaches, and to help people understand what your code does, or what you think it does. $\endgroup$
    – Mr.Wizard
    Jul 17, 2014 at 9:52
  • $\begingroup$ @Jan I found the question you referenced ambiguous at the time it was asked and looking again I still find it so. This situation would be a good application of the maxim above: what are you actually trying to accomplish? My instinct says that you should simply be defining u[b_, x_] := Sqrt[w[b, x]] but without a bit more context it would be foolish to state that absolutely. $\endgroup$
    – Mr.Wizard
    Jul 17, 2014 at 9:56
  • $\begingroup$ @Jan In this case I suggest you edit this one. (In this case because I am the only one to answer, and it was fast. It would be rude to fundamentally change a question after people have posted answers that took effort.) $\endgroup$
    – Mr.Wizard
    Jul 17, 2014 at 9:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.