Embedded Software: Functional vs Non-Functional Programming

Hello everyone, I am the Mixed Bag Master.

In this article, we will share a comparison between functional programming and non-functional programming in embedded applications.

Functional vs Non-Functional Programming

Functional programming (also known as functional programming, lambda calculus) is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data, emphasizing the purity and immutability of functions.

In the field of embedded applications, there are significant differences between functional programming and non-functional programming (such as common imperative programming), which we will compare from multiple aspects below.

Embedded Software: Functional vs Non-Functional Programming

1. Testability

Functional programming:

The characteristics of pure functions make the code in functional programming highly testable.

Since the output of a function depends only on its input, testing requires only providing different input parameters and verifying whether the output meets expectations, without considering complex external environments and states.

Is it necessary to perform self-testing in embedded software? This article utilizes the high testability characteristic of functional programming:

Embedded Software: Functional vs Non-Functional Programming
Embedded Software: Functional vs Non-Functional Programming

Non-functional programming:

In non-functional programming, there is a lot of shared state and side effects, which require simulating complex external environments and states during testing, increasing the difficulty and complexity of testing.

2. Maintainability

Functional programming:

The code structure is usually built around the composition and reuse of functions, with clear dependencies between functions, and each function is responsible for a single task.

This results in a high degree of modularity, making it easy to understand and maintain.

For example, when processing sensor data, data reading and processing can be encapsulated into independent pure functions, and then the entire processing flow can be completed through function composition.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Simulate reading sensor data
float read_sensor(void) 
{
    srand(time(NULL));
    return (float)rand() / RAND_MAX * 100;
}

// Square the sensor data
float square(float value) 
{
    return value * value;
}

void print_sensor_data(float value) 
{
    printf("Processed sensor data: %f\n", value);
}

int main(void) 
{
    float sensor_value = read_sensor();
    float processed_value = square(sensor_value);
    print_sensor_data(processed_value);
    
    return 0;
}
  • Each function is a pure function, with clear inputs and outputs, and does not depend on or modify global state.
  • This improves the maintainability of the code, for example, the <span>square</span> function can be tested independently.

Non-functional programming:

Non-functional programming (such as imperative programming) typically uses variables, loops, and conditional statements to control the execution flow of the program.

The code structure focuses more on describing how to complete tasks step by step, which may involve many state changes and side effects.

When dealing with complex logic, the code may become lengthy and complicated, with relatively low readability and maintainability.

For example, in an embedded control system, using imperative programming may involve a lot of loops and conditional statements to implement different control logic, resulting in a lack of clarity in the overall structure of the code.

In the above sensor example, the implementation using non-functional programming would be as follows:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Simulate reading sensor data
float sensor_value;
void read_sensor(void) 
{
    srand(time(NULL));
    sensor_value = (float)rand() / RAND_MAX * 100;
}

// Square the sensor data
void square_sensor_data(void) 
{
    sensor_value = sensor_value * sensor_value;
}

void print_sensor_data(void) 
{
    printf("Processed sensor data: %f\n", sensor_value);
}

int main(void) 
{
    read_sensor();
    square_sensor_data();
    print_sensor_data();
    
    return 0;
}
  • This implementation uses a global variable sensor_value to store sensor data, with different functions reading and writing to it, resulting in side effects.
  • The maintainability and testability of the code are poor because the dependencies between functions are unclear, and modifying one function may affect others.

3. Performance and Resource Utilization

Functional programming:

Frequent creation of immutable data copies and function calls in functional programming can increase memory overhead and execution time.

In embedded systems, due to limited resources, this overhead can significantly impact system performance.

For example, in a resource-constrained microcontroller system, excessive use of functional programming may lead to memory shortages or slower processing speeds. Additionally, some features of functional programming (such as recursive calls) may lead to stack overflow issues.

#include <stdio.h>

#define ARRAY_SIZE 1000

// Functionally recursive sum of array elements
int sum_array_recursive(int arr[], int index) 
{
    if (index == 0) 
    {
        return arr[0];
    }
    return arr[index] + sum_array_recursive(arr, index - 1);
}

int main(void) 
{
    int arr[ARRAY_SIZE];
    for (int i = 0; i < ARRAY_SIZE; i++) 
    {
        arr[i] = i;
    }
    int sum = sum_array_recursive(arr, ARRAY_SIZE - 1);
    printf("Sum: %d\n", sum);
    return 0;
}

Using recursion to sum array elements allocates a new stack frame on the stack for each recursive call. When the array size is large, recursive calls can lead to significant stack space usage, potentially causing stack overflow issues.

Non-functional programming:

Non-functional programming can directly manipulate memory and hardware resources, achieving high performance and resource utilization through proper optimization.

In embedded systems, imperative programming typically allows for better control over memory allocation and deallocation, reducing unnecessary overhead.

In the above example of summing array elements, the implementation using non-functional programming would be as follows:

#include <stdio.h>

#define ARRAY_SIZE 1000

// Non-functionally sum array elements
int sum_array(int arr[], int size) 
{
    int result = 0;
    for (int i = 0; i < size; i++) 
    {
        result += arr[i];
    }
    return result;
}

int main(void) 
{
    int arr[ARRAY_SIZE];
    for (int i = 0; i < ARRAY_SIZE; i++) 
    {
        arr[i] = i;
    }
    int sum = sum_array(arr, ARRAY_SIZE);
    printf("Sum: %d\n", sum);
    return 0;
}

This code uses a simple loop structure to directly sum the array elements. In terms of memory usage, it only uses a fixed-size array and an integer variable to store the result, with no additional memory overhead.

Conclusion

Functional programming and non-functional programming each have their advantages and disadvantages in embedded applications.

When choosing a programming paradigm, it is necessary to consider the specific application scenario, system requirements, and resource constraints comprehensively.

For embedded applications that require high maintainability and testability but have relatively low performance requirements, functional programming may be a good choice;

while for embedded applications that require high performance and resource utilization, non-functional programming may be a better option.

In actual development, both programming paradigms can also be combined to fully leverage their advantages.

Embedded Software: Functional vs Non-Functional Programming

END

Author:ZhengNL

Source:Embedded Mixed BagCopyright belongs to the original author. If there is any infringement, please contact for deletion..Recommended ReadingThe company received a lawyer’s letter for using pirated AD software…If your code is fast and good, you are a fool!!!Why are hardware engineers’ salaries lower than software engineers, even though hardware is harder?→ Follow to avoid getting lost ←

Leave a Comment