Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Higher Order Polymorphic Function

I am very familiar with functional langauges such as Scheme, and Haskell. I'm trying to solve a problem in Java and struggling, possibly because I'm still in a functional mindset.

I want to write:

public void doQueryAndStoreData(String query, <? extends Collection> storeIn) {
    /* make a jdbc query, get ResultSet */
    ResultSet rset = ...;
    ProcessResultSet proc = new ProcessResultSet();
    proc.process(rset, storeIn);
    /* clean up */
}

with an interface like:

private interface IProcessResultSet<C> {
    public void process(ResultSet rset, C storeIn);
}

and a class implementing the interface like:

private class ProcessResultSet implements IProcessResultSet<? extends Collection> {
    public void process(ResultSet rset, Map storeIn) {
        /* do something */
    }

    public void process(ResultSet rset, List storeIn) {
        /* do something else */
    }
}

so that the first method can call the appropriate process based on what type of storeIn it's given.

In Haskell I could write

class Storeable c a where
    store :: a -> c a -> c a

doQueryAndStoreData :: Storeable c a => ResultSet a -> c a -> c a
doQueryAndStoreData (ResultSet rs) coll = foldr store coll rs

and provide Storeable instances for whatever collection type I want to store my ResultSet in.

Is this the correct approach in Java? Because I feel like I'm somewhat fighting the langauge to accomplish this.

like image 423
cdk Avatar asked Jan 24 '13 16:01

cdk


2 Answers

No, Java doesn't do that.

You'd need to do something like:

public <T> void doQueryAndStoreData(
    String query,
    T storeIn,
    ResultSetProcessor<T> processor
) {

Or much more likely:

public void doQueryAndStoreData(
    String query,
    ResultSetHandler handler // may contain processor and storeIn
) {

I hope I don't need to mention SQL injection vulnerabilities are a bad thing. (Also Map is not a Collection in Java (it is in C# but C# Collection isn't very useful).)

like image 98
Tom Hawtin - tackline Avatar answered Sep 28 '22 05:09

Tom Hawtin - tackline


You cannot do that, unfortunately. The compiler must know at compile time which method this call is bound to. If you want to decide which method to call based on the runtime type of the object, you have to manually check it:

The most you can do:

private class ProcessResultSet implements IProcessResultSet<? extends Collection> {

    @Override
    public void process(ResultSet rset, Collection storeIn) {
        if (storeIn instanceof Set) {
            return processSet(rset, (Set) storeIn);
        } else if (storeIn instanceof List) {
            return processList(rset, (List) storeIn);
        } else {
            throw new IllegalArgumentException("Unimplemented storage type");
        }
    }


    public void processSet(ResultSet rset, Set storeIn) {
        /* do something */
    }

    public void processList(ResultSet rset, List storeIn) {
        /* do something else */
    }
}
like image 44
gaborsch Avatar answered Sep 28 '22 07:09

gaborsch