Comment on JEP 305

alex at syncwords.com alex at syncwords.com
Wed Jan 8 16:09:24 UTC 2020


Thank you for your excellent reply!
 
1. I'll skip this. I already gave my thoughts on pattern matching. Moreover, I don't think "o instanceof Type x" is a natural extension of pattern matching. One is a deconstruction operation, the other is a boolean expression with a side-effect. It's fine for them to be separate features.
 
2. I see what you are saying. The example you give isn't a good one. println(char[]) and println(Object) are essentially equivalent (except for a small bug in PrintStream::write(char[]) which will flush multiple times). A better example is:
 
Object o = new Object[] { null };
if (o instanceof Object[])
   System.out.println(Arrays.asList(o));
 
Of course, this is a well-known problem of varargs. (Java should have gone with JSR 65 Concise Object-Array Literals). However, the vast majority of the time overloaded methods play nice with polymorphism.
 
To keep perfect backward compatibility, it is possible to invert the behavior. Make the original type the "default" type, and resort to flow typing only when type resolution fails. Because the vast majority of the time the resolution of a type to its derived type does not change program behavior, this should cause little surprise. If there is ever a surprise, it will be in new code.
 
Another trivial example:
Object o = ...
if (o instanceof Type) {
  var a = o; // flow-typing doesn't work. Oh well... type inference can fail.
  Type b = o; // is fine
}
 
Buffer b = ...
if (b instanceof FloatBuffer) {
  var arr = b.array(); // Will resolve to Object... type inference fails again
  float[] arr = b.array(); // Will resolve to float[]
}
 
> 3. Note that the left part of instanceof is not necessarily a
> variable. It could be a field, an array, a method call or other kind
> of expression. I saw dozens of
> complaints about Kotlin, like you change an immutable property to a
> mutable, and boom: flow typing is broken everywhere within your class.
 
Easy! Spend a line to declare a variable. The readers of your code will thank you!
Flow-typing of local variables covers 80% of use-cases. Creating a new variable using old syntax covers the other 20%. Declaring variables inside boolean expressions is ugly.
 
In the case of fields, flow typing is possible but there is the issue of mutable fields and concurrent writes. This is why changing a field to mutable breaks flow typing in Kotlin. This actually can be resolved. Flow typing on mutable fields is possible, provided there are no memory barriers (volatile reads or synchronized blocks) because the compiler is free to reorder concurrent accesses. So Kotlin's behavior is not mandatory.
 
4. To repeat, the problems with introducing variables in the 80% case of testing a local variable:
 
- Have to invent "stupid" variable names for variables which already have good names
- Broken refactoring
- Very weird constructs like (!(a instanceof Foo b))
- Breaks taboo on declaring and assigning variables inside expressions. Declarations should be statements.
- Feature-creeps the language instead of removing misguided compiler errors.
 
Aleksandr Dubinsky
 
 
-----Original Message-----
From: "Tagir Valeev" <amaembo at gmail.com>
Sent: Wednesday, January 8, 2020 4:02pm
To: alex at syncwords.com
Cc: "Amber dev" <amber-dev at openjdk.java.net>
Subject: Re: Comment on JEP 305



Hello!

1. Current instanceof is just a first step towards a pattern matching,
destructuring patterns cannot be expressed via flow typing and it
would be weird to introduce both features.
2. It's impossible to change existing Java to support flow typing
without breaking existing programs. E.g.:

static void test(Object obj) {
 if (obj instanceof char[]) {
 System.out.println(obj);
 }
}

If we allow flow-typing, then the println call should be rebound to
another method accepting char[] array, changing the program semantics.
It would be a compatibility disaster, much worse than e.g. simply
making some programs non-compilable. To introduce flow-typing in a
compatible way we would need to invent a new instanceof operator and
ask everybody to use it in new code. It's dirty and unlikely people
would adopt it soon.

3. Note that the left part of instanceof is not necessarily a
variable. It could be a field, an array, a method call or other kind
of expression. In all of these cases, flow typing would be useless
while variable introduction works consistently. I saw dozens of
complaints about Kotlin, like you change an immutable property to a
mutable, and boom: flow typing is broken everywhere within your class.
Proposed Java pattern matching doesn't care: it will still work.

With best regards,
Tagir Valeev.

On Wed, Jan 8, 2020 at 7:47 PM <alex at syncwords.com> wrote:
>
>
> First of all, let me start by saying that I wish there were a better place for the general public to provide feedback to proposed language changes. I understand that this feedback can get overwhelming, but it's also bizarre to have an "open" process and release public "preview" features but with few avenues, other than this list and, I guess, Twitter, for the wide, experienced, and plenty wise Java community to give feedback.
>
> Specifically, I want to share my feedback regarding the "Pattern Matching for instanceof" feature. I think "flow typing" is a great idea, and I don't like the current JEP 305 proposal because it forces the declaration of a new variable. Declaring a variable is onerous because each variable needs a good name. It is difficult to think of a good name for a variable that redeclares another variable which already has a good name. Moreover, having two names for the same variable hurts readability. It also breaks refactoring. Additional problems are weird constructs like if (!(a instanceof Foo b)). Flow typing is more general.
>
> There is no reason given for why the variable should be renamed, other than claimed harmony with a future, major language expansion under the banner of pattern matching. I hope that expansion does not make it. I read over Brian Goez's and David Bierman's document. What I have to say is this: Every language is shaped by the kinds of programs their authors write. Java was and is a general-purpose language that followed and (to a lesser extent) still follows the Keep It Simple, Stupid principle. The pattern matching proposal, however, seems like syntactic sugar written by and for programmers working on AST parsers. Not a lot of people work on those. (Incidentally, I dabble in them, and even I don't think it's worth trying to replace a mess of if statements with a mess of switch clauses, and then add chapters to Java books to explain how it all works.) If we're going to pick a use-case that is poorly addressed by the Java language, it should be scientific computing and AI (numpy, pytorch, etc). These would benefit from operator overloading and range expressions.
>
> Aleksandr Dubinsky


More information about the amber-dev mailing list