Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

can you clarify "how" it makes one a better developer?

When I think of how the java streams API is used, it generates lots of garbage (i.e. lots of intermediary allocs), doesn't always make things clearer.. i'm genuinely curious (and in fact i like the streams API, it's just often misused by collecting at the wrong step..).



It depends your area of work.

If you're working on graphic engines, quants, system programming, you won't really be using a GC language anyways. There, being a better programmer is a lot about low level in the small design details.

If you're instead working on enterprise or consumer applications, backend processing, big data, information systems, saas, etc. There, you'll find Clojure makes you a better programmer, because it teaches a lot about in the medium to large design skills for growing such systems, where high/medium level decisions matters more and micro-opromizations a lot less.

Things that I've learned from Clojure are:

    * Better grasp of OOP and polymorphism
    * Better grasp of recursion and memoization in general
    * Better code structure for independent, modular, and reusable designs
    * Better isolation of external effects and internal business logic
    * Better, safer and more clear data manipulation techniques
    * Better domain modeling and data modeling 
    * Better handling of data at the boundaries of my application
    * Logic programming
    * Better understanding of mutation/immutable trade-offs
    * Better balance between spaghetti code and lasagna code
    * Monads and other functional patterns
    * Better use of higher order functions that benefit code understanding, extensibility and reuse
    * Better understanding of language design, code parsing and generation
    * Better understanding of numbers in general and numeric tower details
    * Better understanding of dependency injection and stateful components
    * Better understanding of parallel computing and various lock and lock-free designs
    * Better understanding of asynchronous and concurent computing, use of events, queues, CSP, future/promise, structured concurency, etc.
    * The awesomeness of structural edits, homoiconicity, and Lisp in general
    * The awesomeness of interactive live programming
    * Emacs


I think it helps you better understand how data flows through you program.

My input is A, and I need to create D. A -> A', then another function makes B, then another makes C, then another makes D. You can reason about and relatively easily test each of these steps. However, testing in a repl gets quite messy with calls such as h(g(f(x))). In python, you'd need to decorate you functions with an input/output logger.


Testing in a repl is easier and not messy at all if you use the Clojure arrow macro: (-> x f g h) You can see each step clearly, and build each result on top of what you did previously.


> When I think of how the java streams API is used, it generates lots of garbage (i.e. lots of intermediary allocs)

Not extremely relevant because it’s Lean 4 and not Java, but destructive updates can help with that:

https://arxiv.org/pdf/1908.05647.pdf

Edit: Now linking to the right paper.


Your programmer’s worldview will expand, you’ll learn new ways of doing things.


I can't speak about Haskell, but Clojure's lazy sequences also generate a lot of intermediate allocs.

For example, here's Clojure's implementation of `map`[1]. It internally uses `cons` to build a cell[2] and `map` to recursively walk the collection (but all wrapped up in `lazy-seq` to delay evaluation).

Transducers[3] do help with this if you are applying a stack of collection transformations. But, and this is just my opinion as a very occasional Clojure user, transducers are harder for me to grok and so I generally avoid using them. If I was doing performance critical work, I might try to build up a better mental model.

My biggest complaint about the Java streams API is that it makes it hard to write your own stream transformation functions. Or rather, you can, but then calling them is awkward. You generally transform a Stream by calling instance methods - e.g. `myStream.map(::f)`. But since Java doesn't have extension functions, there's no way for you to make a custom function callable in the same way as the built-in functions. I ended up writing a small shim to build a stream pipeline without using member functions. You would use it something like this:

    newPipeline(stream)
        .then(map(::mapFn))
        .then(filter(::filterFn))
        .then(customTransform())
        .collect(Collectors.toList());
Contrast that to Clojure, where everything's a function:

    (into []
      (customTransform
        (filter filterFn
          (map mapFn collection))))
Or (using the threading macro, I think this is right)

    (->> collection
      (map mapFn)
      (filter filterFn)
      (customTransform)
      (into []))
Or (using transducers, I'm really not sure if this is right)

    (into []
      (comp
        (map mapFn)
        (filter filterFn)
        (customTransducer))
      collection)
        
                      
[1] https://github.com/clojure/clojure/blob/2b3ba822815981e7f769...

[2] https://github.com/clojure/clojure/blob/2b3ba822815981e7f769...

[3] https://clojure.org/reference/transducers




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: