Function (computer programming): Difference between revisions

Content deleted Content added
Terminology: PL/I uses procedure for both
m Reverted edit by 192.145.175.229 (talk) to last version by Chatul
 
(6 intermediate revisions by 5 users not shown)
Line 28:
Subroutines were implemented in [[Konrad Zuse]]'s [[Z4 (computer)|Z4]] in 1945.
 
In 1945, [[Alan M. Turing]] used the terms "bury" and "unbury" as a means of calling and returning from subroutines.<ref name="Turing_1945">{{citation |author-first=Alan Mathison |author-last=Turing |author-link=Alan Mathison Turing |title=Proposals for Development in the Mathematics Division of an Automatic Computing Engine (ACE) |date=1946-03-19 |orig-year=1945}} (NB. Presented on 1946-03-19 before the Executive Committee of the National Physical Laboratory (Great Britain).)</ref><ref name="Carpenter_1977">{{cite journal |title=The other Turing machine |author-last1=Carpenter |author-first1=Brian Edward |author-link1=Brian Carpenter (Internet engineer) |author-last2=Doran |author-first2=Robert William |author-link2=Robert William Doran |date=1977-01-01 |orig-year=October 1975 |doi=10.1093/comjnl/20.3.269 |volume=20 |issue=3 |journal=[[The Computer Journal]] |pages=269–279|doi-access=free }} (11 pages)</ref>
 
In January 1947 John Mauchly presented general notes at 'A Symposium of Large Scale Digital Calculating Machinery'
Line 140:
 
====Delayed stacking {{anchor|Leaf procedure}}{{anchor|Leaf function}}====
 
One disadvantage of the call stack mechanism is the increased cost of a procedure call and its matching return.{{ clarify | date = November 2015 | reason = increased relative to what?}} The extra cost includes incrementing and decrementing the stack pointer (and, in some architectures, checking for [[stack overflow]]), and accessing the local variables and parameters by frame-relative addresses, instead of absolute addresses. The cost may be realized in increased execution time, or increased processor complexity, or both.
 
This overhead is most obvious and objectionable in ''leaf procedures'' or ''[[leaf functionsfunction]]s'', which return without making any procedure calls themselves.<ref>{{cite web|url=http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka13785.html |title=ARM Information Center |publisher=Infocenter.arm.com |access-date=2013-09-29}}</ref><ref>{{cite web |title=x64 stack usage |url=https://docs.microsoft.com/en-us/cpp/build/stack-usage |website=Microsoft Docs |publisher=Microsoft |access-date=5 August 2019}}</ref><ref>{{cite web|url=http://msdn.microsoft.com/en-us/library/67fa79wz%28v=VS.90%29.aspx |title=Function Types |publisher=Msdn.microsoft.com |access-date=2013-09-29}}</ref> To reduce that overhead, many modern compilers try to delay the use of a call stack until it is really needed.{{Citation needed|date=June 2011}} For example, the call of a procedure ''P'' may store the return address and parameters of the called procedure in certain processor registers, and transfer control to the procedure's body by a simple jump. If the procedure ''P'' returns without making any other call, the call stack is not used at all. If ''P'' needs to call another procedure ''Q'', it will then use the call stack to save the contents of any registers (such as the return address) that will be needed after ''Q'' returns.<!-- Mention caller-saves vs. callee-saves?-->
<!---If the procedure or function itself uses stack handling commands, outside of the prologue and epilogue, e.g. to store intermediate calculation values, the programmer needs to keep track of the number of 'push' and 'pop' instructions so as not to corrupt the original return address.-->
<!--Major cleanup needed from this point on-->
 
== Features ==
{{uncited section|date=August 2025}}
 
In general, a callable unit is a list of instructions that, starting at the first instruction, executes sequentially except as directed via its internal logic. It can be invoked (called) many times during the [[Execution (computing)|execution]] of a program. Execution continues at the next instruction after the call instruction when it [[Return statement|returns]] control.
Line 219 ⟶ 221:
In many contexts, a callable may have [[side-effect (computer science)|side effect]] behavior such as modifying passed or global data, reading from or writing to a [[peripheral device]], accessing a [[computer file|file]], halting the program or the machine, or temporarily pausing program execution.
 
Side effects are considered undesirebleundesirable by [[Robert C. Martin]], who is known for promoting design principles. Martin argues that side effects can result in [[sequential coupling|temporal coupling]] or order dependencies.<ref name="clean code">{{cite book |last1=Martin |first1=Robert C. |title=Clean Code: A Handbook of Agile Software Craftsmanship |date=Aug 1, 2008 |publisher=[[Pearson PLC|Pearson]] |isbn=9780132350884 |edition=1 |url=https://www.oreilly.com/library/view/clean-code-a/9780136083238/ |access-date=19 May 2024}}</ref>
 
In strictly [[functional programming]] languages such as [[Haskell (programming language)|Haskell]], a function can have no [[Side effect (computer science)|side effects]], which means it cannot change the state of the program. Functions always return the same result for the same input. Such languages typically only support functions that return a value, since there is no value in a function that has neither return value nor side effect.
Line 231 ⟶ 233:
=== Nested call {{endash}} recursion ===
 
If supported by the language, a callable may call itself, causing its execution to suspend while another ''nested'' execution of the same callable executes. [[Recursion (computer science)|Recursion]] is a useful means to simplify some complex algorithms and break down complex problems. Recursive languages provide a new copy of local variables on each call. If the programmer desires the recursive callable to use the same variables instead of using locals, they typically declare them in a shared context such static or global.
 
Languages going back to [[ALGOL]], [[PL/I]] and [[C (programming language)|C]] and modern languages, almost invariably use a call stack, usually supported by the instruction sets to provide an activation record for each call. That way, a nested call can modify its local variables without affecting any of the suspended calls variables.
 
Recursion allows direct implementation of functionality defined by [[mathematical induction]] and recursive [[divide and conquer algorithm]]s. Here is an example of a recursive function in C/C++ to find [[Fibonacci]] sequence|Fibonacci numbers]]:
 
<syntaxhighlight lang="c">
Line 253 ⟶ 255:
 
Some languages, e.g., [[Ada (programming language)|Ada]], [[Pascal (programming language)|Pascal]], [[PL/I]], [[Python (programming language)|Python]], support declaring and defining a function inside, e.g., a function body, such that the name of the inner is only visible within the body of the outer.
 
<!-- Would an example be helpful here? -->
A simple example in Pascal:<syntaxhighlight lang="pascal">function E(x: real): real;
function F(y: real): real;
begin
F := x + y
end;
begin
E := F(3) + F(4)
end;</syntaxhighlight>The function <code>F</code> is nested within <code>E</code>. Note that <code>E</code>'s parameter <code>x</code> is also visible in <code>F</code> (as <code>F</code> is a part of <code>E</code>) while both <code>x</code> and <code>y</code> are invisible outside <code>E</code> and <code>F</code> respectively.
 
=== Reentrancy ===
Line 584 ⟶ 594:
* [[Functional programming]]
* [[Fused operation]]
* [[Generator (computer programming)]]
* [[Intrinsic function]]
* [[Lambda function (computer programming)]], a function that is not bound to an identifier