Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
Help coderanch get a
new server
by contributing to the fundraiser

Ben Weidig

+ Follow
since May 24, 2023
Merit badge: grant badges
Cows and Likes
Total received
In last 30 days
Total given
Total received
Received in last 30 days
Total given
Given in last 30 days
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Ben Weidig

After trying to learn Haskell and Clojure, I definitely have to agree

But sometimes it's good to know some of the dark arts  
1 year ago

Junilu Lacar wrote:There's at least an element of craftsmanship in it for me.

That's a good point, and I see craftsmanship is more fitting for the "art" of software development than calling it "artistic".

But hell, if a signed and dated urinal can be considered as art, then I don't know why a beautiful program (or for that matter, a crappy program that works) can't be considered as a work of art.

Some people consider explaining pictures in an art gallery to a dead hare art    so I'm pretty sure we can call software development an art, too.

In the end, for me, it all comes down to personal semantics and how one interprets art for themselves.
I see craftsmanship, artistic expression, and creativity as three different things.
However, I can't tell you exactly where the lines are, as they overlap quite a bit.
1 year ago
I'd second the notion of them not being synonymous.

For me, creativity is rooted in using your imagination to bring forth new ideas or solve problems in new ways, thinking outside the box.

Artistic, on the other hand, means primarily that people have the skills to create works of art, like drawing, music, etc.
I don't mean to downplay being artistic as just possessing a particular skill set, but it's a big part and necessity.

No doubt that there's an inevitable overlap, as creative artists can make for more interesting art, but it's not a hard requirement for a creative to be artistic.

Just look at something like "oil pointing reproduction", it's a whole industry without much creativity.
You can buy a replica of any work of art, or even a photo, as an oil painting done by an artistic person, as they need to be able to paint an oil painting.
Still, it's supposed to be a "perfect" replica, so there's no room for actual creativity.

IMO, using "artistic" in the field of technology can be misleading, except you use technology to create a work of art.
We often talk about the "art of programming", but is it really an art?
You could elevate almost any task to an "art form" by setting high enough skill requirements, but that just would dilute the meaning further.
1 year ago
Thanks again for having me!
I really enjoyed discussing the book and functional concepts in general  

Congratulations to the four winners    I hope you like the book!
Hi Zain,

you can run Gradle like this to show you all deprecation warnings:

./gradlew --warning-mode all

The output should include explanations and links to the documentation, for example

1 year ago
Thank you for sharing your story!

I think in my case, it was a mix of me not being the best student in the first place, and not seeing a real use case for French, even though France is right next door.
The French language itself is fine, it might have some weird quirks, but which language doesn't?

English, on the other hand, helped me consume many forms of media, like books, movies, games, etc., so I didn't have much of an issue with the 9 years at school.

For me, it's the difference between being forced to learn a language and wanting to learn one.
I still remember fondly many of the Japanese classes I took at university, even though I wasn't that good at it.
But more of the language stuck with me compared to French, and I don't have an actual use case for Japanese, either.
I like the French/English/Spanish analogy, as programming languages share many aspects with "normal" languages.
Most languages are in a family, sharing concepts, some base vocabulary, etc., making it easier to learn a new one.
That doesn't mean it's simple, though.

English and French are both Indo-European languages, but there are three more levels of distinction until you reach the actual language.
And still, it's easier to learn French as an English speaker than some completely different languages like Japanese.

Japanese still shares many aspects most languages share, but is wrapped in an unfamiliar writing system and new characteristics usually not present in Indo-European languages, like multiple characters systems, the lack of a future tense, different vocabulary/grammar rules depending on politeness, or counting classifiers that depend on what you count and its size/shape.
But learning Japanese allows you to read Chinese to an extent.
Each language you learn contributes to how easily you can approach a new one.
However, not everyone is interested in learning new languages.

I learned French for 5 years in school, and I hated it!
Learning a new programming language, though, is always fun for me.
Still,  sometimes we forget that not everyone shares the same enthusiasm for learning new languages, particularly outside of a work context, and that's totally fine, too.

Thank you!

When I try to learn a new language, I usually go full in and start looking at "normal" code/projects immediately, even if I don't understand each thing.

In Clojure, though, I was overwhelmed with the different order, inside-out evaluation, lack of types, being functional, etc., so I grabbed a copy "Clojure for the Brave and True" and started with the basics.

If all you know is C-style syntax, Lisp-like can feel quite alien at first.
Once you realize how it ticks and the language starts making sense, damn!
Why didn't I realize that everything just makes sense?

Clojure is such a nice language, and I wish I could use it more.
But I don't want to force Clojure code on my colleagues, so I'd end up the only maintainer for any Clojure code.
Maybe a small FC/IS would be an option, as it would be too intrusive to the overall architecture.
Last time I tried interop from Java to Clojure, though, I didn't like it very much, as everything is, as expected, untyped.
However, with clear and well-defined boundaries that shouldn't be big issue.
Didn't see your response while writing mine, so here's an addition.

You're right in your criticism, but you also mention why it's not the strongest argument against Java, at least in my opinion.
Java isn't an FP-focused language, and I think it isn't trying to be.
The verbosity of Java is a curse and a blessing at the same time.
For a language like Java, the verbosity often makes it easier to reason with.

Clojure fixes that by being easier to reason with from the get-go... if you understand Lisp-like syntax.
Without knowing the syntax, non-Clojure devs will immediately be lost, where most "any other language" developers will have fewer problems getting the gist of Java code.
I know that this is mostly because we still introduce new developers to C-style languages and OOP, but still... FP-focused languages are "harder" for most people due to their focus on Math, compared to the metaphor-based approach of OOP.

Nevertheless, I agree with you, there needs to be an easier/more compact way to mutate Records.
Although, their JEP mentions explicitly that "war on boilerplate" wasn't a design goal.
But seeing how they evolved since Java 14, like the upcoming JEP 405: Record Patterns, I haven't given up hope that there might be something coming in the near future
Hi Sean,

it's fair to say that Java's immutability support at the language level is limited, especially compared to something like Clojure.

Sean Corfield wrote:How important do you feel immutability is in functional style code?

Personally, I find immutability quite important, regardless of the paradigm, as it eliminates so much possible bug surface.
The fewer moving parts, the better!
For functional programming, however, I see it as a must-have.

How do you balance that immutability with Java's mutable by default nature.

Designing immutable data structures in Java is possible, it just needs more work.
As Campbell already said, the introduction of Records (in Java 14  as a preview I think, finalized in 16?) gave us a new way to declare "data aggregation types", which makes it easier to design immutable types.
If you read the corresponding JEP 395, they're supposed to "act as transparent carriers for immutable data".

Java is still only shallowly immutable, so some extra work is required to achieve "full" immutability, but it's the first step in the right direction.
You also need additional work when immutable data has to change.
Copy constructors, builder, withers,, are possible, but you must either do it yourself or use a dependency.
At my company, we try to use Records for simpler types.
But for more complex types, especially if they can't be initialized in a single step, we rely on the Immutables project, an annotation processor that generates immutable types based on abstract classes and interfaces, including builders, etc.

What advice do you have for trying to work extensively with immutability in Java?

My general advice, not only for immutability, is building a functional mindest, so you can reap many of the benefits of functional programming in any paradigm.
For immutability, that means for me:

  • Treat everything as immutable, especially if you don't control the API. For example, the Collectors.toList() returns usually an ArrayList, but it's not guaranteed as stated in the documentation, so don't rely on it.
  • Prefer immutable types, like Records, over POJOs.
  • Prefer pure functions/methods. Don't change incoming args.
  • Wrap outgoing Collections in their unmodifiable wrapper.
  • If it doesn't work as an immutable data structure, don't force it. There's no shame in mutability.

  • Still, you have to consider the potential overhead due to the lack of deep language-support.
    Without persistent data structures with path copying, like in Clojure, you have to think about recreating/copying data structures and how it might affect your performance.
    Today's hardware is way more powerful, and "premature optimization is the root of all evil".
    But keeping it in mind from the beginning doesn't hurt, either.

    That's why one viable approach to more FP in Java is the "Functional Core/Imperative Shell" design, which I talk about in the final chapter.
    The imperative, mutable world is a layer around the "as pure as possible" and immutable inner core, that does the actual work.
    Such FC/IS can be introduced gradually, you even can have multiple ones and size them as required.

    I think one of the main lessons for a more functional approach to Java code is not being too strict, as the language was never designed to be the perfect functional language.
    Every little new functional, or even only functional-akin feature, is still a very good thing in the long haul, because so many of us can't leave the Java world easily and switch to a "better for functional" language.
    So you have to take the good with the bad, but I promise you that in the end, you still will be more productive and have safer, more straightforward code that's easier to reason with.
    It was my pleasure!

    Getting critical questions and being confronted with different views and backgrounds is always a good way to re-evaluate and re-adjust your own point of view.

    Thanks to all of you for the interesting and sometimes not so easy to answer questions!

    Sean Corfield wrote:So that's about 18 years

    Looks like it's time for the weekend when I can't do such simple math anymore

    Exactly, the language design, good stewardship, and preservation of backward compatibility to the vast ecosystem IS the main selling point for Java IMHO.
    If that means there are trade-offs in areas of how well certain features can be integrated, I'm ok with that.
    There's still a lot to gain from such features.

    Looking at my other most-used language, Swift, I see quite a different approach to a programming language.
    It's an interestingly designed language with many features done right.
    But the price was the lack of ABI stability before version 5 and multiple changes to the syntax over the years.

    So each yearly iOS release brought a new Swift version that broke your code and dependencies.
    Combined with the fact that Apple forces you to recompile and re-upload the app every other year, that's quite a nuisance!
    Hi Dinkar,

    thanks for the warm welcome!

    Dinkar Chaturvedi wrote:So when compared to other pure functional languages, how do you see Java's functional constructs faring against them?

    That's a tricky question... if I say Java's not good for FP, no one will buy my book

    Jokes aside, Java's functional support can feel quite constrained or forced compared to a "pure" functional language, but I think that's to be expected in a multi-paradigm language without such support from the ground up.
    But for me, that isn't the issue or the eventual deciding factor to use it.

    As I see it, the Java team did a fantastic job integrating the possibility of functional programming in a way that works without breaking the language and is quite close to how Java devs would expect it..
    Naturally, this is a trade-off and affects how "pure" the functional support or how good the constructs are compared to other languages that don't focus on compatibility, or don't need to integrate it 12 years after the language's inception.

    For example, backing each lambda with a concrete type as a functional interface makes them first-class citizens without breaking Java, as there are no dynamic types.
    Pre-Java 8 interfaces even become usable for lambdas automagically if the comply with the "single-abstract method" requirement of functional interfaces.
    However, enforcing concrete types can create incompatibility between identical lambdas that are represented by different types.
    I talk about this in the book, and usually, type inference or bridging the gap with a method reference is enough to make it work.
    From a pure FP point of view, that might feel subpar, and it is, but from a Java devs view, you still have access to many of the benefits of FP without needing to go fully functional.

    Also, do you think if this limits Java's ability to allow developers to fully realize the potential of achieving the benefits of functional programming?

    If a developer only checks out a single language trying to realize the potential of a paradigm's ability, then I'd say yes.
    But I wouldn't recommend Java as the language to learn/use if you want to be exposed to the full potential of FP.
    Just as you wouldn't start/use F# for being exposed to the full potential of OOP, either.
    Sure, you can use either language for both paradigms, but software development is about choosing the right tools for the job.

    For me, Java's functional support is a great way to get your feet wet and see the tip of the FP iceberg.
    That's why I called my book "A Functional Approach to Java" and not "Functional Programming with Java".
    Being able to introduce FP into your Java code base gradually is the real benefit of Java's functional support, in my opinion.
    Hi Simon!

    The book's upper ceiling is Java 17, as it was the current LTS version at the time of writing.
    If there's something on the horizon, I mention it, link to JEPs, might even tease a little code, etc., but don't go into much detail.

    My reasoning was that many Java devs are still stuck on 11 or even 8.
    If they finally get to use a new version, I think it's unlikely they will switch directly to 21 with preview features enabled.
    And, to be honest, the book was initially planned to be no longer than 275 pages.
    I ended up with a 403 pages book which took quite some more time to write...

    So where do you begin to cut or draw the line?
    I concentrated on available features instead of upcoming ones, as preview features might still change, and printed books are kind of immutable data structures that can only be fixed with new editions

    Campbell Ritchie wrote:There are two, one being called RVM Forth

    Reversible computing sounds quite interesting, thanks!
    I've put a few papers on my reading list.

    so they ended up with a little bit of a cheat: this

    Unchecking an Exception is absolutely a cheat!
    And it was "abused" even before lambdas entered the scene.
    With lambas, however, it's sometimes a necessary evil to regain some form of sanity, even though it always feels weird to do so.

    You're right, the conventional story for checked Exceptions is a convincing one, and if used "correctly", they can be an incredible tool.
    Sadly, I think they're often a misunderstood or misused/overused feature and can be more of a nuisance and obstacle to overcome.

    Hopefully, someday we get a language-level tool to deal with them, as approaches like Kotlin's "let's treat them all as unchecked" don't sit well with me, either.

    Maybe something like what Swift does with the keywords try, try?, and try! in front of a throwing method call to indicate either:
  • try: this call requires a do-catch-block
  • try?: no do-catch, but the method's return value is wrapped into an Optional, which is empty in the case of an Exception
  • try!: trust me, I'm an engineer... meaning no do-catch, but the method will blow up in the case of an Exception, as the call is wrapped in a runtime assertion to not throw an error.

  • This way, the catch-or-specify requirement would still be there, and method signatures confer all the information you need to not be surprised by an Exception, but the compiler can force you to make a conscious decision on how to handle things.
    Even if you just want to ignore an Exception, you have to say so yourself.