Thursday, June 26, 2014

Constructors in converging OOP with FP (What it means to be data II?)

Oderski's convergence of FP with OOP helped me to realized two things. First, the arguments of primary constructor (you normally forwards calls to it in Java also, so it must be distinguished) can introduce and initialize fields implicitly, without the Java hassle

final Type1 field1; // val

Type1 field2; // var

Cons(Type1 aValue1, Type2 aValu2) {  this.field1 = aValue1

  this.field2 = aValue2

can be rewritten in Scala simply by

Cons(val aValue1: Type1; var aValue2: Type2)

Whatever functions (methods) you now define on Cons, you can use the constructor arguments because they are fields now.

Contrast this with partially applied functions or functions defined in some evironment, eg.

(define (cons x y)
  (lambda (m) (m x y)))

that I have revised in my previous post. You see, anonymous function, instantiated by "car" expects function m and will apply x,y to it when m is supplied. So, x and y are pieces of data that are embedded into the function. Basically, function is also an object, which can carry data. We create instances of cons function by calling cons (x,y) whereupon x and y play the same role as in Scala object -- constructor arguments become fields of the constructed object!

That is how functions can represent data. Partial application (curring) memorizes the function as well as some of the arguments to be applied in the classical object fields (actually classical OOP object is nothing more than a simple old good "record" of structural programming). Closures are not simple functions but objects that carry the state (where function was defined). That is the secret of storing the data in functions.

Thanks mister Odersky to bringing this on the surface. See also: how to customize a class: by constant fields or method polymorphism?

No comments: