{ "hash": "7ab8361570c3e19de9d884ea5d541d09", "result": { "markdown": "# Functions\n\n\n\nThis section will use the following add-on packages:\n\n``` {.julia .cell-code}\nusing CalculusWithJulia, Plots\n```\n\n\n\n\n---\n\n\nA mathematical [function](http://en.wikipedia.org/wiki/Function_(mathematics)) is defined abstractly by:\n\n\n> **Function:** A function is a *relation* which assigns to each element in the domain a *single* element in the range. A **relation** is a set of ordered pairs, $(x,y)$. The set of first coordinates is the domain, the set of second coordinates the range of the relation.\n\n\n\nThat is, a function gives a correspondence between values in its domain with values in its range.\n\n\nThis definition is abstract, as functions can be very general. With single-variable calculus, we generally specialize to real-valued functions of a single variable (*univariate, scalar functions*). These typically have the correspondence given by a rule, such as $f(x) = x^2$ or $f(x) = \\sqrt{x}$. The function's domain may be implicit (as in all $x$ for which the rule is defined) or may be explicitly given as part of the rule. The function's range is then the image of its domain, or the set of all $f(x)$ for each $x$ in the domain ($\\{f(x): x \\in \\text{ domain}\\}$).\n\n\nSome examples of mathematical functions are:\n\n\n\n$$\nf(x) = \\cos(x), \\quad g(x) = x^2 - x, \\quad h(x) = \\sqrt{x}, \\quad\ns(x) = \\begin{cases} -1 & x < 0\\\\1&x>0\\end{cases}.\n$$\n\n\nFor these examples, the domain of both $f(x)$ and $g(x)$ is all real values of $x$, where as for $h(x)$ it is implicitly just the set of non-negative numbers, $[0, \\infty)$. Finally, for $s(x)$, we can see that the domain is defined for every $x$ but $0$.\n\n\nIn general the range is harder to identify than the domain, and this is the case for these functions too. For $f(x)$ we may know the $\\cos$ function is trapped in $[-1,1]$ and it is intuitively clear than all values in that set are possible. The function $h(x)$ would have range $[0,\\infty)$. The $s(x)$ function is either $-1$ or $1$, so only has two possible values in its range. What about $g(x)$? It is a parabola that opens upward, so any $y$ values below the $y$ value of its vertex will not appear in the range. In this case, the symmetry indicates that the vertex will be at $(1/2, -1/4)$, so the range is $[-1/4, \\infty)$.\n\n\n:::{.callout-note}\n## Note\n**Thanks to Euler (1707-1783):** The formal idea of a function is a relatively modern concept in mathematics. According to [Dunham](http://www.maa.org/sites/default/files/pdf/upload_library/22/Ford/dunham1.pdf),\n\n:::\n\nEuler defined a function as an \"analytic expression composed in any way whatsoever of the variable quantity and numbers or constant quantities.\" He goes on to indicate that as Euler matured, so did his notion of function, ending up closer to the modern idea of a correspondence not necessarily tied to a particular formula or βanalytic expression.β He finishes by saying: \"It is fair to say that we now study functions in analysis because of him.\"\n\n\nWe will see that defining functions within `Julia` can be as simple a concept as Euler started with, but that the more abstract concept has a great advantage that is exploited in the design of the language.\n\n\n## Defining simple mathematical functions\n\n\nThe notation `Julia` uses to define simple mathematical functions could not be more closely related to how they are written mathematically. For example, the functions $f(x)$, $g(x)$, and $h(x)$ above may be defined by:\n\n::: {.cell execution_count=4}\n``` {.julia .cell-code}\nf(x) = cos(x)\ng(x) = x^2 - x\nh(x) = sqrt(x)\n```\n\n::: {.cell-output .cell-output-display execution_count=5}\n```\nh (generic function with 1 method)\n```\n:::\n:::\n\n\nThe left-hand sign of the equals sign is an assignment. In this use, a function with a given signature is defined and attached to a method table for the given function name. The right-hand side is simply `Julia` code to compute the *rule* corresponding to the function.\n\n\nCalling the function also follows standard math notation:\n\n::: {.cell execution_count=5}\n``` {.julia .cell-code}\nf(pi), g(2), h(4)\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\n(-1.0, 2, 2.0)\n```\n:::\n:::\n\n\nFor typical cases like the three above, there isn't really much new to learn.\n\n\n:::{.callout-note}\n## Note\nThe equals sign in `Julia` always indicates either an assignment or a mutation of the object on the left side. The definition of a function above is an *assignment*, in that a function is added (or modified) in a table holding the methods associated with the function's name.\n\nThe equals sign restricts the expressions available on the *left*-hand side to a) a variable name, for assignment; b) mutating an object at an index, as in `xs[1]`; c) mutating a property of a stuct; or d) a function assignment following this form `function_name(args...)`.\n\nWhereas function definitions and usage in `Julia` mirrors standard math notation; equations in math are not so mirrored in `Julia`. In mathematical equations, the left-hand of an equation is typically a complicated algebraic expression. Not so with `Julia`, where the left hand side of the equals sign is prescribed and quite limited.\n\n:::\n\n### The domain of a function\n\n\nFunctions in `Julia` have an implicit domain, just as they do mathematically. In the case of $f(x)$ and $g(x)$, the right-hand side is defined for all real values of $x$, so the domain is all $x$. For $h(x)$ this isn't the case, of course. Trying to call $h(x)$ when $x < 0$ will give an error:\n\n::: {.cell execution_count=6}\n``` {.julia .cell-code}\nh(-1)\n```\n\n::: {.cell-output .cell-output-error}\n```\nLoadError: DomainError with -1.0:\nsqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).\n```\n:::\n:::\n\n\nThe `DomainError` is one of many different error types `Julia` has, in this case it is quite apt: the value $-1$ is not in the domain of the function.\n\n\n### Equations, functions, calling a function\n\n\nMathematically we tend to blur the distinction between the equation\n\n\n\n$$\ny = 5/9 \\cdot (x - 32)\n$$\n\n\nand the function\n\n\n\n$$\nf(x) = 5/9 \\cdot (x - 32)\n$$\n\n\nIn fact, the graph of a function $f(x)$ is simply defined as the graph of the equation $y=f(x)$. There is a distinction in `Julia` as a command such as\n\n::: {.cell execution_count=7}\n``` {.julia .cell-code}\nx = -40\ny = 5/9 * (x - 32)\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\n-40.0\n```\n:::\n:::\n\n\nwill evaluate the right-hand side with the value of `x` bound at the time of assignment to `y`, whereas assignment to a function\n\n::: {.cell hold='true' execution_count=8}\n``` {.julia .cell-code}\nf(x) = 5/9 * (x - 32)\nf(72)\t\t\t\t## room temperature\n```\n\n::: {.cell-output .cell-output-display execution_count=9}\n```\n22.22222222222222\n```\n:::\n:::\n\n\nwill create a function object with a value of `x` determined at a later time - the time the function is called. So the value of `x` defined when the function is created is not important here (as the value of `x` used by `f` is passed in as an argument).\n\n\nWithin `Julia`, we make note of the distinction between a function object versus a function call. In the definition `f(x)=cos(x)`, the variable `f` refers to a function object, whereas the expression `f(pi)` is a function call. This mirrors the math notation where an $f$ is used when properties of a function are being emphasized (such as $f \\circ g$ for composition) and $f(x)$ is used when the values related to the function are being emphasized (such as saying \"the plot of the equation $y=f(x)$).\n\n\nDistinguishing these three related but different concepts (equations, function objects, and function calls) is important when modeling on the computer.\n\n\n### Cases\n\n\nThe definition of $s(x)$ above has two cases:\n\n\n\n$$\ns(x) = \\begin{cases} -1 & s < 0\\\\ 1 & s > 0. \\end{cases}\n$$\n\n\nWe learn to read this as: when $s$ is less than $0$, then the answer is $-1$. If $s$ is greater than $0$ the answer is $1.$ Often - but not in this example - there is an \"otherwise\" case to catch those values of $x$ that are not explicitly mentioned. As there is no such \"otherwise\" case here, we can see that this function has no definition when $x=0$. This function is often called the \"sign\" function and is also defined by $\\lvert x\\rvert/x$. (`Julia`'s `sign` function actually defines `sign(0)` to be `0`.)\n\n\nHow do we create conditional statements in `Julia`? Programming languages generally have \"if-then-else\" constructs to handle conditional evaluation. In `Julia`, the following code will handle the above condition:\n\n``` {.julia .cell-code}\nif x < 0\n -1\nelseif x > 0\n 1\nend\n```\n\n\nThe \"otherwise\" case would be caught with an `else` addition. So, for example, this would implement `Julia`'s definition of `sign` (which also assigns $0$ to $0$):\n\n``` {.julia .cell-code}\nif x < 0\n -1\nelseif x > 0\n 1\nelse\n 0\nend\n```\n\n\nThe conditions for the `if` statements are expressions that evaluate to either `true` or `false`, such as generated by the Boolean operators `<`, `<=`, `==`, `!-`, `>=`, and `>`.\n\n\nIf familiar with `if` conditions, they are natural to use. However, for simpler cases of \"if-else\" `Julia` provides the more convenient *ternary* operator: `cond ? if_true : if_false`. (The name comes from the fact that there are three arguments specified.) The ternary operator checks the condition and if true returns the first expression, whereas if the condition is false the second condition is returned. (Another useful control flow construct is [short-circuit](https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation) evaluation.)\n\n\nFor example, here is one way to define an absolute value function:\n\n::: {.cell execution_count=11}\n``` {.julia .cell-code}\nabs_val(x) = x >= 0 ? x : -x\n```\n\n::: {.cell-output .cell-output-display execution_count=10}\n```\nabs_val (generic function with 1 method)\n```\n:::\n:::\n\n\nThe condition is `x >= 0` - or is `x` non-negative? If so, the value `x` is used, otherwise `-x` is used.\n\n\nHere is a means to implement a function which takes the larger of `x` or `10`:\n\n::: {.cell execution_count=12}\n``` {.julia .cell-code}\nbigger_10(x) = x > 10 ? x : 10.0\n```\n\n::: {.cell-output .cell-output-display execution_count=11}\n```\nbigger_10 (generic function with 1 method)\n```\n:::\n:::\n\n\n(This could also utilize the `max` function: `f(x) = max(x, 10.0)`.)\n\n\nOr similarly, a function to represent a cell phone plan where the first $500$ minutes are $20$ dollars and every additional minute is $5$ cents:\n\n::: {.cell execution_count=13}\n``` {.julia .cell-code}\ncellplan(x) = x < 500 ? 20.0 : 20.0 + 0.05 * (x-500)\n```\n\n::: {.cell-output .cell-output-display execution_count=12}\n```\ncellplan (generic function with 1 method)\n```\n:::\n:::\n\n\n:::{.callout-warning}\n## Warning\nType stability. These last two definitions used `10.0` and `20.0` instead of the integers `10` and `20` for the answer. Why the extra typing? When `Julia` can predict the type of the output from the type of inputs, it can be more efficient. So when possible, we help out and ensure the output is always the same type.\n\n:::\n\n##### Example\n\n\nThe `ternary` operator can be used to define an explicit domain. For example, a falling body might have height given by $h(t) = 10 - 16t^2$. This model only applies for non-negative $t$ and non-negative $h$ values. So, in particular $0 \\leq t \\leq \\sqrt{10/16}$. To implement this function we might have:\n\n::: {.cell execution_count=14}\n``` {.julia .cell-code}\nh(t) = 0 <= t <= sqrt(10/16) ? 10.0 - 16t^2 : error(\"t is not in the domain\")\n```\n\n::: {.cell-output .cell-output-display execution_count=13}\n```\nh (generic function with 1 method)\n```\n:::\n:::\n\n\n#### Nesting ternary operators\n\n\nThe function `s(x)` isn't quite so easy to implement, as there isn't an \"otherwise\" case. We could use an `if` statement, but instead illustrate using a second, nested ternary operator:\n\n::: {.cell execution_count=15}\n``` {.julia .cell-code}\ns(x) = x < 0 ? -1 :\n x > 0 ? 1 : error(\"0 is not in the domain\")\n```\n\n::: {.cell-output .cell-output-display execution_count=14}\n```\ns (generic function with 1 method)\n```\n:::\n:::\n\n\nWith nested ternary operators, the advantage over the `if` condition is not always compelling, but for simple cases the ternary operator is quite useful.\n\n\n## Functions defined with the \"function\" keyword\n\n\nFor more complicated functions, say one with a few steps to compute, an alternate form for defining a function can be used:\n\n\n\n```{verbatim}\nfunction function_name(function_arguments)\n ...function_body...\nend\n```\n\n\nThe last value computed is returned unless the `function_body` contains an explicit `return` statement.\n\n\nFor example, the following is a more verbose way to define $sq(x) = x^2$:\n\n::: {.cell execution_count=16}\n``` {.julia .cell-code}\nfunction sq(x)\n return x^2\nend\n```\n\n::: {.cell-output .cell-output-display execution_count=15}\n```\nsq (generic function with 1 method)\n```\n:::\n:::\n\n\nThe line `return x^2`, could have just been `x^2` as it is the last (and) only line evaluated.\n\n\n:::{.callout-note}\n## Note\nThe `return` keyword is not a function, so is not called with parentheses. An emtpy `return` statement will return a value of `nothing`.\n\n:::\n\n##### Example\n\n\nImagine we have the following complicated function related to the trajectory of a [projectile](http://www.researchgate.net/publication/230963032_On_the_trajectories_of_projectiles_depicted_in_early_ballistic_woodcuts) with wind resistance:\n\n\n\n$$\n\tf(x) = \\left(\\frac{g}{k v_0\\cos(\\theta)} + \\tan(\\theta) \\right) x + \\frac{g}{k^2}\\ln\\left(1 - \\frac{k}{v_0\\cos(\\theta)} x \\right)\n$$\n\n\nHere $g$ is the gravitational constant $9.8$ and $v_0$, $\\theta$ and $k$ parameters, which we take to be $200$, $45$ degrees and $1/2$ respectively. With these values, the above function can be computed when $x=100$ with:\n\n::: {.cell execution_count=17}\n``` {.julia .cell-code}\nfunction trajectory(x)\n g, v0, theta, k = 9.8, 200, 45*pi/180, 1/2\n a = v0 * cos(theta)\n\n (g/(k*a) + tan(theta))* x + (g/k^2) * log(1 - k/a*x)\nend\n```\n\n::: {.cell-output .cell-output-display execution_count=16}\n```\ntrajectory (generic function with 1 method)\n```\n:::\n:::\n\n\n::: {.cell execution_count=18}\n``` {.julia .cell-code}\ntrajectory(100)\n```\n\n::: {.cell-output .cell-output-display execution_count=17}\n```\n96.7577179163216\n```\n:::\n:::\n\n\nBy using a multi-line function our work is much easier to look over for errors.\n\n\n##### Example: the secant method for finding a solution to $f(x) = 0$.\n\n\nThis next example, shows how using functions to collect a set of computations for simpler reuse can be very helpful.\n\n\nAn old method for finding a zero of an equation is the [secant method](https://en.wikipedia.org/wiki/Secant_method). We illustrate the method with the function $f(x) = x^2 - 2$. In an upcoming example we see how to create a function to evaluate the secant line between $(a,f(a))$ and $(b, f(b))$ at any point. In this example, we define a function to compute the $x$ coordinate of where the secant line crosses the $x$ axis. This can be defined as follows:\n\n::: {.cell execution_count=19}\n``` {.julia .cell-code}\nfunction secant_intersection(f, a, b)\n # solve 0 = f(b) + m * (x-b) where m is the slope of the secant line\n # x = b - f(b) / m\n m = (f(b) - f(a)) / (b - a)\n b - f(b) / m\nend\n```\n\n::: {.cell-output .cell-output-display execution_count=18}\n```\nsecant_intersection (generic function with 1 method)\n```\n:::\n:::\n\n\nWe utilize this as follows. Suppose we wish to solve $f(x) = 0$ and we have two \"rough\" guesses for the answer. In our example, we wish to solve $q(x) = x^2 - 2$ and our \"rough\" guesses are $1$ and $2$. Call these values $a$ and $b$. We *improve* our rough guesses by finding a value $c$ which is the intersection point of the secant line.\n\n::: {.cell execution_count=20}\n``` {.julia .cell-code}\nq(x) = x^2 - 2\nπ, π = 1, 2\nπ = secant_intersection(q, π, π)\n```\n\n::: {.cell-output .cell-output-display execution_count=19}\n```\n1.3333333333333335\n```\n:::\n:::\n\n\nIn our example, we see that in trying to find an answer to $f(x) = 0$ ( $\\sqrt{2}\\approx 1.414\\dots$) our value found from the intersection point is a better guess than either $a=1$ or $b=2$:\n\n::: {.cell execution_count=21}\n\n::: {.cell-output .cell-output-display execution_count=20}\n{}\n:::\n:::\n\n\nStill, `q(π)` is not really close to $0$:\n\n::: {.cell execution_count=22}\n``` {.julia .cell-code}\nq(π)\n```\n\n::: {.cell-output .cell-output-display execution_count=21}\n```\n-0.22222222222222188\n```\n:::\n:::\n\n\n*But* it is much closer than either $q(a)$ or $q(b)$, so it is an improvement. This suggests renaming $a$ and $b$ with the old $b$ and $c$ values and trying again we might do better still:\n\n::: {.cell hold='true' execution_count=23}\n``` {.julia .cell-code}\nπ, π = π, π\nπ = secant_intersection(q, π, π)\nq(π)\n```\n\n::: {.cell-output .cell-output-display execution_count=22}\n```\n-0.03999999999999959\n```\n:::\n:::\n\n\nYes, now the function value at this new $c$ is even closer to $0$. Trying a few more times we see we just get closer and closer. He we start again to see the progress\n\n::: {.cell hold='true' execution_count=24}\n``` {.julia .cell-code}\nπ,π = 1, 2\nfor step in 1:6\n π, π = π, secant_intersection(q, π, π)\n current = (c=π, qc=q(π))\n @show current\nend\n```\n\n::: {.cell-output .cell-output-stdout}\n```\ncurrent = (c = 1.3333333333333335, qc = -0.22222222222222188)\ncurrent = (c = 1.4000000000000001, qc = -0.03999999999999959)\ncurrent = (c = 1.4146341463414633, qc = 0.0011897679952408424)\ncurrent = (c = 1.41421143847487, qc = -6.007286838860537e-6)\ncurrent = (c = 1.4142135620573204, qc = -8.931455575122982e-10)\ncurrent = (c = 1.4142135623730954, qc = 8.881784197001252e-16)\n```\n:::\n:::\n\n\nNow our guess $c$ is basically the same as `sqrt(2)`. Repeating the above leads to only a slight improvement in the guess, as we are about as close as floating point values will allow.\n\n\nHere we see a visualization with all these points. As can be seen, it quickly converges at the scale of the visualization, as we can't see much closer than `1e-2`.\n\n::: {.cell hold='true' execution_count=25}\n\n::: {.cell-output .cell-output-display execution_count=24}\n{}\n:::\n:::\n\n\nIn most cases, this method can fairly quickly find a zero provided two good starting points are used.\n\n\n## Parameters, function context (scope), keyword arguments\n\n\nConsider two functions implementing the slope-intercept form and point-slope form of a line:\n\n\n\n$$\nf(x) = m \\cdot x + b, \\quad g(x) = y_0 + m \\cdot (x - x_0).\n$$\n\n\nBoth functions use the variable $x$, but there is no confusion, as we learn that this is just a dummy variable to be substituted for and so could have any name. Both also share a variable $m$ for a slope. Where does that value come from? In practice, there is a context that gives an answer. Despite the same name, there is no expectation that the slope will be the same for each function if the context is different. So when parameters are involved, a function involves a rule and a context to give specific values to the parameters. Euler had said initially that functions composed of \"the variable quantity and numbers or constant quantities.\" The term \"variable,\" we still use, but instead of \"constant quantities,\" we use the name \"parameters.\"\n\n\nSomething similar is also true with `Julia`. Consider the example of writing a function to model a linear equation with slope $m=2$ and $y$-intercept $3$. A typical means to do this would be to define constants, and then use the familiar formula:\n\n::: {.cell execution_count=26}\n``` {.julia .cell-code}\nm, b = 2, 3\nmxb(x) = m*x + b\n```\n\n::: {.cell-output .cell-output-display execution_count=25}\n```\nmxb (generic function with 1 method)\n```\n:::\n:::\n\n\nThis will work as expected. For example, $f(0)$ will be $b$ and $f(2)$ will be $7$:\n\n::: {.cell execution_count=27}\n``` {.julia .cell-code}\nmxb(0), mxb(2)\n```\n\n::: {.cell-output .cell-output-display execution_count=26}\n```\n(3, 7)\n```\n:::\n:::\n\n\nAll fine, but what if somewhere later the values for $m$ and $b$ were *redefined*, say with $m,b = 3,2$?\n\n\nNow what happens with $f(0)$? When $f$ was defined `b` was $3$, but now if we were to call `f`, `b` is $2$. Which value will we get? More generally, when `f` is being evaluated in what context does `Julia` look up the bindings for the variables it encounters? It could be that the values are assigned when the function is defined, or it could be that the values for the parameters are resolved when the function is called. If the latter, what context will be used?\n\n\nBefore discussing this, let's just see in this case:\n\n::: {.cell hold='true' execution_count=28}\n``` {.julia .cell-code}\nm, b = 3, 2\nmxb(0)\n```\n\n::: {.cell-output .cell-output-display execution_count=27}\n```\n2\n```\n:::\n:::\n\n\nSo the `b` is found from the currently stored value. This fact can be exploited. we can write template-like functions, such as `f(x)=m*x+b` and reuse them just by updating the parameters separately.\n\n\nHow `Julia` resolves what a variable refers to is described in detail in the manual page [Scope of Variables](https://docs.julialang.org/en/v1/manual/variables-and-scoping/). In this case, the function definition finds variables in the context of where the function was defined, the main workspace. As seen, this context can be modified after the function definition and prior to the function call. It is only when `b` is needed, that the context is consulted, so the most recent binding is retrieved. Contexts (more formally known as environments) allow the user to repurpose variable names without there being name collision. For example, we typically use `x` as a function argument, and different contexts allow this `x` to refer to different values.\n\n\nMostly this works as expected, but at times it can be complicated to reason about. In our example, definitions of the parameters can be forgotten, or the same variable name may have been used for some other purpose. The potential issue is with the parameters, the value for `x` is straightforward, as it is passed into the function. However, we can also pass the parameters, such as $m$ and $b$, as arguments. For parameters, we suggest using [keyword](https://docs.julialang.org/en/v1/manual/functions/#Keyword-Arguments) arguments. These allow the specification of parameters, but also give a default value. This can make usage explicit, yet still convenient. For example, here is an alternate way of defining a line with parameters `m` and `b`:\n\n::: {.cell execution_count=29}\n``` {.julia .cell-code}\nmxplusb(x; m=1, b=0) = m*x + b\n```\n\n::: {.cell-output .cell-output-display execution_count=28}\n```\nmxplusb (generic function with 1 method)\n```\n:::\n:::\n\n\nThe right-hand side is identical to before, but the left hand side is different. Arguments defined *after* a semicolon are keyword arguments. They are specified as `var=value` (or `var::Type=value` to restrict the type) where the value is used as the default, should a value not be specified when the function is called.\n\n\nCalling a function with keyword arguments can be identical to before:\n\n::: {.cell execution_count=30}\n``` {.julia .cell-code}\nmxplusb(0)\n```\n\n::: {.cell-output .cell-output-display execution_count=29}\n```\n0\n```\n:::\n:::\n\n\nDuring this call, values for `m` and `b` are found from how the function is called, not the main workspace. In this case, nothing is specified so the defaults of $m=1$ and $b=0$ are used. Whereas, this call will use the user-specified values for `m` and `b`:\n\n::: {.cell execution_count=31}\n``` {.julia .cell-code}\nmxplusb(0; m=3, b=2)\n```\n\n::: {.cell-output .cell-output-display execution_count=30}\n```\n2\n```\n:::\n:::\n\n\nKeywords are used to mark the parameters whose values are to be changed from the default. Though one can use *positional arguments* for parameters - and there are good reasons to do so - using keyword arguments is a good practice if performance isn't paramount, as their usage is more explicit yet the defaults mean that a minimum amount of typing needs to be done.\n\n\n##### Example\n\n\nIn the example for multi-line functions we hard coded many variables inside the body of the function. In practice it can be better to pass these in as parameters along the lines of:\n\n::: {.cell hold='true' execution_count=32}\n``` {.julia .cell-code}\nfunction trajectory(x; g = 9.8, v0 = 200, theta = 45*pi/180, k = 1/2)\n a = v0 * cos(theta)\n (g/(k*a) + tan(theta))* x + (g/k^2) * log(1 - k/a*x)\nend\ntrajectory(100)\n```\n\n::: {.cell-output .cell-output-display execution_count=31}\n```\n96.7577179163216\n```\n:::\n:::\n\n\n### The `f(x,p)` style for parameterization\n\n\nAn alternative to keyword arguments is to bundle the parameters into a container and pass them as a single argument to the function. The idiom in `Julia` is to use the *second* argument for parameters, or `f(x, p)` for the function argument specifications. This style is used in the very popular `SciML` suite of packages.\n\n\nFor example, here we use a *named tuple* to pass parameters to `f`:\n\n::: {.cell hold='true' execution_count=33}\n``` {.julia .cell-code}\nfunction trajectory(x ,p)\n g, v0, theta, k = p.g, p.v0, p.theta, p.k # unpack parameters\n\n a = v0 * cos(theta)\n (g/(k*a) + tan(theta))* x + (g/k^2) * log(1 - k/a*x)\nend\n\np = (g=9.8, v0=200, theta = 45*pi/180, k=1/2)\ntrajectory(100, p)\n```\n\n::: {.cell-output .cell-output-display execution_count=32}\n```\n96.7577179163216\n```\n:::\n:::\n\n\nThe style isn't so different from using keyword arguments, save the extra step of unpacking the parameters. The *big* advantage is consistency β the function is always called in an identical manner regardless of the number of parameters (or variables).\n\n\n## Multiple dispatch\n\n\nThe concept of a function is of much more general use than its restriction to mathematical functions of single real variable. A natural application comes from describing basic properties of geometric objects. The following function definitions likely will cause no great concern when skimmed over:\n\n::: {.cell hold='true' execution_count=34}\n``` {.julia .cell-code}\nArea(w, h) = w * h\t\t # of a rectangle\nVolume(r, h) = pi * r^2 * h\t # of a cylinder\nSurfaceArea(r, h) = pi * r * (r + sqrt(h^2 + r^2)) # of a right circular cone, including the base\n```\n\n::: {.cell-output .cell-output-display execution_count=33}\n```\nSurfaceArea (generic function with 1 method)\n```\n:::\n:::\n\n\nThe right-hand sides may or may not be familiar, but it should be reasonable to believe that if push came to shove, the formulas could be looked up. However, the left-hand sides are subtly different - they have two arguments, not one. In `Julia` it is trivial to define functions with multiple arguments - we just did.\n\n\nEarlier we saw the `log` function can use a second argument to express the base. This function is basically defined by `log(b,x)=log(x)/log(b)`. The `log(x)` value is the natural log, and this definition just uses the change-of-base formula for logarithms.\n\n\nBut not so fast, on the left side is a function with two arguments and on the right side the functions have one argument - yet they share the same name. How does `Julia` know which to use? `Julia` uses the number, order, and *type* of the positional arguments passed to a function to determine which function definition to use. This is technically known as [multiple dispatch](http://en.wikipedia.org/wiki/Multiple_dispatch) or **polymorphism**. As a feature of the language, it can be used to greatly simplify the number of functions the user must learn. The basic idea is that many functions are \"generic\" in that they have methods which will work differently in different scenarios.\n\n\n:::{.callout-warning}\n## Warning\nMultiple dispatch is very common in mathematics. For example, we learn different ways to add: integers (fingers, carrying), real numbers (align the decimal points), rational numbers (common denominators), complex numbers (add components), vectors (add components), polynomials (combine like monomials), ... yet we just use the same `+` notation for each operation. The concepts are related, the details different.\n\n:::\n\n`Julia` is similarly structured. `Julia` terminology would be to call the operation \"`+`\" a *generic function* and the different implementations *methods* of \"`+`\". This allows the user to just need to know a smaller collection of generic concepts yet still have the power of detail-specific implementations. To see how many different methods are defined in the base `Julia` language for the `+` operator, we can use the command `methods(+)`. As there are so many ($\\approx 200$) and that number is growing, we illustrate how many different logarithm methods are implemented for \"numbers:\"\n\n::: {.cell execution_count=35}\n``` {.julia .cell-code}\nmethods(log, (Number,))\n```\n\n::: {.cell-output .cell-output-display execution_count=34}\n```{=html}\n# 11 methods for generic function log: