Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to upper-bound a self-referential type?

Tags:

java

generics

I have things (say, for context, numbers) that can perform operations on their own type:

interface Number<N> {
    N add(N to);
}
class Int implements Number<Int> {
    Int add(Int to) {...}
}

and actors that act on all subtypes of a certain upper bound:

interface Actor<U> {
    <E extends U> E act(Iterable<? extends E> items);
}

I want to make an actor that acts polymorphically on any numerical type:

class Sum implements Actor<Number> {
    <N extends Number<N>> N act(Iterable<? extends N> items) {...}
}

Now, clearly this doesn't work because Number and Number<N> are not the same. In fact, since Number doesn't constrain an implementor's type parameter to be its own type, such an actor could not possibly work. But I don't care to operate on Numbers in general - I am satisfied for my functionality to work only on Numbers of some type N extends Number<N>

As an alternative, I could declare:

interface Actor<E> {
    E act(Iterable<? extends E> items);
}

class Sum<N extends Number<N>> implements Actor<N> {
    N act(Iterable<? extends N> items) {...}
}

But this doesn't work for me because it forces me to know N when I construct my Sum, which my use case doesn't conveniently allow. It also forces an ugly <N extends Number<N>> on every class or method that polymorphically uses a Sum, causing a proliferation of type clutter.

Is there any elegant way to do what I want?

Example:

Here is some sample code expressing what I would like to do.

interface Folder<U> {
    <E extends U> E fold(Iterable<? extends E> items);
}

class Sum implements Folder<Number> {
    <N extends Number<N>> N fold(Iterable<? extends N> items) {
        Iterator<? extends N> iter = items.iterator();
        N item = iter.next();
        while (iter.hasNext())
            item = item.add(iter.next());
        return item;
    }
}

class Concat implements Folder<String> {
    <S extends String> fold(Iterable<? extends S> items) {
        StringBuilder concatenation = new StringBuilder();
        for (S item : items)
            concatenation.append(item);
        return concatenation.toString();
    }
}

class FoldUtils {
    static <U, E extends U> E foldDeep(Folder<U> folder, Iterable<? extends Iterable<? extends E>> itemses) {
        Collection<E> partialResults = new ArrayList<E>();
        for (Iterable<? extends E> items : itemses)
            partialResults.add(folder.fold(items));
        return folder.fold(partialResults);
    }
}
like image 952
Reinstate Monica Avatar asked Jul 18 '14 21:07

Reinstate Monica


People also ask

How do you reference yourself from a class in C++?

Self-Referential Classes in C++ Self-referential classes are a special type of classes created specifically for a Linked List and tree-based implementation in C++. To create a self-referential class, declare a data member as a pointer to an object of the same class.

What is a paradox of self-reference?

In classical philosophy, paradoxes were created by self-referential concepts such as the omnipotence paradox of asking if it was possible for a being to exist so powerful that it could create a stone that it could not lift.

What is self referencing structure with example?

Self Referential structures are those structures that have one or more pointers which point to the same type of structure, as their member. Example: CPP.

Which one is a self-referential data type?

A self-referential structure is one of the data structures which refer to the pointer to (points) to another structure of the same type. For example, a linked list is supposed to be a self-referential data structure. The next node of a node is being pointed, which is of the same struct type.


1 Answers

Looking at your example, I'm not sure what you gain from having the generic method provide the concrete parameter vs having it in the actor:

class Sum<T extends Number<T>> implements Actor<T> {
    T act(Iterable<? extends T> items) {...}
}

What's the virtue of having a Sum<any-self-referential-Number> vs just having a Sum<Int>, and a Sum<Float>, etc?

If you're worried about the tiny memory overhead of creating different instances, you could just return the same instance each time with an unchecked cast, as is common where safe (see e.g. Guava's Optional.absent() or Collections.emptyList()).

In your example, somebody's eventually going to have to essentially do:

List<List<Int>> list;
foldDeep(new Sum(), list)

So why not just require the type parameter there?

foldDeep(new Sum<Int>(), list)

Or if encapsulated behind a factory,

foldDeep(Sum.instance(), list)
foldDeep(NumberFolders.sum(), list)

In short, it's not clear to me why this wouldn't work just as well:

interface Folder<U> {
    U fold(Iterable<? extends U> items);
}

class Sum<T extends Number<T>> implements Folder<T> {
    public T fold(Iterable<? extends T> items) {
        //...
    }
}

class FoldUtils {
    static <E> E foldDeep(Folder<E> folder, Iterable<? extends Iterable<? extends E>> itemses) {
        Collection<E> partialResults = new ArrayList<>();
        for (Iterable<? extends E> items : itemses)
            partialResults.add(folder.fold(items));
        return folder.fold(partialResults);
    }
}

//...
FoldUtils.foldDeep(new Sum<>(), list);
like image 152
Mark Peters Avatar answered Oct 26 '22 10:10

Mark Peters