Question

How are these principles applied in the context of streams and lambda expressions? In particular, the applicability with respect to the following three principles: - Single Responsibility Principle (SRP) - Liskov-Substitution Principle (LSP) - Open-closed Principle(OCP)

I feel like Lambdas, in general, have single responsibilities however when we use streams we use many lambda expressions chained,together ( map, iterate etc). So streams violate SRP according to my understanding.

I'm unsure if LSP is even applicable to streams and lambda's because it mostly deals with subtypes.

I would like to gain a clearer perspective on this.

Was it helpful?

Solution

I think streams+lambdas sometimes violate the single responsibility principle and sometimes don't. Sequencing of other operations is a "single thing" for the purposes of SRP. That's what streams do. If you mix that too much with defining the other operations, which is what lambdas do, you can get into a situation where you are no longer doing a "single thing."

Consider the following function from this question:

const getPctSameXs = (getX, filter = vals => vals) =>
  (objA, objB) =>
    filter(getXs(objB, getX))
      .reduce(
        (numSame, x) =>
          getXs(objA, getX).indexOf(x) > -1 ? numSame + 1 : numSame,
        0
      ) / Object.keys(objA).length * 100;

Here the lambdas make it really difficult to determine the sequencing. Consider my response that accomplishes the same task:

function getPctSameXs(obj1, obj2, f) {
  const mapped1 = mapObj(obj1, f);
  const mapped2 = mapObj(obj2, f);
  const same = mapped1.filter(x => mapped2.indexOf(x) != -1);
  const percent = same.length / mapped1.length * 100;
  return percent;
}

SRP purists would probably want to move some of this into separate functions, but this is roughly at the same level of abstraction, and the sequencing is easy to see.

In other words, a syntactic construct like a stream neither fulfills nor violates a principle on its own. It's about how you use it.

OTHER TIPS

SRP and OCP both sound like wisdom, but are essentially meaningless. There are no clear set of definitions, and there are conflicting interpretations, most of which don't even seem to have any clear design advantages.

Unless you define what you mean (not just link the Clean Code book, or some article without good examples), there is no point discussing this.

Liskov, even though it has its gray areas, is well defined, but as you mentioned is not applicable here.

A much better question though is, do you write lambdas and use streams that violate encapsulation / object-orientation / Law of Demeter? Because a lot of labmda/stream code out there does. Things like:

people.filter(p -> p.getName().startsWith("A"))

Unless you're in the Person class this filtering violates all of the above.

Licensed under: CC-BY-SA with attribution
scroll top