What is a 'thunk'?
A thunk
usually refers to a small piece of code that is called as a function, does some small thing, and then JUMP
s to another location (usually a function) instead of returning to its caller. Assuming the JUMP target is a normal function, when it returns, it will return to the thunk's caller.
Thunks can be used to implement lots of useful things efficiently
protocol translation -- when calling from code that uses one calling convention to code that uses a different calling convention, a
thunk
can be used to translate the arguments appropriately. This only works if the return conventions are compatible, but that is often the casevirtual function handling -- when calling a virtual function of a multiply-inherited base class in C++, there needs to be a fix-up of the
this
pointer to get it to point to the right place. Athunk
can do this.dynamic closures -- when you build a dynamic closure, the closure function needs to be able to get at the context where it was created. A small
thunk
can be built (usually on the stack) which sets up the context info in some register(s) and then jumps to a static piece of code that implements the closure's function. The thunk here is effectively supplying one or more hidden extra arguments to the function that are not provided by the call site.
What is a 'thunk', as used in Scheme or in general?
It is really simple. When you have some computation, like adding 3 to 5, in your program, then creating a thunk of it means not to calculate it directly, but instead create a function with zero arguments that will calculate it when the actual value is needed.
(let ((foo (+ 3 5))) ; the calculation is performed directly, foo is 8
;; some other things
(display foo)) ; foo is evaluated to 8 and printed
(let ((foo (lambda () (+ 3 5)))) ; the calculation is delayed, foo is a
; function that will perform it when needed
;; some other things
(display (foo))) ; foo is evaluated as a function, returns 8 which is printed
In the second case, foo
would be called a thunk.
Lazy languages blur the line between binding a variable to a value and creating a function to return that value, so that writing something like the first form above is actually treated like the second, under the hood.
In simple terms, what's the difference between a thunk and a Higher Order Function?
I understand that both are functions that return functions
Your understanding is slightly incorrect
- Thunks can return a value of any type – not just a Function type
- Higher-order functions can return a value of any type – not just a Function type
My experience so far with thunks have been using them to return functions as opposed to just action objects so that I can work with async requests in Redux.
Thunks (and higher-order functions, for that matter) are not intrinsically related to any particular library (React, Redux) or any particular control flow (sync, async). A thunk is just a nullary function – they have a variety of common uses cases, but most commonly are used to delay the evaluation of a specific computation.
A closure is an implementation of a High Order Function (HOF) in order to create a new scope for private variables...right? Other examples of HOFs include map, reduce and filter.
A closure is not necessarily an implementation of a higher-order function. The function
keyword (and =>
arrow function syntax) does create a closure tho which does have a new (lexical) scope, yes.
Is there any thing else that explicitly defines a difference between the two?
Yes. How they are the same:
- they are both functions
- they can both return values of any type
How they are different:
- thunks are nullary functions (they accept no arguments)
- higher-order functions accept a function as an argument and/or return a function
Perhaps the most critical distinction:
- A thunk can only be considered a higher-order function if it returns a function.
Lazy loading vs thunking?
Using the following definitions:
Lazy Loading
Lazy loading is a design pattern commonly used in computer programming to defer initialization of an object until the point at which it is needed.
Thunk
A thunk is an unevaluated expression, often represented as an object on the heap with bound variables and a code pointer (a closure). Lazy evaluation replaces thunks by more evaluated forms (pure values for simple types but otherwise an evaluated outer structure, and possibly unevaluated inner contents, i.e., weak head normal form). That replacement is done destructively, i.e., a side-effect of evaluation.
You might say that "lazy loading" is a means of deferring evaluation in an object oriented language until the first time an object is demanded. When the value is required, the entire object is evaluated.
A thunk is similar in that it is a means of deferring evaluation of any expression in a functional programming language. When demanded, the thunk is replaced with its evaluated contents, which may be another thunk. In languages like Haskell, all values are (notionally) represented by thunks, making every evaluation step potentially lazy.
They are broadly similar mechanisms for achieving the same end goal: non-strict evaluation.
What is a 'thunk'? (in the context of re-entrant sort functions, eg: qsort_r)
The name seems to be from the original proposed implementation by Diomidis Spinellis
The implementation shows that it is just used as an opaque data block, passed through qsort_r
and back to your compare function.
It seems to somewhat match the 3rd concept in this answer.
a mapping of machine data from one system-specific form to another, usually for compatibility reasons
But really, it just seems like a misleading name. I usually think of thunks as containing blocks of code. In this case it is just a container for context.
Xcode Instruments, Leaks. Meaning of thunk for @escaping @callee_guaranted() - ()
A thunk generally is a box around a delayed function call (possibly adding some context, and possibly requiring additional context to complete). In Swift, thunks are generally used to help manage memory or calling conventions around a closure. As a rule, you can ignore the thunk; it's a bit of an implementation detail.
What this is really telling you is that you're leaking an SKNode somewhere, and that SKNode was created in a block dispatched to the main queue (probably using DispatchQueue.main.async
). It is highly unlikely that this call stack actually has anything to do with the leak. It's just telling you where the leaked object was created.
Difference between a thunk and a closure
"ruleRunner is a thunk, or a function that returns a function."
No, that's rubbish. A function that returns a function is known as a higher-order function. The returned function is often a closure.
I thought a thunk was "a function that contains all of the context (state, functions, etc) it will need in order to carry out some sort of logic in the future."
Yes, that sounds reasonable. This is similar to a closure, however a closure usually takes some further arguments while a thunk doesn't - it only needs to be started to execute.
Related Topics
How Does Modulus and Rand() Work
Error Lnk1104: Cannot Open File 'Debug\Myprojectlib.Lib'
How to Programmatically Gain Root Privileges
How to Define a Template Function Within a Template Class Outside of the Class Definition
Comparison of Double, Long Double, Float and Float128
Why Is the Sprite Not Rendering in Opengl
How to Separate C++ Main Function and Classes from Objective-C And/Or C Routines at Compile and Link
How to Know If a Pointer Points to the Heap or the Stack
A How to Create a Matrix in C++
Number of Combinations (N Choose R) in C++
Measure Execution Time in C++ Openmp Code
How to Use Visual Studio Code to Compile Multi-Cpp File
Order of Evaluation of Assignment Statement in C++
Multithreaded Rendering on Opengl
How to Recover View Space Position Given View Space Depth Value and Ndc Xy
Are Destructors Called After a Throw in C++
How to Compile a Visual Studio Project from the Command-Line