1

I'm creating some kind of filtering system, which is based on that the different elements accept/produce the same kind of 'context'.

For example with the following, the process can be modelled:

{generate_numbers(1..100)} --> {is_prime} --> {output}

The context can be a simple 'HashMap'. generate_numbers creates contexts where 'x' is set to some number is_prime uses this context, looks for 'x' and puts 'prime'=true/false accordingly.

pros:

  • flexibility (easily extendable further (HashMap))

cons:

  • typeless values are casted all over the place

It is also a viable approach to declare everything as a field in the 'context', but this way the easily extendability is sacrificed (i can live with that)


But...the situation is a bit more complicated because these transformator elements are scattered all over the application's packages:

{generate_numbers(1..100)} --> {is_prime} --> {calc(f_1)} --> {output}
{--------------- pkg_A ------------------} | {--------- pkg_B -------}

So there are parts where pkg_A does some work, then there are places where pkg_B parts process the context --> that's why i would like to mix the two methods


I've come up with the following ideas:

option 1

  • say i've named the basic HashMap containing context E
  • create subclasses of E where some entries are presented in field for which getters/setters are availibe
  • in every processing function cast the incoming argument into the required class type

pro:

  • relatively easy to implement

con:

  • should syncronize the HashMap content w/ the field
  • more than one way to access a value can cause confusion

option 2

  • create some 'tool' classes which do the casting

pro:

  • no runtime casting for a subclass at every function

con:

  • access is always translated down to HashMap access
  • there is a casting every time a field is read

option 3

i'm entirely wrong, i should address the problem in a different way

UPDATE:

with "how to promote a context class?" i mean that how can i make a relatively convienient context which will carry all the messy stuff the application is working on, because in the current workflow these informations are blurred with the control logic

Zoltán Haindrich
  • 1,788
  • 11
  • 20

2 Answers2

1

I believe you shoudl switch to Scala :D.
Scala is a functional language with OOP design which runs on Java Virtual Machine and supports what you just mentioned and has a powerful pattern matching engine.

The other way might involve simulating functional paradigm in Java, which has actually crossed my mind a few days ago, but I had too much work and forgot about it :D.

Basically, what I was thinking back them is that you should have an interface

public interface Functionalizable {
    public void map(Function f);
}

Where Function would also be an interface which you could extend to write your own functions. Then, one such example (maybe bad, but those were my thought while I was traveling to work in a train) could be like this:

public class FunctionList extends ArrayList implements Functionalizable {
    public void map(Function f) {
        // iterate over the elements of a list
        // applying the function f on each of them
    }
}

and you could call it like this:

List l = new FunctionList();
// add some data
l.map(
    new Function() {
        // some function
    }
)

Of course, none of this code is actually compilable, but only whows what I've been thinking about. And yes, introducing functional paradigm in Java is a pain, so once more, my best advice is to stick with a real functional language, like Scala. :D

ioreskovic
  • 5,531
  • 5
  • 39
  • 70
  • this is part of a refactoring run, so switching language is not really an option; but scala looks very intresting - i will read more on scala – Zoltán Haindrich Jul 15 '12 at 10:05
  • I tried doing something like that myself, with some success: http://stackoverflow.com/questions/11484235/implementing-simple-functional-like-paradigm-in-java-collections-and-type-castin – ioreskovic Jul 15 '12 at 10:12
0

Trying to pass around metadata will make a maintenance headache. Instead, you want a functional programming solution, but in particular it appears you want to handle list comprehensions - in your example the generate_numbers function. While you could do this by rolling your own - as @Lopina suggests - by creating a set of function objects I think the better path is using an existing Java library.

In particular Google Guava has a number of tools for working against Java collections in this manner - the functional idioms are what you want. You'll have to write your own functions - in this case Guava Predicates - to use within the Guava's framework, but I think it provides right tools and level of abstraction for the problem you describe. I found this question's answer particularly helpful understanding predicates.

Example Guava Code

import java.util.Arrays;

import com.google.common.base.Predicate;
import com.google.common.collect.*;

public class PrimeFinder {
    static Predicate<Integer> isPrimeToTenThousand = new Predicate<Integer>() {
        private boolean[] primes = new boolean[10000];
        {
            // prime detection algorithm from
            // http://www.mkyong.com/java/how-to-determine-a-prime-number-in-java/
            // will contain true or false values for the first 10,000 integers
            Arrays.fill(primes, true); // assume all integers are prime.
            primes[0] = primes[1] = false; // we know 0 and 1 are not prime.
            for (int i = 2; i < primes.length; i++) {
                // if the number is prime,
                // then go through all its multiples and make their values false.
                if (!primes[i]) continue;
                for (int j = 2; i * j < primes.length; j++)
                    primes[i * j] = false;
            }
        }

        @Override
        public boolean apply(Integer number) {
            return primes[number];
        }
    };

    public static void main(String args[]) {
        ImmutableSortedSet<Integer> positiveIntegersTo100 = Ranges.open(1, 100).asSet(DiscreteDomains.integers());
        Iterable<Integer> primeNumbersTo100 = Iterables.filter(positiveIntegersTo100, isPrimeToTenThousand);
        // output: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
        System.out.println(primeNumbersTo100);
    }
}

Finally, this other question and its answers on how to simulate Python list comprehensions in Java should be helpful.

Iulian Popescu
  • 2,595
  • 4
  • 23
  • 31
orangepips
  • 9,891
  • 6
  • 33
  • 57
  • you have leaved the 'how to promote a context class?' question open...i'm not really looking for a functional programming library; in your example you ignored the that i sad that in the context there is a 'x' variable which holds the number and a 'prime' which is true/false whenever it's prime or not...i don't really understand – Zoltán Haindrich Jul 15 '12 at 18:01
  • @Zoltán Nagy: In your example, does calc(f_1) act on all values 1-100, or just the primes? – orangepips Jul 16 '12 at 15:49
  • on all of the context; i used it because the example is clearer this way....in the real application a bunch of things are computed at different parts of the program, and used elsewhere... – Zoltán Haindrich Jul 16 '12 at 16:39