> From: "Guy Steele" <guy.ste...@oracle.com> > To: "Brian Goetz" <brian.go...@oracle.com> > Cc: "amber-spec-experts" <amber-spec-experts@openjdk.java.net> > Sent: Saturday, April 16, 2022 4:10:06 AM > Subject: Re: Evolving past reference type patterns
> Yes, this is a clear improvement to the example code. > That said, I am always (or at least now) a bit leery of language designers > motivating a new language feature by pointing out that it would make a > compiler > easier to write. As I have learned the hard way on more than one language > project, compilers are not always representative of typical application code. > (Please consider this remark as only very minor pushback on the form of the > argument.) This is a very specific example due to the way integers are encoded in the bytecode, also you can simplify the code a bit more because ICONST_M1, ICONST_0, etc are all subsequents. Moreover, as i said earlier, it's more a work for method patterns. If we suppose we have a static pattern method isByte in java.lang.Byte class Byte { static pattern (byte) isByte(int value) { if (value >= -128 && value <= 127) { return match (short) value; } return no-match; } } the code becomes return with(switch (value) { case -1 .. 5 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_M1 + value); case Byte.isByte(byte _) -> ConstantInstruction.ofArgument(Opcode.BIPUSH, value); case Short.isShort(short _) -> ConstantInstruction.ofArgument(Opcode.SIPUSH, value); default -> ConstantInstruction.ofLoad(Opcode.LDC, BytecodeHelpers.constantEntry(constantPool(), value)); }); Rémi >> On Apr 15, 2022, at 5:36 PM, Brian Goetz < [ mailto:brian.go...@oracle.com | >> brian.go...@oracle.com ] > wrote: >>> * asking if something fits in the range of a byte or int; doing this by >>> hand is >>> annoying and error-prone >>> * asking if casting from long to int would produce truncation; doing >>> this by >>> hand is annoying and error-prone >> Here’s some real code I wrote recently that would benefit dramatically from >> this: >> default CodeBuilder constantInstruction(int value) { >> return with(switch (value) { >> case -1 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_M1); >> case 0 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_0); >> case 1 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_1); >> case 2 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_2); >> case 3 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_3); >> case 4 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_4); >> case 5 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_5); >> default -> { >> if (value >= -128 && value <= 127) { >> yield ConstantInstruction.ofArgument(Opcode.BIPUSH, value); >> } >> else if (value >= -32768 && value <= 32767) { >> yield ConstantInstruction.ofArgument(Opcode.SIPUSH, value); >> } >> else { >> yield ConstantInstruction.ofLoad(Opcode.LDC, >> BytecodeHelpers.constantEntry(constantPool(), value)); >> } >> } >> }); >> } >> could become the less error-prone and uniform: >> default CodeBuilder constantInstruction(int value) { >> return with(switch (value) { >> case -1 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_M1); >> case 0 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_0); >> case 1 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_1); >> case 2 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_2); >> case 3 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_3); >> case 4 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_4); >> case 5 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_5); >> case byte value -> ConstantInstruction.ofArgument(Opcode.BIPUSH, >> value); >> case short value -> ConstantInstruction.ofArgument(Opcode.SIPUSH, >> value); >> default -> ConstantInstruction.ofLoad(Opcode.LDC, >> BytecodeHelpers.constantEntry(constantPool(), value)); >> }); >> } >>