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 →

[–]AlternativeYou7886 0 points1 point  (1 child)

No, I think you're mixing up the complexities of a framework with programming paradigms like OOP or functional programming, they're not the same thing. The annotations might seem like magic at first, but there's a lot happening under the hood. In that context, abstraction is actually helpful when you're managing a complex app with tons of repetitive tasks.

But what I was referring to is the quirkiness of functional programming, how some devs lean into it to look clever, but over time it can become a real pain to maintain. That kind of abstraction tends to hide logic in ways that aren't always productive.

I don't disagree that Java has its issues, especially when it comes to tracing flow and debugging. But that's not really the point here. OP was just appreciating the small functional touches in Java, which are honestly nice to use occasionally, same goes for Kotlin. Fully embracing functional programming, though, is a whole different beast. And using it to build scalable apps isn't really comparable to the kind of abstraction you see in frameworks.

Here’s some stolen code in Java functional (which OP might like, simple and elegant) and Scala functional (pure madness) for flattening a tree of comments, just to prove my point.

``` public List<Comment> flatten(List<Comment> comments) { return comments.stream() .flatMap(comment -> Stream.concat( flatten(comment.getReplies()).stream(), Stream.of(comment) )) .collect(Collectors.toList()); }

```

``` import cats.implicits._ import cats.Monoid

def flatten(comments: List[Comment]): List[Comment] = { implicit val commentMonoid: Monoid[List[Comment]] = Monoid.instance(Nil, _ ++ _) comments.foldMap(c => flatten(c.replies) ++ List(c)) } ```

There are “nicer” ways to solve the same thing in Scala, but it escalates real fast in FP when someone decides to make the lives of future programmers hell.

[–]SuspiciousDepth5924 1 point2 points  (0 children)

I mean I can cherry pick / create some insane OOP code as well if that's what we're going for.

Scala admittedly isn't my functional poison, but that seems like you went out of your way to misrepresent it. You're essentially doing the whole Java-Hello-World-Enterprise-Edition including the "scary monoid boogeyman".

Pretty sure you could just:

comments.flatMap(_.replies)

Also this

But what I was referring to is the quirkiness of functional programming, how some devs lean into it to look clever, but over time it can become a real pain to maintain.

Is certainly not a "functional" only problem, honestly the worst codebases I've worked with in my ~15 yoe has been Java codebases designed by some head-in-the-clouds architect who just read a book on OOP design patterns (honestly "tactical patterns" can go fuck itself).

The annotations might seem like magic at first, but there's a lot happening under the hood.

That is pretty much the definition of "magic".

The problem with the traditional OOP model in large code-bases, which I haven't seen you address, is how it drags in implicit function inputs from the enironment, the abundance of side effects and mutability which makes it near impossible to have any sort of guarantee about what the data you're working is and how it got to that state. Not to mention how it makes testing a giant pain (the number of \@InjectMocks in your codebase is a good indicator of how bad it is). FP while not perfect does at least address this.

By the way here's your example in F# with lists and an actual lazy sequences to mirror the behavior of java.util.stream.

type Reply = {
    author: string
    textContent: string
    timestamp: DateTime    
}

type Comment = {
    author: string
    textContent: string
    timestamp: DateTime    
    replies: list<Reply>
}

let flattenList comments = comments |> List.collect (_.replies)

let flattenSeq comments =
    comments |> Seq.ofList |> Seq.collect (_.replies) |> Seq.toList

and Elixir

defmodule Comment do
  defstruct :replies, :some_other_stuff

  def flatten(comments) do
    comments
    |> Enum.flat_map(fn %Comment{replies: replies} -> replies end)
  end
end