9

One of the tenets of Functional Programming is the use of Pure Functions. A Pure function is one that is side-effect free and referentially transparent.

Getters are not referentially transparent - if a Setter is called between calls to the Getter, the Getter's return value changes even though its parameters have not (typically no parameters)

Setters produce side-effects - Calling a Setter typically manipulates a value that is not its return value (in fact, traditionally a setter returns nothing)

I know in Scala we just kind accept the fact we are meshing together two paradigms (functional and object oriented) and use getters/setters as we would in a language like Java.

In a language like Haskell (which I'm not fluent with, but I'm told holds truer to a "Pure" functional language) I'm just curious, how you would model properties on objects such that Getters are referentially transparent and Setters are side-effect free?

Would the solution be to pass back a copy of the object the setter was invoked on as the setter's return value, and this copy contains the change to the property value?

3
  • 8
    Getters and setters have the object as parameter - even though it's usually implicit - so getters are referentially transparent.
    – user7043
    Commented Jul 27, 2011 at 18:21
  • @delnan, only if the attribute that it is reading is immutable. Commented Jul 28, 2011 at 7:53
  • 3
    @dan_waterworth: Only if we read the "same" in "referentially transparent" as object identity. If the fact the underlying attribute is different makes it a call with different arguments (which is in line with most definitions of equality). This is ignoring another thread calling a setter and finishing it between the call to the getter and the getter finishing, but in that case you got more serious problems anyway.
    – user7043
    Commented Jul 28, 2011 at 8:48

3 Answers 3

8

Exactly. See case class method copy, or the general concept of lenses.

In particular, if state needs changing, you'd use a State monad. Changes to that state monad can be made through lenses, which makes extracting information from "state" and changing it easy.

See also this question about the general problem that comes from a deep structure like "state" and making changes to it. The answers have good links on both lenses and zippers if you want to get deeper into that.

2
  • Question Daniel: is there any particular reason that copy() is tied to Case classes? This doesn't seem specific to the needs (wrong word, but can't think of another) of Case classes specifically, it seems (to me) more of a feature suitable for all classes. What if I need copy() on my non-case class? Is there a trait I can use to get that functionality?
    – ThaDon
    Commented Jul 28, 2011 at 2:11
  • 1
    @ThaDon case classes are supposed to be defined by their constructor parameters -- their equality, hash code and extractor are based on this assumption, and so is the copy method. On non-case classes, it is anyone's guess whether the constructor parameters are all that's needed to copy a class. You can, however, easily write your own copy method. Commented Jul 28, 2011 at 14:07
11

Well, in Haskell, objects are (usually) immutable, so getters (which you get when you use record syntax) or functions that act like getters are referentially transparent. And then you don't "set" values on objects -- if anything you create a new object which is similar to the old one, but with a different value for one of the fields. This is also a pure function.

1
  • 1
    "objects are (usually) immutable" when are they not?
    – sara
    Commented May 2, 2016 at 6:47
-1

"Getters and setters have the object as parameter - even though it's usually implicit - so getters are referentially transparent. – delnan"

Referentially transparent means that the function ALWAYS returns the same output for the same inputs; so if an object attribute has been changed by a setter, you are not returning the same output. :)

4
  • But, if the object was changed by a setter, the input to the getter (i.e. the implicit self argument) HAS changed. Commented Jul 27, 2011 at 21:02
  • 1
    The object reference value/pointer hasn't changed unless the object has been moved on the heap. Commented Jul 27, 2011 at 23:05
  • 5
    Yes, but logically, the implicit input is the object itself, not the value of the pointer. Commented Jul 28, 2011 at 3:54
  • "if an object attribute has been changed by a setter, you are not returning the same output": In functional terms, you have destroyed the first object and created a new one. For performance reasons (avoid copying and updating of references from the old to the new object) you are storing the new object in the same memory area that contained the old object.
    – Giorgio
    Commented Jun 17, 2013 at 5:21

Not the answer you're looking for? Browse other questions tagged or ask your own question.