1

What's a good place to put pure functions that have connections to a system?

public class Core {
    System system;
}

public class System {
    SubSystem subSystem;
    // subSystem.Multiply(a, b);
}

public class SubSystem {
    public float Multiply(float a, float b) { return a * b; }
}

In this case, the SubSystem has a strong connection to the System. The functions within the SubSystem are pure/stateless.

The problem: If there is no state, why bother with the instance when a static class could do the same job?

Essentially it's Core.system.subSystem.Multiply(a, b); over SubSystem.Multiply(a, b);

And, sure we can go with static classes. But what happens when you have multiple systems with multiple static subsystems spread around the project? The connection is lost, and it quickly becomes a mess.

The way I see it, there are the following options:

Core.system.subSystem.Multiply(a, b); // instances
SubSystem.Multiply(a, b);             // static
SystemUtils.SubSystem.Multiply(a, b); // with namespace

But which one is best? And is there a better way?

4
  • If subsystems are stateles why would you want to have many of them? Oct 22, 2018 at 13:18
  • Sub-system may not be the correct word for it. It's all about separating functions into logical chunks that have some connection to the data that it modifies.
    – Iggy
    Oct 22, 2018 at 14:11
  • Whatever you prefer to call it, if it is stateless why would you want to have many of them? And nothing in your question seems to be about modifying data. Oct 22, 2018 at 16:58
  • Subsystem doesn't have any reference to System, as you imply. You don't need instances for pure methods. Oct 22, 2018 at 22:27

1 Answer 1

2

The problem: If there is no state, why bother with the instance when a static class could do the same job?

Objects can be developed using interfaces and thus mocked. Static classes cannot implement interfaces.
On a related note, objects can be passed from one method to the other, but static classes cannot.

If there is no state, why bother with the instance when a static class could do the same job?

"no state" and "static" are not equivalent terms.

It is true that static classes and methods entail not having a state (though you can argue that static properties are still a form of state - albeit a global one).

It is not true that anything that doesn't use a state must therefore be static. Taking your example of a multiplication method, it's perfectly possible to create several classes which can perform this function:

  • NormalMultiplier uses the simple a * b approach.
  • WolframAlphaMultiplier asks Wolfram Alpha for the result.
  • WindowsMultiplier relies on the Windows Calculator to find the result.

It seems a bit silly for multiplication, but it makes more sense for e.g. getting an accurate value of pi. Your local computer won't be able to calculate pi to as many decimal digits as Wolfram Alpha can (in a reasonable timeframe); but then again, if you only need a handful of decimal digits, you don't want to have to rely on the network connection to Wolfram Alpha.

In all three cases, the Multiply(a,b) method doesn't particularly requires a state; but how would you go about implementing these as static classes? You could do that, but then you make it impossible for these classes to have a common ancestor (e.g. Multiplier) or implement the same interface (e.g. IMultiplier).

This is where static classes fall apart. They are only useful in cases where there is exactly one implementation, never more, never less. And that's simply not always the case.
Indirectly, that also makes it impossible to mock static classes, which can be an issue when testing.

9
  • So, if you not gonna have different behaviour for Multiply function and you don't need to mock it for the tests(because function not depend on external resources) - you can use static method.
    – Fabio
    Oct 22, 2018 at 20:21
  • The "pure" attribute is probably more important than hypothetical polymorphism or mocking. Pure methods are the best type of method you can create. Oct 22, 2018 at 22:26
  • @Fabio: Yes, although I disagree with yuor assertion that you don't need to mock it for the tests(because function not depend on external resources) Depending on external resources is irrelevant in regards to needing to test/mock something. For example, consider MyService which depends on Multiplier, with no external resources. Suppose I want to test how MyService behaves when it receives a wrong multiplication result. I would then want to mock and inject a WrongMultiplier to ensure that I can test this path, and thus I need to be able to mock Multiplier.
    – Flater
    Oct 23, 2018 at 6:29
  • @FrankHileman: Probably more important indeed, but the purity of a method and its testability/mockability are not mutually exclusive. They are two independent considerations.
    – Flater
    Oct 23, 2018 at 6:31
  • @Fabio: Just to be clear: I'm aware that multiplication isn't the best example here as it's a mathematically proven operation that isn't liable to be changed at any point in the future, but the ability to test the behavior of MyService when its dependencies yield particular outcomes (correct result, wrong result, exception, ...) is a relevant test case, especially when the dependencies themselves are open to regressions or inaccuracies.
    – Flater
    Oct 23, 2018 at 6:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.