Du bist nicht angemeldet
Facebook Login
Hello! You're not logged in. If you log in you can comment on articles and exchange with other users. We won't spy any of your data and after an hour you'll be logged out automatically.
Recommend

« The Joys of functional programming in Scala »

(09.09.2012 00:01)

In this article we will go through some of the basic syntax of functions in Scala and functions as first class citizens in Scala and Clojure. We will compare the syntactic concepts with their decompiled Java and comparable Java concepts. It concludes in a comparison of decompiled closures in Scala and Clojure.

a box showing x as input resulting in f(x)Going with the trends in programming, as a friend of VM based languages, will mean that there is no going around the hype that is Scala. One can harshly summarize it into an interesting mixture of paradigmes with an at times amusingly huge choice of syntax. All prejeduce aside it is in fact great joy to wildly mix common methodologies of both paradigmes, whilst fully ignorant towards the extremists believes of either side.

Perhaps it is nothing new to the python programmer or others spending their daily programming in an interpreted language both functional and object oriented, but for those coming from a Java background it can be great to finally have an excuse to make use of those features otherwise considered unmaintainable and possibly undesirable

Function syntax in Scala

On first sight a vast amount of its functional world appears a mangeling and mixing of endlessly nested inner classes, strangely repetitive API's defining only slightly different function types, and endless different amounts of syntax to make the exact same statement. However its concepts of functions as objects and thus first class members, with their underlying implementation being an annonumous inner class overriding an apply method of their implemented interface, strangely interesting possibilities open up. Enough for words, lets see some of that syntax, whilst slowly fading away the magic... 

val callMe: (Int => Int) = (x: Int) => {
      1 // is the loneliest number...
}
val callMe: Function1[Int, Int] = (x: Int) => {
      1 // is the loneliest number...
}
val callMe: Function1[Int, Int] = new Function1[Int, Int] {
      def apply(x:Int):Int = {
        1 // is the loneliest number...
      }
}

...all three of the above decompile into the exact same java code...

import scala.Serializable;
import scala.runtime.AbstractFunction1.mcII.sp;

public final class Simple$$anonfun$1 
     extends AbstractFunction1.mcII.sp 
         implements Serializable {

  public static final long serialVersionUID = 0L;

  public final int apply(int x) {
     return apply$mcII$sp(x); 
  } 

  public int apply$mcII$sp(int v1) { 
     return 1; // is the loneliest number...
  }
}

So the whole thing isn't too far away from...

Function1<Integer, Integer> callMe = new Function1<Integer, Integer>() {
			public int apply(Integer x) {
				return 1; // is the lonliest number...
			}
}

Great! now with that thinking we should be able get through some of that syntactic beauty. Thinking back to some of the things mumbled about earlier the very next thing to try is first class functions, which in lesser fancy words simply means to assign and pass around functions in variables

 Functions as first class citizens in Scala

To declare a function that takes a function we can use the same notation as seen above to define a function type so (Input) => Return however nesting all those lovely equal arrows quite quickly becomes a little messy...

val gimmeFunc: (((Int) => Int) => Int) = (func: ((Int) => Int)) => {
      func(1) // is going to be the lonliest number...
}

as we've come this far, we might as well imagine we want a function that returns a function rather than calling it and returning its return...

 
val gimmeFunc: (((Int) => Int) => ((Int) => Int)) = 
     (func: ((Int) => Int)) => {
      func // when will 1 be back?
    }

and for the sake of looking at some more of those pretty brackets and arrows, a function that gets a function which got a function and the whole thing returning a function...

val gimmeRealFunc: 
    ((((Int) => Int) => (Int) => Unit) => 
      (((Int) => Int) => (Int) => Unit)) = 
      (func: (((Int) => Int) => (Int) => Unit)) => {
      func // it's not coming back, is it?
}

Joking aside, it may seem over the top at first but you may get to a point where arranging your functions becomes so repetitive that you want to create a function doing so instead. 

Just so that we can say this article has actually got some useful background, here a little example of what can commonly be done with functions as the above (rather the first one than the overly brackety ones). Below we take two intiger and a function as input, the function we expect has to take two integer and return an integer.

val operateSomething = (x: Int, op: (Int, Int) => Int, y: Int) => {
       op(x, y);
}
     
operateSomething(1, _+_, 2) // 48!

 Closures in Scala and Clojure decompiled into Java 

We'll keep it simple to make their equivalents more readable and actually be able to read the decompilations. First of all a simple closure in Scala...

 class Simple {

  def main(args: Array[String]) {
    
    var closure: () => Int = () => {1};
    
    val enclose: Int => Int = (y: Int) => {
      closure = () => {
        y + 20
      }
      y + 10;
    }
    
    enclose(1); // 11
    closure(); // 21
   }
}

We'll leave out the type declarations, so we'll need a bit of imagination to fill the gaps (this is simply to avoid cluttering this article with even more uninteresting code snippets). Below the above decompiled into Java...

import scala.Function0;
import scala.Function1;
import scala.ScalaObject;
import scala.Serializable;
import scala.reflect.ScalaSignature;
import scala.runtime.AbstractFunction0.mcI.sp;
import scala.runtime.AbstractFunction1.mcII.sp;
import scala.runtime.ObjectRef;

@ScalaSignature(bytes = "...")
public class Simple implements ScalaObject {
	public void main(String[] args) {
		final ObjectRef closure$1 = new ObjectRef(
				new AbstractFunction0.mcI.sp() {
					public static final long serialVersionUID = 0L;

					public final int apply() {
						return apply$mcI$sp();
					}

					public int apply$mcI$sp() {
						return 1;
					}

				});
// here the outer function
		Function1 enclose = new AbstractFunction1.mcII.sp() {
			public static final long serialVersionUID = 0L;
			private final ObjectRef closure$1;

			public final int apply(int y) {
				return apply$mcII$sp(y);
			}

			public int apply$mcII$sp(final int v1$1) {
// and here its closure
				closure$1.elem = new AbstractFunction0.mcI.sp() {
					public static final long serialVersionUID = 0L;
					private final int v1$1;

					public final int apply() {
						return apply$mcI$sp();
					}

					public int apply$mcI$sp() {
						return v1$1 + 20;
					}

				};
				return v1$1 + 10;
			}
		};
		enclose.apply$mcII$sp(1); // 11
		((Function0) closure$1.elem).apply$mcI$sp(); // 21
	}
}

As already hinted at earlier, most of the magic here is as expected done via nested annonumous inner classes. The complication lies in preventing the nested class from altering the state of the outer class. To do so one requires a little trickery keeping the state in question immutable as mostly seen above.

Now lets see the same as the above, i.e. a simple closure in Clojure...

(defn enclose[y] (
                   (defn closure[] (
                                  (+ y 20)
                                  ))
                   (+ y 10)
                 ))

(enclose 1) ; 11

(closure )  ; 21

If we now compile the above ahead of time using (compile 'simple) and decompile the results into java, we'll see...

public final class closeit$enclose extends AFunction {

	public static final Var const__0 = (Var) RT.var("clojure.core", "defn");
	public static final Var const__1 = (Var) RT.var("closeit", "closure");
	public static final Keyword const__2 = 
			(Keyword) RT.keyword(null, "file");
	public static final Keyword const__3 = 
			(Keyword) RT.keyword(null, "line");
	public static final Object const__4 = Integer.valueOf(6);
	public static final Keyword const__5 = (Keyword) RT.keyword(null,
			"arglists");
	public static final Object const__6 = PersistentList.create(Arrays
			.asList(new Object[] { RT.vector(new Object[0]) }));

	public static final AFn const__7 = (AFn) RT.map(new Object[] {
			RT.keyword(null, "arglists"),
			PersistentList.create(Arrays.asList(new Object[] { RT
					.vector(new Object[0]) })), RT.keyword(null, "line"),
			Integer.valueOf(6), RT.keyword(null, "file"), "closeit.clj" });

	public static final Var const__8 = (Var) RT.var("clojure.core", "fn");

	public Object invoke(Object y) {
		Var tmp3_0 = const__1;
		tmp3_0.setMeta((IPersistentMap) const__7);
		Var tmp13_3 = tmp3_0;
		y = null;
		tmp13_3.bindRoot(new closeit.enclose.closure__589(y));
		return tmp13_3;
	}
}

public final class closeit$enclose$closure__589 extends AFunction {
	public static final Var const__0 = (Var) RT.var("clojure.core", "+");
	public static final Object const__1 = Long.valueOf(20L);
	public static final Object const__2 = Long.valueOf(10L);
	Object y;

	public closeit$enclose$closure__589(Object paramObject) {
		this.y = paramObject;
	}

	public Object invoke() {
		((IFn) Numbers.add(this.y, 20L)).invoke();
		return Numbers.add(this.y, 10L);
	}
}

We see again that functions are boiled down to nested classes but their calling and the general seperation of states is a little more convoluted than the previously seen bytecode decompiled from the scala closure. If you want to delve in deeper into some of the snippets seen above all the tools we used are free. To decompile the different bytecode classes we used the simple tools provided by http://java.decompiler.free.fr/ and for the coding itself we used the Eclipse plugin for Scala and Counterclockwise for Clojure.

Books about „Scala“

The following books are all about the topic "Scala" and are highly recommended. I have not read all of these books, but quality-checked them and already read a good number of the books I recommend. Furthermore I have used the majority of them for my research to get the information for this article. If you are unsure of whether you fully understood the topic and know what you wanted to know, it is always a good help to grab on of these books.
Programming in Scala
Programming in Scala
Author: Martin Odersky
Publisher: Artima Inc
Price: £24.26
Scala for the Impatient
Scala for the Impatient
Author: Cay S. Horstmann
Publisher: Addison Wesley
Price: £15.05
Functional Programming in Scala
Functional Programming in S...
Author: Paul Chiusano
Publisher: Manning Publications
Price: £17.37
Scala Cookbook: Recipes for Object-Oriented and Functional Programming
Scala Cookbook: Recipes for...
Author: Alvin Alexander
Publisher: O'Reilly Media
Price: £19.31
Like this article or have questions about it? Become a fan of the Kammerath Network and discover new articles even bevore they are finished: facebook.com/kammerath.net

Visitors who read this article were also interested in...

8 visitors also read this
7 visitors also read this
7 visitors also read this
6 visitors also read this

You just have to log in with your facebook account here to write comments. » Login with Facebook.
© 2014 Jan Kammerath
Phone +49 2241 955 98 60 or e-Mail contact.

The Kammerath Network Website System is published under the Mozilla Public License 1.1.

This website was developed by Jan Kammerath and in some parts contains copyrighted material that Jan Kammerath owns as intellectual property. Other parts of it are published either under the creative commons license and are owned by 3rd parties or are published as open source software by Jan Kammerath. The Kammerath family also owns e-mail addresses under the domains kammerath.net, kammerath.co.uk, kammerath.com and kammerath.ru. If you ask where the name Kammerath comes from you might get a lot of different answers as this today is mostly unknown.



Search site
Categories
Offers
Laden...