Delayed Evaluation
   HOME

TheInfoList



OR:

In computer programming, a thunk is a
subroutine In computer programming, a function or subroutine is a sequence of program instructions that performs a specific task, packaged as a unit. This unit can then be used in programs wherever that particular task should be performed. Functions may ...
used to inject a calculation into another subroutine. Thunks are primarily used to delay a calculation until its result is needed, or to insert operations at the beginning or end of the other subroutine. They have many other applications in compiler code generation and modular programming. The term originated as a whimsical irregular form of the verb ''think''. It refers to the original use of thunks in
ALGOL 60 ALGOL 60 (short for ''Algorithmic Language 1960'') is a member of the ALGOL family of computer programming languages. It followed on from ALGOL 58 which had introduced code blocks and the begin and end pairs for delimiting them, representing a k ...
compilers, which required special analysis (thought) to determine what type of routine to generate.


Background

The early years of compiler research saw broad experimentation with different evaluation strategies. A key question was how to compile a subroutine call if the arguments can be arbitrary mathematical expressions rather than constants. One approach, known as " call by value", calculates all of the arguments before the call and then passes the resulting values to the subroutine. In the rival " call by name" approach, the subroutine receives the unevaluated argument expression and must evaluate it. A simple implementation of "call by name" might substitute the code of an argument expression for each appearance of the corresponding parameter in the subroutine, but this can produce multiple versions of the subroutine and multiple copies of the expression code. As an improvement, the compiler can generate a helper subroutine, called a ''thunk'', that calculates the value of the argument. The address and environment of this helper subroutine are then passed to the original subroutine in place of the original argument, where it can be called as many times as needed. Peter Ingerman first described thunks in reference to the ALGOL 60 programming language, which supports call-by-name evaluation.


Applications


Functional programming

Although the software industry largely standardized on call-by-value and
call-by-reference In a programming language, an evaluation strategy is a set of rules for evaluating expressions. The term is often used to refer to the more specific notion of a ''parameter-passing strategy'' that defines the kind of value that is passed to the f ...
evaluation, active study of call-by-name continued in the functional programming community. This research produced a series of lazy evaluation programming languages in which some variant of call-by-name is the standard evaluation strategy. Compilers for these languages, such as the Glasgow Haskell Compiler, have relied heavily on thunks, with the added feature that the thunks save their initial result so that they can avoid recalculating it; this is known as
memoization In computing, memoization or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again. Memoization ...
or
call-by-need In a programming language, an evaluation strategy is a set of rules for evaluating expressions. The term is often used to refer to the more specific notion of a ''parameter-passing strategy'' that defines the kind of value that is passed to the f ...
. Functional programming languages have also allowed programmers to explicitly generate thunks. This is done in source code by wrapping an argument expression in an
anonymous function In computer programming, an anonymous function (function literal, lambda abstraction, lambda function, lambda expression or block) is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to ...
that has no parameters of its own. This prevents the expression from being evaluated until a receiving function calls the anonymous function, thereby achieving the same effect as call-by-name. The adoption of anonymous functions into other programming languages has made this capability widely available. The following is a simple demonstration in JavaScript (ES6): // 'hypot' is a binary function const hypot = (x, y) => Math.sqrt(x * x + y * y); // 'thunk' is a function that takes no arguments and, when invoked, performs a potentially expensive // operation (computing a square root, in this example) and/or causes some side-effect to occur const thunk = () => hypot(3, 4); // the thunk can then be passed around without being evaluated... doSomethingWithThunk(thunk); // ...or evaluated thunk(); //

5


Object-oriented programming

Thunks are useful in object-oriented programming platforms that allow a
class Class or The Class may refer to: Common uses not otherwise categorized * Class (biology), a taxonomic rank * Class (knowledge representation), a collection of individuals or objects * Class (philosophy), an analytical concept used differentl ...
to inherit multiple interfaces, leading to situations where the same method might be called via any of several interfaces. The following code illustrates such a situation in C++. class A ; class B ; class C : public A, public B ; int use(B *b) int main() In this example, the code generated for each of the classes A, B and C will include a dispatch table that can be used to call on an object of that type, via a reference that has the same type. Class C will have an additional dispatch table, used to call on an object of type C via a reference of type B. The expression will use B's own dispatch table or the additional C table, depending on the type of object b refers to. If it refers to an object of type C, the compiler must ensure that C's implementation receives an instance address for the entire C object, rather than the inherited B part of that object. As a direct approach to this pointer adjustment problem, the compiler can include an integer offset in each dispatch table entry. This offset is the difference between the reference's address and the address required by the method implementation. The code generated for each call through these dispatch tables must then retrieve the offset and use it to adjust the instance address before calling the method. The solution just described has problems similar to the naïve implementation of call-by-name described earlier: the compiler generates several copies of code to calculate an argument (the instance address), while also increasing the dispatch table sizes to hold the offsets. As an alternative, the compiler can generate an ''adjustor thunk'' along with C's implementation of that adjusts the instance address by the required amount and then calls the method. The thunk can appear in C's dispatch table for B, thereby eliminating the need for callers to adjust the address themselves.


Numerical calculations requiring evaluations at multiple points

Routines for computations such as integration need to calculate an expression at multiple points. Call by name was used for this purpose in languages that didn't support closures or procedure parameters.


Interoperability

Thunks have been widely used to provide interoperability between software modules whose routines cannot call each other directly. This may occur because the routines have different calling conventions, run in different CPU modes or
address space In computing, an address space defines a range of discrete addresses, each of which may correspond to a network host, peripheral device, disk sector, a memory cell or other logical or physical entity. For software programs to save and retrieve st ...
s, or at least one runs in a virtual machine. A compiler (or other tool) can solve this problem by generating a thunk that automates the additional steps needed to call the target routine, whether that is transforming arguments, copying them to another location, or switching the CPU mode. A successful thunk minimizes the extra work the caller must do compared to a normal call. Much of the literature on interoperability thunks relates to various
Wintel Wintel (portmanteau of Windows and Intel) is the partnership of Microsoft Windows and Intel producing personal computers using Intel x86-compatible processors running Microsoft Windows. Background By the early 1980s, the chaos and incompatibil ...
platforms, including MS-DOS, OS/2, Windows and .NET, and to the transition from
16-bit 16-bit microcomputers are microcomputers that use 16-bit microprocessors. A 16-bit register can store 216 different values. The range of integer values that can be stored in 16 bits depends on the integer representation used. With the two mos ...
to
32-bit In computer architecture, 32-bit computing refers to computer systems with a processor, memory, and other major system components that operate on data in 32-bit units. Compared to smaller bit widths, 32-bit computers can perform large calculation ...
memory addressing. As customers have migrated from one platform to another, thunks have been essential to support
legacy software In computing, a legacy system is an old method, technology, computer system, or application program, "of, relating to, or being a previous or outdated computer system", yet still in use. Often referencing a system as "legacy" means that it paved ...
written for the older platforms. The transition from 32-bit to 64-bit code on x86 also uses a form of thunking (WoW64). However, because the x86-64 address space is larger than the one available to 32-bit code, the old "generic thunk" mechanism could not be used to call 64-bit code from 32-bit code. The only case of 32-bit code calling 64-bit code is in the WoW64's thunking of Windows APIs to 32-bit.


Overlays and dynamic linking

On systems that lack automatic virtual memory hardware, thunks can implement a limited form of virtual memory known as overlays. With overlays, a developer divides a program's code into segments that can be loaded and unloaded independently, and identifies the entry points into each segment. A segment that calls into another segment must do so indirectly via a branch table. When a segment is in memory, its branch table entries jump into the segment. When a segment is unloaded, its entries are replaced with "reload thunks" that can reload it on demand. Similarly, systems that dynamically link modules of a program together at run-time can use thunks to connect the modules. Each module can call the others through a table of thunks that the linker fills in when it loads the module. This way the modules can interact without prior knowledge of where they are located in memory.


See also


Thunk technologies

* DOS Protected Mode Interface (DPMI) * DOS Protected Mode Services (DPMS) *
J/Direct J/Direct was a technology included in some versions of Microsoft Java Virtual Machine, which allowed direct calls into the Windows API. J/Direct was specific of Microsoft's Virtual Machine, in replacement of the standard Java Native Interface (JNI) ...
*
Microsoft Layer for Unicode The Microsoft Layer for Unicode (MSLU) is a software library for legacy versions of Windows, simplifying the creation of Unicode-aware programs on Windows 9x (Windows 95, Windows 98, and Windows Me). It is also known as UnicoWS (Unicode for Windows ...
*
Platform Invocation Services Platform Invocation Services, commonly referred to as P/Invoke, is a feature of Common Language Infrastructure implementations, like Microsoft's Common Language Runtime, that enables managed code to call native code. Managed code, such as C# or ...
* Win32s * Windows on Windows *
WoW64 In computing on Microsoft platforms, WoW64 (Windows 32-bit on Windows 64-bit) is a subsystem of the Windows operating system capable of running 32-bit applications on 64-bit Windows. It is included in all 64-bit versions of Windows—including ...
* libffi


Related concepts

*
Anonymous function In computer programming, an anonymous function (function literal, lambda abstraction, lambda function, lambda expression or block) is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to ...
*
Futures and promises In computer science, future, promise, delay, and deferred refer to constructs used for synchronizing program execution in some concurrent programming languages. They describe an object that acts as a proxy for a result that is initially unknown ...
* Remote procedure call * Shim (computing) *
Trampoline (computing) In computer programming, the word trampoline has a number of meanings, and is generally associated with jump instructions (i.e. moving to different code paths). Low-level programming Trampolines (sometimes referred to as indirect jump vectors) ...
*
Reducible expression In mathematics, computer science, and logic, rewriting covers a wide range of methods of replacing subterms of a formula with other terms. Such methods may be achieved by rewriting systems (also known as rewrite systems, rewrite engines, or reduc ...


Notes


References

{{reflist, refs= {{cite book , author-last=Levine , author-first=John R. , author-link=John R. Levine , title=Linkers and Loaders , date=2000 , orig-year=October 1999 , edition=1 , publisher=
Morgan Kaufmann Morgan Kaufmann Publishers is a Burlington, Massachusetts (San Francisco, California until 2008) based publisher specializing in computer science and engineering content. Since 1984, Morgan Kaufmann has published content on information technology ...
, series=The Morgan Kaufmann Series in Software Engineering and Programming , location=San Francisco, USA , isbn=1-55860-496-0 , oclc=42413382 , url=https://www.iecc.com/linker/ , access-date=2020-01-12 , url-status=live , archive-url=https://archive.today/20121205032107/http://www.iecc.com/linker/ , archive-date=2012-12-05 Code

ftp://ftp.iecc.com/pub/linker/] Errata
https://archive.today/20200114224817/https://linker.iecc.com/ 2020-01-14 -->
/ref> Computing terminology Functional programming