# Solidity Function Type Examples – A Simple Illustrated Guide

In this article, we’ll continue our story on function types, but this time, we’ll go through several illustrative examples and learn how they work and breathe in practice.

This way, by complementing what we already know about function types, we’ll get a broader perspective and better understanding.

It’s part of our long-standing tradition to make this (and other) articles a faithful companion, or a supplement to the official Solidity documentation, starting with these docs for this article’s topics.

• In the next section, we’ll just lay out the source code for easier reference and testing purposes.
• In the subsequent section, we’ll analyze what the code does and comment on the points of interest.

## Smart Contract – Internal Function Type

```// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

library ArrayUtils {
// internal functions can be used in internal library functions because
// they will be part of the same code context
function map(uint[] memory self, function (uint) pure returns (uint) f)
internal
pure
returns (uint[] memory r)
{
r = new uint[](self.length);
for (uint i = 0; i < self.length; i++) {
r[i] = f(self[i]);
}
}

function reduce(
uint[] memory self,
function (uint, uint) pure returns (uint) f
)
internal
pure
returns (uint r)
{
r = self[0];
for (uint i = 1; i < self.length; i++) {
r = f(r, self[i]);
}
}

function range(uint length) internal pure returns (uint[] memory r) {
r = new uint[](length);
for (uint i = 0; i < r.length; i++) {
r[i] = i;
}
}
}

contract Pyramid {
using ArrayUtils for *;

function pyramid(uint l) public pure returns (uint) {
return ArrayUtils.range(l).map(square).reduce(sum);
}

function square(uint x) internal pure returns (uint) {
return x * x;
}

function sum(uint x, uint y) internal pure returns (uint) {
return x + y;
}
}
```

## Smart contract – Internal Function Type – Code Breakdown and Analysis

```// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
```

Defines the library containing our generic functions `map(...)` and `reduce(...)`, which receive the function type object defining their actual behavior.

Functions `map()` and `reduce()` are well-known in the programming world, and especially the parallel programming world; `map()` is used to apply the same operation to a range of elements, and `reduce()` is used to collect or aggregate the results after `map()` to a single result.

```library ArrayUtils {
// internal functions can be used in internal library functions because
// they will be part of the same code context
```

The `map()` function uses a special feature of library functions: when the function can be seen as a method of an object, it’s idiomatic to call the first parameter `self`

Function `map()` will accept function type `f` as the element that determines the `map()` behavior.

```    function map(uint[] memory self, function (uint) pure returns (uint) f)
internal
pure
returns (uint[] memory r)
{
```

Defines `r` as the resulting array of type `uint`, iterates over the original `self` array, and applies the function `f` to each element.

```        r = new uint[](self.length);
for (uint i = 0; i < self.length; i++) {
r[i] = f(self[i]);
}
}
```

Iterates over the resulting array contained in `self`, successively applies the `f` function (type) to each element of the array, and aggregates the result to the `r` variable.

We should note that the `r` variable contains a (starting) value from each previous iteration and carries it to the next iteration to be used in the `f` function.

```    function reduce(
uint[] memory self,
function (uint, uint) pure returns (uint) f
)
internal
pure
returns (uint r)
{
r = self[0];
for (uint i = 1; i < self.length; i++) {
r = f(r, self[i]);
}
}
```

The `range()` function is a simple function that initializes the array elements to their index values.

```    function range(uint length) internal pure returns (uint[] memory r) {
r = new uint[](length);
for (uint i = 0; i < r.length; i++) {
r[i] = i;
}
}
}
```

Creates a new contract for calculating the sum of squares for a range of numbers `l`, along with the supporting, behavior-defining functions `square()` and `sum()`.

```contract Pyramid {
using ArrayUtils for *;
```

Uses the `ArrayUtils` library, produces an array of (index-initialized) values from the `ArrayUtils.range(l)` function, passes it to the `map()` function, and applies the `square()` function, yielding a new array of squares.

Then it passes the array of squares to the `reduce()` function and applies the sum function.

```    function pyramid(uint l) public pure returns (uint) {
return ArrayUtils.range(l).map(square).reduce(sum);
}

function square(uint x) internal pure returns (uint) {
return x * x;
}

function sum(uint x, uint y) internal pure returns (uint) {
return x + y;
}
}
```

We might ask ourselves, why didn’t we just use the `squares()` and `sum()` functions?

The answer lies in the design decision to have a generic, scalable arrangement of our code, where we can just plug in, add, and maintain a list of functions and apply them to our input data.

We can think of it in a more practical way: when we want a smartphone (a generic function) to have new functionality, we’d add it by installing a specific application; we most certainly wouldn’t want to buy a new phone every time we want to do something new with a phone.

## Running the Example: Internal Function Type

This section contains additional information for running the contract. We should expect that our example accounts may change with each refresh/reload of Remix.

To run the example, we will just deploy the `Pyramid` contract.

### Contract Test Scenario: Internal Function Type

1. Call the `pyramid(5)` function.
2. Get the result of 02 + 12 + 22 + 32 + 42 = 0 + 1 + 4 + 9 + 16 = 30.

## Smart Contract – External Function Type

```// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

contract Oracle {
struct Request {
bytes data;
function(uint) external callback;
}

Request[] private requests;
event NewRequest(uint);

function query(bytes memory data, function(uint) external callback) public {
requests.push(Request(data, callback));
emit NewRequest(requests.length - 1);
}

function reply(uint requestID, uint response) public {
// Here goes the check that the reply comes from a trusted source
requests[requestID].callback(response);
}
}

contract OracleUser {
Oracle constant private ORACLE_CONST = Oracle(address(0x00000000219ab540356cBB839Cbe05303d7705Fa)); // known contract
uint public exchangeRate;

ORACLE_CONST.query("USD", this.oracleResponse);
}

function oracleResponse(uint response) public {
require(
"Only oracle can call this."
);
exchangeRate = response;
}
}
```

## Smart contract – External Function Type – Code Breakdown and Analysis

```// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
```

💡 Info: “Blockchain oracles are entities that connect blockchains to external systems, thereby enabling smart contracts to execute based upon inputs and outputs from the real world.”

Creates an `Oracle` smart contract that ties together the associated external function type with the exchange symbol, and uses it in the later callback.

`contract Oracle {`

Defines an elementary request as a user-defined type `Request`.

```    struct Request {
bytes data;
```

The function type is very simple. It is named `callback` and stored with the variable data (exchange symbol).

```        function(uint) external callback;
}
```

An array of requests is declared and an event is defined.

```    Request[] public requests;
event NewRequest(uint);
```

The function query stores the exchange symbol (`Request.data`) with the callback function type (`Request.callback;` check the previous article on details regarding the remote function call).

Each request is pushed to the array (indices start with 0 and increment by 1 with each push operation).

```    function query(bytes memory data, function(uint) external callback) public {
requests.push(Request(data, callback));
```

Emits the signal showing the index location of a request.

```        emit NewRequest(requests.length - 1);
}
```

Calls the remote (`OracleUser`) function and sets the remote contract’s exchange rate. The `requestID` was in an emitted signal. We’ll use it later in our test scenario.

```    function reply(uint requestID, uint response) public {
// Here goes the check that the reply comes from a trusted source
requests[requestID].callback(response);
}
}
```

Creates the `OracleUser` contract.

`contract OracleUser {`

Declares the `Oracle` contract address; we have to update it (underlined) in the `OracleUser` source code before deploying `OracleUser` contract.

`    Oracle constant private ORACLE_CONST = Oracle(address(0x00000000219ab540356cBB839Cbe05303d7705Fa)); // known contract`

Here we’ll use a slight modification of the official example and declare the `exchangeRate` variable as public to show that the exchange rate is appropriately set.

`    uint public exchangeRate;`

Calls a remote contract’s, i.e. Oracle’s `query()` function with an exchange symbol and a callback function as arguments.

```    function buySomething() public {
ORACLE_CONST.query("USD", this.oracleResponse);
}
```

Sets the exchange rate, but can only be called by the `Oracle` contract; this constraint is set by the require clause.

```    function oracleResponse(uint response) public {
require(
"Only oracle can call this."
);
exchangeRate = response;
}
}
```

## Running the Example: External Function Type

This section contains additional information for running the contract. We should expect that our example accounts may change with each refresh/reload of Remix.

To run the example, we will first deploy the Oracle contract, copy its address to the `ORACLE_CONST` initialization line, and then deploy the `OracleUser` contract.

### Contract Test Scenario: External Function Type

1. `OracleUser` contract: call the `buySomething()` function.
2. `Oracle` contract: call the `reply(0, 17)` function.
3. `OracleUser` contract: call the `exchangeRate()` getter function and check the exchange rate set by the `Oracle` contract.

## Conclusion

Through this article, we analyzed several examples of smart contracts, got more familiar with the principles they use, and improved our understanding in terms of their usefulness and areas of application.

1. First, we had a clean listing of the internal function type example.
2. Second, we broke down the code of the internal function type example and analyzed it thoroughly.
3. Third, we got familiar with a very simple and short topic of how to run the internal function type example.
4. Fourth, we went through the actual steps of running the example of the internal function type and interpreting the results.
5. Fifth, we had a clean listing of the external function type example.
6. Sixth, we broke down the code of the external function type example and analyzed it thoroughly.
7. Seventh, we got familiar with a very simple and short topic of how to run the external function type example.
8. Eighth, we went through the actual steps of running the example of the external function type and interpreting the results.

## What’s Next?

This tutorial is part of our extended Solidity documentation with videos and more accessible examples and explanations. You can navigate the series here (all links open in a new tab):