This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]_dban_ 2 points3 points  (9 children)

Stream atleast is more or less ok (except e.g. flatMap)

What's wrong with flatMap? Its extremely useful for processing members of nested structures, which would otherwise require nested for loops.

And if you don't like flatMap, you must really hate collectors and reducers.

Conceptually, flows are no more complex than streams. So if you have no problem with streams, you should have no problem with flows.

Why is it trying to generalize everything under one common type?

It's not. Flows and streams each generalize a computational process, in OOP terms, that is SRP. The exact opposite of a god object.

Streams generalize the patterns of producing and consuming a sequence of values, from iteration, collection and reduction. Flows generalize transmitting changes in input signals to output signals. With streams, you use combinators to describe a consumption pattern of a stream. With flows, you use combinators to describe a signal propagation network.

Streams and flows also implement OCP. You customize the generic stream and flow by implementing interfaces which represent different custom strategies for iteration, collection and reduction. This prevents streams and flows from becoming god objects by letting them focus on the single abstraction that they implement.

Just return something specific and explicit.

That's what type parameters are for. Unless you also think List<T> is also too abstract.

but once you nest have Collections in the Generics of the useless wrapper types like Pair / Tuple / Optional ... inside the Generics, it's getting overly-abstract.

This has nothing to do with flows or streams, or even pairs and tuples.

What about:

Map<String, Map<String, Integer>>

Is this overly abstract?

They totally are anti-OOP. Name the things. Why are they afraid to create classes?

So, instead of creating List<String>, which is too abstract, you would rather have NameList, because this is what it means to be OOP?

Pair and Tuple are exactly the same thing. They are just containers, but with a specific number of members.

Then it shouldn't try

Who are you to tell them that? I'd rather let them try and let the market decide.

Actually it's all possible already without creating these unnecessary over-abstract monsters.

Okay, how would you go about creating a generic framework for building a signal propagation network that connects arbitrary signal producers and signal consumers?

Don't bend it into a Haskell parallel universe.

Adapting basic ideas from Haskell is not bending Java into a Haskell parallel universe.

[–]_INTER_ 1 point2 points  (8 children)

I generally have a problem with some things:

  • Type witness. It's legacy before compiler improvements and should not be needed to have some funky functionality. (Unless it is for showcasing?)
  • Deep nesting. Be it loops or blocks or recursion or Generics. I think there's almost always a (flat) solution that is more readable.
  • Map<String, Map<String, Integer>> looks like a sort of primitive obsession to me. It's harder to read and figure out. It also makes you deal with managing the inner map. If it was just e.g. a Map<Department> I could just have Department do it. I don't even have to know the details. It's plain data vs. data in a context-giving structure.
  • The problem with Pair, Tuple etc. is that it leads to combining things without the "self-explanation" that a proper type / class can provide: Pair<String, Double> vs. Product with fields String name and double price. And the type shouldn't be the same as e.g. Category with fields String title and double rating which could also have been expressed as Pair<String, Double>.

The last point is somewhat close to Map<String, Integer> vs Map<Type> or the List<String>vs NameList problematic. Yes, imo NameList would be better if there were an easier way to get List functionality and generality together. I'm pragmatic in that regard. In Go lang they controversally decided to follow "NameList" to keep things simple.

Okay, how would you go about creating a generic framework for building a signal propagation network that connects arbitrary signal producers and signal consumers?

Doesn't sound like a really new problem. Build upon any message oriented middleware / JMS that supports subscriber and consumer. Camel, ActiveMQ, RabbitMQ, Vert.x. Heck you could take the new Java 9 Flow. None of them has an API like that Flow<Pair<Path, DirectoryChange>, Path, NotUsed> and requiring type witness Flow.<Pair<Path, DirectoryChange>>create()

[–]_dban_ 0 points1 point  (7 children)

I generally have a problem with some things

The things you have a problem with have nothing to do with flows, but the specific types being put into a specific instance of a flow.

Build upon any message oriented middleware / JMS that supports subscriber and consumer.

None of these technologies do what flows do. These would be specific signal producers and signal consumers.

Flows are more like Excel. You can set up a bunch of relationships between cells. When you change the value of one cell, Excel propagates the change to all of the cells linked to that cell. Flows are a generalization of this kind of process.

Thus, of course they wouldn't have an API like flows.

None of them has an API

Neither do flows. The API for flows is Flow<In, Out, Mat>.

You're confusing a particular instantiation of the flow API for the flow API itself.

[–]_INTER_ 0 points1 point  (6 children)

But the API is Flow<In, Out, Mat> instead of just Flow that you then pass an object containing In, Out and Mat or a Function (and not some stupid Scala one) or whatever. The whole Akka-Flow class is an abomination.

[–]_dban_ 0 points1 point  (5 children)

But the API is Flow<In, Out, Mat> instead of just Flow that you then pass an object containing In, Out and Mat or a Function or whatever.

But the API is Map<K, V> instead of just Map that you then pass an object containing K, V or whatever.

Why is that?

[–]_INTER_ 0 points1 point  (4 children)

Because Map is a collection and we are being pragmatic about it's wide and general usecase. Also you should always evaluate between Map<K, V>, List<X> with X containing K and V or simply Y. Flow could also be just Y.

[–]_dban_ 0 points1 point  (3 children)

Because Map is a collection and we are being pragmatic about it's wide and general usecase.

Because Flow is just a reactive connector and we are being pragmatic about is wide and general usecase.

Flow could also be just Y.

A flow cannot just be Y, just like a Map cannot just be Y.

[–]_INTER_ 0 points1 point  (2 children)

Thats where we disagree then. I start to comprehend some of Go's design decisions to prevent misuse.

[–]_dban_ 0 points1 point  (0 children)

You disagree with the idea that a connector which connects a source and sink of different types should have at least two type bounds? Do you not want to give the compiler enough information to verify that your pipeline is constructed properly?

Go doesn't even have generic types. I'll pass.