Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Three Java Variants Extend the Language : Page 2

Learn about three of the most promising Java variants—how they work, what their features do, and how you can integrate them into your development environment.


advertisement
The Pizza Variant
The Pizza package originated at the University of Southern Australia and now is an independent project hosted at sourceforge.net. It provides three major features:
  • Generics

  • Function pointers

  • Class cases
  • The first two are features that many developers have asked for in Java. They are included in a number of different Java variants.

    Generics
    A generic is a method, function, or class that does not completely specify all of the types of its variables, because the types can be specified later. The result is multiple versions of the method, function, or class that is specialized to a particular set of types.



    Generics fall under the rubric of parametric polymorphism (PP). PP exists in a number of forms, in numerous languages, and with many different names. For example, the C++ version of generics is templates. So in the case of Java, generics basically add templates to the language—and they are quite easy to use. As an example, you can create a simple pair class (a pair is a data structure containing a head and a tail).

    In regular Java, you could represent the head and tail as Objects. To get access to either, you would use the head() or tail() methods, each of which return an Object. Listing 1 shows OldPair.java, which implements a pair without using generics.

    The problem is that many developers find casting from Object to Integer annoying. Creating a generic class can improve this process. You can declare a generic class by specifying one or more type parameters, like so:

    public class MyPair<Head,Tail> { ... }

    The <head, tail> part of this declaration looks kind of like a function declaration, which is fine because it's supposed to. Just as a function takes some values and returns an answer, a generic class is a kind of meta-function that takes some types and returns a class.

    For example, you can declare a pair whose head and tail are both integers, like this:

    MyPair<int,int> p = new MyPair( 20, 30 );

    This declares a pair called p, which is actually a pair of integers. MyPair<int,int> is a class, while MyPair is really a class template (not to be confused with C++ templates!). MyPair isn't really a type, so you use it directly. You must instantiate it by supplying types. In this case, you supplied int and int, resulting in MyPair<int,int>, which you can use directly (as shown above).

    The nice thing about such a parameterized type is that you don't have to use casts to access its members. For example, look at the declaration of the head() method from MyPair:

    public Head head() { return head; }

    Note the return type. It isn't Object or Integer, it's Head—that is, it's whatever type was declared for the head value of the pair. Accessing the head thus doesn't require a cast:

    int head = p.head();

    Listing 2 shows the complete source for MyPair.

    Function Pointers
    Pizza also adds a neat feature called a function pointer. A function pointer lets you refer to a function (method) as if it were a regular value. You can also create functions that aren't really methods—they are just pure functions like you'd find in non-object-oriented languages. (If you are familiar with functional languages such as Scheme, you might have encountered these features under the name closure.)

    The following is an example of a function called isOdd, which tells you whether a number is odd:

    (int)->boolean isOdd = fun( int n ) -> boolean { return (n&1)==1; };

    The syntax is a little tricky. First, note the fun keyword. Instead of writing isOdd( int n ) { ... }, you write fun( int n ) { ... }, for example:

    boolean isOdd( int n ) { ... }

    instead of:

    fun( int n ) -> boolean { ... }

    This function has no name. Instead of declaring the function as having the name isOdd, the code declares it anonymously. You then can assign it to a variable called isOdd:

    (int)->boolean isOdd = fun( int n ) -> boolean { return (n&1)==1; };

    The first line declares a variable called isOdd. The type of this variable is (int)->Boolean, the type that takes an integer as a parameter and returns a boolean. Using such a function is easy. You just use the variable name as if it were the function name:

    isOdd( 23 );

    So what do you gain from this? Well, for one thing, you easily can assign another function to the same variable, like this:

    isOdd = fun( int n ) -> boolean { ... };

    This can be a completely different anonymous function. Also, you can assign such functions from variable to variable:

    isOdd = reallyFastIsOdd;

    One useful application of this is passing a function as a parameter to another function. For example, you can implement a filter that takes an array of integers and use it with an anonymous function that returns a boolean. This kind of function is often called a predicate. It answers a true-or-false question about an integer. Your filter method would run through a list of integers and ask the true-or-false question about each one. It would collect the ones that give a true answer and return an array containing them.

    So, for example, if you have an array of integers called integers, you can filter out the even ones as follows:

    int odds[] = filter( integers, isOdd );

    The second argument to filter is the isOdd function, which returns true for odd numbers only.

    You can be even terser by just passing the predicate directly to filter without assigning it to isOdd first, like this:

    int odds[] = filter( integers, fun( int n ) -> boolean { return (n&1)==1; } );

    Listing 3 includes the complete implementation of filter. Click here for complete instructions for running the Pizza variant.



    Comment and Contribute

     

     

     

     

     


    (Maximum characters: 1200). You have 1200 characters left.

     

     

    Sitemap