17

java - Significant difference between functional and procedural collection handl...

 4 years ago
source link: https://softwareengineering.stackexchange.com/questions/401882/significant-difference-between-functional-and-procedural-collection-handling
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Significant difference between functional and procedural collection handling

Closed. This question needs to be more focused. It is not currently accepting answers.

Want to improve this question? Update the question so it focuses on one problem only by editing this post.

Closed 7 months ago.

I'm planning an empirical study on function passing - specifically lambdas aka anonymous functions aka arrow functions. Now, although functional or even object-oriented approaches are highly favored over procedural/imperative programming nowadays, there seems to be very little empirical evidence for their superiority. Even though many different claims exist on why you're better off with higher-order programming¹, it's hard for me to construct cases that pose a chance for statistically significant differences.

The code is more expressive, telling what to do and not how

Claims like these are nice from a subjective and aesthetic point, but they'd have to map to empirical differences in productivity or maintainability in order to have leverage.

Currently I'm focused on Java's Stream API since it brought a major shift in how you write Java. For the industry this was accompanied by big rewrites, demand for employee training and updates to IDEs without much evidence that it's far better than what we had before.

Here's an example of what I mean where in my opinion the lambda-based implementation likely won't yield better results - even taking into account that participants would have to know the Stream API on top of the language API.

// loop-based
public int inactiveSalaryTotal(List<Employee> employees) {
    int total = 0;
    for (Employee employee : employees) {
        if (!employee.isActive()) {
            total += employee.getSalary();
        }
    }
    return total;
}

// lambda-based
public int inactiveSalaryTotal(List<Employee> employees) {
    return employees.stream()
                   .filter(e -> !e.isActive())
                   .mapToInt(Employee::getSalary)
                   .sum();
}

I personally rather suspect advantages regarding collection of streams but I'm doubting that the average Java developer knows the API surface well enough to not get stranded for certain tasks.

// loop-based
public Map<String, Double> averageSalaryByPosition(List<Employee> employees) {
    Map<String, List<Employee>> groups = new HashMap<>();
    for (Employee employee : employees) {
        String position = employee.getPosition();
        if (groups.containsKey(position)) {
            groups.get(position).add(employee);
        } else {
            List<Employee> group = new ArrayList<>();
            group.add(employee);
            groups.put(position, group);
        }
    }
    Map<String, Double> averages = new HashMap<>();
    for (Map.Entry<String, List<Employee>> group : groups.entrySet()) {
        double sum = 0;
        List<Employee> groupEmployees = group.getValue();
        for (Employee employee : groupEmployees) {
            sum += employee.getSalary();
        }
        averages.put(group.getKey(), sum / groupEmployees.size());
    }
    return averages;
}

// lambda-based
public Map<String, Double> averageSalaryByPosition(List<Employee> employees) {
    return employees.stream().collect(
            groupingBy(Employee::getPosition, averagingInt(Employee::getSalary))
    );
}

Specific Question

Can you construct an exemplary case where lambda-based collection handling outperforms procedural handling (looping) by much in regard to either comprehension time, writing time, ease of change or time it takes to perform a specific task like fixing a bug as well as counting certain calls or parameters. I'm also very much interested in how you think it performs better, because least LOC isn't really what I'm looking for here but rather something that can be measured in time - eventually with the average Java developer. Outperforming is also explicitly not meant in regard to runtime performance.

Examples can be pseudo-code or any language supporting both paradigms such as Java, JavaScript, Scala, C#, Kotlin.


¹ with the main focus on function passing, I'm assuming OOP and FP to be somewhat isomorphic for this purpose (type systems aside) since you could view an object as just a tuple of functions. With objects being able to accept and return other objects you've basically got higher-order functions


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK