Type Class / Witness
Remi Forax
forax at univ-mlv.fr
Fri Aug 8 19:06:52 UTC 2025
Hello,
for those who where not at the JVMLS, it may make sense to re-read this email later,
when the talk of Brian on Type class / witness is visible on youtube.
I write this now because i'm sure i will totally forget about that in few days.
During the talk, Brian said that witness are restricted to be used only by value classes so we avoid the operator overloading hell that you can see in other languages.
I think this restriction can be bypassed.
The problem is that you can always wrap any class into a value class organized as a monad (containing a superposition of states) thus bypassing that restriction.
As an example, let say we want to abuse of the >> operator to emulate C++ iostream.
Let suppose we have this witness interface defined in the JDK (it is by example used by Integer)
witness interface BitwiseNumeric<V> {
V rightShift(V v1, V v2);
// other methods
}
And the witness interface for exact conversion also defined in the JDK
witness interface Conversion<U, V> {
U convert(V value);
}
So the trick is to create a value class that encode either a Writer or any value you want to add to the writer as a monad,
The exact conversion is used to wrap any value into the IOStream, the righShift is used to consume the wrapped value using a side-effect.
value class IOStream {
private final Writer writer;
private final Object o;
private IOStream(Writer writer, Object o) { this.writer = writer; this.o = o; super(); }
public IOWriter(Writer! writer) { this(writer, null); }
public static final witness BitwiseNumeric<IOStream!> BITWISE_NUMERIC = new BitwiseNumeric<>() {
public IOStream! rightShift(IOStream! v1, IOStream! v2) {
if (v1.writer == null || v2.writer != null) {
throw new ISE();
}
v1.writer.append("" + v2.o);
return v1;
}
// other methods throw UnsupportedOperationException
};
public static final witness Conversion<IOStream!, Integer!> FROM_INTEGER = new Conversion<>() {
IOStream! convert(Integer! value) {
return new IOStream(null, value);
}
};
}
So one can write
IOStream stream = new IOStream(writer);
var _ = stream >> 2 >> 3;
I think this is a general mechanism so any operator can be abused that way.
regards,
Rémi
More information about the amber-spec-experts
mailing list