• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Immutability? -- Functional Approach to Java

 
Rancher
Posts: 379
22
  • 1
  • Number of slices to send:
    Optional 'thank-you' note:
You touched on this very briefly in one answer here but I'd like to dig a bit deeper, if you don't mind...

My "daily driver" for the past decade has been Clojure which is immutable by default. Several FP languages I've used over the decades have also been immutable by default but more mainstream languages that are adopting FP features are all mutable by default with some, usually limited, support for immutability.

How important do you feel immutability is in functional style code?

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

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

Thanks!
 
Marshal
Posts: 79392
377
  • 1
  • Number of slices to send:
    Optional 'thank-you' note:

Sean Corfield wrote:. . . How do you balance that immutability with Java's mutable by default nature. . . .

Another interesting question for BW. This book really has raised some challenging discussions Doesn't that make the effort of posting worthwhile!
I think that, to some extent, there are old interpretations of what does and does not constitute object‑oriented programming (=OOP). The old way of doing things required inheritance. About 1992, Bertrand Meyer wrote asking how you can have programming without inheritance. And nowadays people say they hardly ever use inheritance. The classical interpretation of OOP was for mutable objects; if you look in Effective Java by Joshua Bloch, you will find all sorts of advantages to immutability.
Maybe, thirty years ago, hardware was slower and creating new objects, as one has to with immutable datatypes, was expensive in terms of performance and memory. I am sure that is no longer the case. I presume you are familiar with the techniques for creating immutable datatypes, and know that the process became much easier in Java16 (I think) when records were introduced.
 
Sean Corfield
Rancher
Posts: 379
22
  • Number of slices to send:
    Optional 'thank-you' note:

Campbell Ritchie wrote:
I presume you are familiar with the techniques for creating immutable datatypes, and know that the process became much easier in Java16 (I think) when records were introduced.



Yes, although Java 16 appeared long after I switched to Clojure (records were in preview in Java 14 but that was also still several years after I'd switched to Clojure)

Records definitely help but you still have to be careful about mutable instance data escaping via the implicit getters, requiring you to either override the constructor or the getter to provide an immutable copy, and there are some things that are still fairly verbose (compared to more FP-focused languages) such as producing a new record instance from an existing instance where only one or two fields are different: FP-focused languages usually have fully immutable data structures (deep immutability) and use some form of persistent data structure implementation to make operations that produce "modified" structures quite cheap and efficient.

It would be nice to have a more compact syntax for "construct a new Point record from myPoint with x = 0" (yes, you can do new Point(0, myPoint.y()) but that doesn't scale well for a record with, say, ten fields and you only want to vary one or two of them).
 
Author
Posts: 28
9
  • 2
  • Number of slices to send:
    Optional 'thank-you' note:
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, et.al., 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.
     
    Ben Weidig
    Author
    Posts: 28
    9
    • 2
    • Number of slices to send:
      Optional 'thank-you' note:
    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
     
    Sean Corfield
    Rancher
    Posts: 379
    22
    • Number of slices to send:
      Optional 'thank-you' note:
    Thanks for your thorough and well-considered answers! I think your book is going to be a great read.

    Ben Weidig wrote:Without knowing the syntax, non-Clojure devs will immediately be lost



    I hear this a lot but I must confess I don't really understand why. After all f(1, 2, 3) just becomes (f 1 2 3) and obj.method("a", "b", "c") just becomes (method obj "a" "b" "c") so it's not really that different
     
    Ben Weidig
    Author
    Posts: 28
    9
    • Number of slices to send:
      Optional 'thank-you' note:
    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.
     
    Sheriff
    Posts: 17652
    300
    • Number of slices to send:
      Optional 'thank-you' note:

    Sean Corfield wrote:

    Ben Weidig wrote:Without knowing the syntax, non-Clojure devs will immediately be lost



    I hear this a lot but I must confess I don't really understand why. After all f(1, 2, 3) just becomes (f 1 2 3) and obj.method("a", "b", "c") just becomes (method obj "a" "b" "c") so it's not really that different


    The key is "knowing the syntax".

    I know next to nothing about Clojure other than that it's a JVM language and that it's functional and maybe comparable to Lisp (?).

    When I see the contrast in your examples, I can understand how non-Clojure devs will be immediately lost, especially those who aren't familiar with functional-style programming. It's not just about programming syntax but semantics as well.

    It would be kind of like opening a box of IKEA furniture and finding that it's missing the instructions.

    With f(1, 2, 3) you know that f is the container of the logic and 1, 2, 3 are pieces that are used to obtain an answer from f().

    f 1 2 3 just looks like four different values that need to be put together somehow.

    Even when you know that the first thing is the function and everything that follows are parameters to the function, I think it would be still take a second for non-Clojure devs to figure out what's going on with something like functions calling other functions, e.g., (map inc (range 10))

    Another analogy is an English-speaking person trying to learn French or Spanish, languages which use different ordering of subject-verb-object. To English speakers, the way to negate things in French can be very strange. For example, Je parle français (I speak French) is negated as je ne parle pas français (I don't speak French). To English speakers, the French ordering looks like "I do speak not French."
     
    Sean Corfield
    Rancher
    Posts: 379
    22
    • Number of slices to send:
      Optional 'thank-you' note:

    Junilu Lacar wrote:Another analogy is an English-speaking person trying to learn French or Spanish



    That's a fair point.

    Just like The Pragmatic Programmer recommends, I make a point to learn a lot of programming languages beyond what I use for work, and I suspect Lisp family languages are easier to read for folks who know a number of non-mainstream languages (I've used over a dozen languages in production, over the years, and learned over a dozen extra "for fun" -- on top of the dozen or so I learned while I was at university).

    Lisp looks pretty "normal" compared to stuff like APL, Forth, and Smalltalk
     
    Ben Weidig
    Author
    Posts: 28
    9
    • Number of slices to send:
      Optional 'thank-you' note:
    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.

     
    Junilu Lacar
    Sheriff
    Posts: 17652
    300
    • Number of slices to send:
      Optional 'thank-you' note:

    Ben Weidig wrote:
    I learned French for 5 years in school, and I hated it!
    Learning a new programming language, though, is always fun for me.


    I studied some French in preparation for going to France for the first time a few years ago. I borrowed a language course on CD from the library. The course used the Pimsleur Method (named after its inventor, Dr. Paul Pimsleur) which involves frequent interleaved repetition and listening to and mimicking native language speakers. I found it was a good approach to learning and actually enjoyed it quite a bit.

    I think one key to learning a new language is immersion. I spent a few years in Singapore working with Malaysian truck drivers with whom I had to constantly interact. I can still remember some of the basic Malay I learned almost 30 years ago.

    Not having immersed myself in French, however, I can still remember some things I learned from Dr Pimleur's course. Repetition is also key, and having good examples to model your learning after. For example, I still remember the question "Ou est la rue Saint Michel?" After repeating this many times before our Paris trip, I told my wife we should find in a hotel on Rue St. Michel so we knew how to ask for directions back in case we got lost.

    Being from the Philippines, I'm not a native English speaker. However, I grew up in the US as a child (1st to 3rd grade) and at one point, English was the only language I understood and spoke. When we went back to the Philippines, I didn't even understand Filipino (based on Tagalog) or Bisaya (my dialect) any more. Again, immersion was key in me relearning my own native tongue within a couple of months. This highlights another key to language learning: youth. It seems  children find it easier to learn new languages than adults. Maybe it's not so much youth as it is having pre-existing biases to overcome.

    I have been programming in Java since 2000 and studied object-oriented programming and patterns intensively. Switching to functional programming was somewhat mind-bending for me and a little more challenging than I remember it was to shift from procedural programming to object-oriented programming. Personally, I found trying to learn how to think in FP was fun nonetheless. Unfortunately, I haven't yet had any opportunities to immerse myself in it.
     
    Junilu Lacar
    Sheriff
    Posts: 17652
    300
    • Number of slices to send:
      Optional 'thank-you' note:

    Ben Weidig wrote:I learned French for 5 years in school, and I hated it!


    Did you hate the language itself or the process of learning the language?

    Back in my days in school (80s-90s), Spanish was a mandatory subject in high school and college: two years in HS and four semesters in college. Despite that, the little that I know of Spanish could fit in a thimble. Most of what we did in school was to memorize conjugations. Learning how to use words to form sentences and express ideas was very minimal and ineffective, in my opinion. This was more a function of pedagogy than it was any inherent difficulty in learning the language itself. I hated having to memorize conjugations of various verbs.

    On the other hand, I enjoy the language courses I'm able to borrow from the library, especially when the approach is contextual/situational and you're able to hear how native speakers would say the words.
     
    Ben Weidig
    Author
    Posts: 28
    9
    • Number of slices to send:
      Optional 'thank-you' note:
    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.
     
    reply
      Bookmark Topic Watch Topic
    • New Topic
    vceplus-200-125    | boson-200-125    | training-cissp    | actualtests-cissp    | techexams-cissp    | gratisexams-300-075    | pearsonitcertification-210-260    | examsboost-210-260    | examsforall-210-260    | dumps4free-210-260    | reddit-210-260    | cisexams-352-001    | itexamfox-352-001    | passguaranteed-352-001    | passeasily-352-001    | freeccnastudyguide-200-120    | gocertify-200-120    | passcerty-200-120    | certifyguide-70-980    | dumpscollection-70-980    | examcollection-70-534    | cbtnuggets-210-065    | examfiles-400-051    | passitdump-400-051    | pearsonitcertification-70-462    | anderseide-70-347    | thomas-70-533    | research-1V0-605    | topix-102-400    | certdepot-EX200    | pearsonit-640-916    | itproguru-70-533    | reddit-100-105    | channel9-70-346    | anderseide-70-346    | theiia-IIA-CIA-PART3    | certificationHP-hp0-s41    | pearsonitcertification-640-916    | anderMicrosoft-70-534    | cathMicrosoft-70-462    | examcollection-cca-500    | techexams-gcih    | mslearn-70-346    | measureup-70-486    | pass4sure-hp0-s41    | iiba-640-916    | itsecurity-sscp    | cbtnuggets-300-320    | blogged-70-486    | pass4sure-IIA-CIA-PART1    | cbtnuggets-100-101    | developerhandbook-70-486    | lpicisco-101    | mylearn-1V0-605    | tomsitpro-cism    | gnosis-101    | channel9Mic-70-534    | ipass-IIA-CIA-PART1    | forcerts-70-417    | tests-sy0-401    | ipasstheciaexam-IIA-CIA-PART3    | mostcisco-300-135    | buildazure-70-533    | cloudera-cca-500    | pdf4cert-2v0-621    | f5cisco-101    | gocertify-1z0-062    | quora-640-916    | micrcosoft-70-480    | brain2pass-70-417    | examcompass-sy0-401    | global-EX200    | iassc-ICGB    | vceplus-300-115    | quizlet-810-403    | cbtnuggets-70-697    | educationOracle-1Z0-434    | channel9-70-534    | officialcerts-400-051    | examsboost-IIA-CIA-PART1    | networktut-300-135    | teststarter-300-206    | pluralsight-70-486    | coding-70-486    | freeccna-100-101    | digitaltut-300-101    | iiba-CBAP    | virtuallymikebrown-640-916    | isaca-cism    | whizlabs-pmp    | techexams-70-980    | ciscopress-300-115    | techtarget-cism    | pearsonitcertification-300-070    | testking-2v0-621    | isacaNew-cism    | simplilearn-pmi-rmp    | simplilearn-pmp    | educationOracle-1z0-809    | education-1z0-809    | teachertube-1Z0-434    | villanovau-CBAP    | quora-300-206    | certifyguide-300-208    | cbtnuggets-100-105    | flydumps-70-417    | gratisexams-1V0-605    | ituonline-1z0-062    | techexams-cas-002    | simplilearn-70-534    | pluralsight-70-697    | theiia-IIA-CIA-PART1    | itexamtips-400-051    | pearsonitcertification-EX200    | pluralsight-70-480    | learn-hp0-s42    | giac-gpen    | mindhub-102-400    | coursesmsu-CBAP    | examsforall-2v0-621    | developerhandbook-70-487    | root-EX200    | coderanch-1z0-809    | getfreedumps-1z0-062    | comptia-cas-002    | quora-1z0-809    | boson-300-135    | killtest-2v0-621    | learncia-IIA-CIA-PART3    | computer-gcih    | universitycloudera-cca-500    | itexamrun-70-410    | certificationHPv2-hp0-s41    | certskills-100-105    | skipitnow-70-417    | gocertify-sy0-401    | prep4sure-70-417    | simplilearn-cisa    |
    http://www.pmsas.pr.gov.br/wp-content/    | http://www.pmsas.pr.gov.br/wp-content/    |