From forax at univ-mlv.fr Fri Aug 8 19:06:52 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 8 Aug 2025 21:06:52 +0200 (CEST) Subject: Type Class / Witness Message-ID: <1062553628.9518187.1754680012094.JavaMail.zimbra@univ-eiffel.fr> 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 rightShift(V v1, V v2); // other methods } And the witness interface for exact conversion also defined in the JDK witness interface Conversion { 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 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 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 From brian.goetz at oracle.com Fri Aug 8 20:01:17 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 8 Aug 2025 20:01:17 +0000 Subject: Type Class / Witness In-Reply-To: <1062553628.9518187.1754680012094.JavaMail.zimbra@univ-eiffel.fr> References: <1062553628.9518187.1754680012094.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <9A545FBA-39BC-463C-9983-E66691A0E0DA@oracle.com> This is a valid observation, but you are getting way ahead of yourself. My talk this week was about general mechanisms; we are not designing this feature yet, and discussions about it are premature (and likely counterproductive, as people chime in with questions about something that is not yet designed.) > On Aug 8, 2025, at 12:06 PM, Remi Forax wrote: > > 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 rightShift(V v1, V v2); > > // other methods > } > > And the witness interface for exact conversion also defined in the JDK > > witness interface Conversion { > 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 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 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 From forax at univ-mlv.fr Fri Aug 8 21:23:59 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 08 Aug 2025 21:23:59 +0000 Subject: Type Class / Witness In-Reply-To: References: <1062553628.9518187.1754680012094.JavaMail.zimbra@univ-eiffel.fr> <9A545FBA-39BC-463C-9983-E66691A0E0DA@oracle.com> Message-ID: In the future, we want to retrofit primitive to be value types. Type classes are one of the solutions for that. R?mi On August 8, 2025 9:12:28 PM UTC, David Alayachew wrote: >Woah, Type Classes! > >Ok, design talk aside, are you saying type classes are something you all >have decided to do? Is that a feature, even if only for value classes, that >we can safely assume is on the road map? > >All previous discussion on this made it sound like it's being strongly >considered, but not on the road map. > > >On Fri, Aug 8, 2025, 4:02?PM Brian Goetz wrote: > >> This is a valid observation, but you are getting way ahead of yourself. >> My talk this week was about general mechanisms; we are not designing this >> feature yet, and discussions about it are premature (and likely >> counterproductive, as people chime in with questions about something that >> is not yet designed.) >> >> > On Aug 8, 2025, at 12:06 PM, Remi Forax wrote: >> > >> > 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 rightShift(V v1, V v2); >> > >> > // other methods >> > } >> > >> > And the witness interface for exact conversion also defined in the JDK >> > >> > witness interface Conversion { >> > 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 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 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 >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: