Skip to content

Instantly share code, notes, and snippets.

@andypetrella
Last active December 19, 2015 17:59
Show Gist options
  • Save andypetrella/5995607 to your computer and use it in GitHub Desktop.
Save andypetrella/5995607 to your computer and use it in GitHub Desktop.
Co-Contra variance in Scala
package cocontra;
import java.math.BigDecimal;
public interface actions extends model {
public static interface Proc {
void _();
}
public static interface Action<A, B> {
B exe(A a);
}
public static class IntHumanAction implements Action<Integer, Human> {
public Human exe(Integer i) {
if (i < 10) {
return new Kid(i);
} else if (i >= 18) {
return new Adult(i);
} else {
return new Teen(i);
}
}
}
public static class NumberAdultAction implements Action<Number, Adult> {
public Adult exe(Number n) {
BigDecimal nb = new BigDecimal(n.toString());
if (nb.compareTo(new BigDecimal("18")) >= 0) {
return new Adult(nb.toBigInteger().intValue());
} else {
return null;
}
}
}
}
package cocontra;
import java.util.ArrayList;
public interface co extends model, actions {
public static Proc covariance = new Proc() {
public void _() {
ArrayList<Kid> kids = new ArrayList<Kid>();
ArrayList<?> abstractList = kids;
/****************************************/
/******* This won't compile !!! *******/
/****************************************/
ArrayList<Human> humans = kids;
/****************************************/
/******* Thus, this neither... *******/
/****************************************/
ArrayList<Object> objects = kids;
//...
ArrayList<Kid> newKidsOnTheBlock = kids;
// So tricky !
ArrayList<? extends Human> youngPeople = kids;
}
};
}
package cocontra
import model._
object Co extends App {
val kids = List(new Kid(9))
val humans:List[Human] = kids
println(humans)
}
package cocontra;
import java.util.ArrayList;
public interface contra extends model, actions {
public static class ListMapper<I, O> {
ArrayList<I> l;
public ListMapper(ArrayList<?> list) {
this.l = (ArrayList<I>)list;
}
public ArrayList<O> map(Action<I, O> action) {
ArrayList<O> o = new ArrayList<O>();
for (I i : l) {
o.add(action.exe(i));
}
return o;
}
}
public Proc contravariance = new Proc() {
public void _() {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 100; i++) { list.add(i); }
ListMapper<Integer, Human> lm = new ListMapper<Integer, Human>(list);
Action<Integer, Human> ok = new IntHumanAction();
Action<Number, Adult> nok = new NumberAdultAction();
/* This compiles and works as expected !!! */
ArrayList<Human> humans = lm.map(ok);
System.out.println(toString(humans));
/****************************************/
/******* This won't compile !!! *******/
/****************************************/
// ArrayList<Adult> adults = lm.map(nok);
// System.out.println(toString(adults));
}
public <A> String toString(ArrayList<A> as) {
StringBuffer sb = new StringBuffer();
sb.append("List(");
String del = "";
for (A a : as) {
sb.append(del)
.append(a);
del = ",";
}
sb.append(")");
return sb.toString();
}
};
}
package cocontra
import model._
object Contra extends App {
val alot:List[Int] = (1 to 100).toList
val intToHuman:Int => Human = (x:Int) => x match {
case x if x < 10 => new Kid(x)
case x if x >= 18 => new Adult(x)
case x => new Teen(x)
}
def toHuman(l:List[Int])(f: Int => Human):List[Human] = l map f
val anyValToAdult:AnyVal => Adult = (x:AnyVal) => x match {
case x:Int => intToHuman(x) match {
case a:Adult => a
case _ => throw new RuntimeException("Too young!")
}
case _ => throw new RuntimeException("Not handled!")
}
val mappedHumans = toHuman(alot)(intToHuman)
println(mappedHumans)
val mappedAdults = toHuman(alot.filter(_ >= 18))(anyValToAdult)
println(mappedAdults)
}
package cocontra;
import java.util.ArrayList;
public class JStuff {
public static void main(String[] args) {
co.covariance._();
contra.contravariance._();
}
}
package cocontra;
public interface model {
public interface Human {}
public static class HImpl implements Human {
public Integer age;
public HImpl(Integer age) { this.age = age; }
public String toString() {
return this.getClass().getSimpleName() + "(" + age + ")";
}
}
public static class Kid extends HImpl {
public Kid(Integer age) { super(age); }
}
public static class Teen extends HImpl {
public Teen(Integer age) { super(age); }
}
public static class Adult extends HImpl {
public Adult(Integer age) { super(age); }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment