Patterns design question: Primitive type tests

Brian Goetz brian.goetz at oracle.com
Fri Nov 3 20:53:50 UTC 2017


Note that is really just about primitives, as they are the only ones 
whose value sets have non-trivial intersection.  Value types, being 
non-polymorphic and having no nontrivial overlap, won't have this problem.

Arguably, for strongly typed literals ("case 0.0f"), we could allow them 
against a target type of Object or Number, since there's only one type 
they could mean, but I don't see the return-on-spec-complexity here.



On 11/3/2017 4:30 PM, Remi Forax wrote:
> I'm happy with choice #3 too.
>
> #2 is a sad choice because this semantics is not explicit,
> #2 means instanceof + unboxing + widening but nowhere in the syntax 
> the wrapper type used for the instanceof and the unboxing appears. Not 
> having the wrapper type mentioned doesn't pass my semantics smell check.
>
> regards,
> Rémi
>
> ------------------------------------------------------------------------
>
>     *De: *"Brian Goetz" <brian.goetz at oracle.com>
>     *À: *"Gavin Bierman" <gavin.bierman at oracle.com>,
>     "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
>     *Envoyé: *Vendredi 3 Novembre 2017 20:37:20
>     *Objet: *Re: Patterns design question: Primitive type tests
>
>     As I outlined in the mail on the survey, I think there are three
>     possible ways to treat primitive type test patterns and numeric
>     constant patterns (when the target type is a reference type):
>
>     1.  Treat them as if they were synonyms for their box type.
>     2.  Treat them as matching a set of values; for example, "int x"
>     matches integers in the traditional 32 bit range, unboxing numeric
>     targets and comparing their values.
>     3.  Outlaw them, to avoid confusion or to preserve the opportunity
>     to do either (1) or (2) later.
>
>     For my mind, I think #2 is the "right" answer; I think #1 would be
>     a sad answer.  But, there are two additional considerations I'd add:
>      - As the survey showed, there would be a significant education
>     component of choosing #2, and;
>      - There isn't really an overwhelming need for being able to say
>     "Is this Object a numeric zero" or "Is this object a boxed
>     primitive in the range of int."
>
>     Taken together, these lead me to #3 -- rather than choose between
>     something sad and something that makes developers heads explode,
>     just do neither.  I don't think this is a bad choice.
>
>     Concretely, what I'd propose is:
>
>     Only allow primitive type test patterns in type-restating
>     contexts.  This means that
>
>         switch (anObject) {
>             case int x: ...
>         }
>
>     is no good -- you'd have to say Integer x or Number x or something
>     more specific.  But you could say:
>
>         switch (anObject) {
>             case Point(int x, int y): ...
>         }
>
>     because the types of the extracted components of Point are int,
>     and therefore the type test pattern is type-restating (statically
>     provable to match.)
>
>     Similarly, for numeric constant patterns, only allow them in
>     switches where the target type is a primitive or a primitive box.
>
>     There are ample workarounds where the user can explicitly say what
>     they want, if they need to -- but I don't think it will actually
>     come up very often.  And this choice leaves us the option to
>     pursue either #1 or #2 later, if it turns out that we
>     underestimated how often people want to do this.
>
>     This also sidesteps the question of dominance, since the confusing
>     cases below (like Integer vs int) will not come up except in
>     situations where we can prove they are equivalent.
>
>
>     On 11/3/2017 6:47 AM, Gavin Bierman wrote:
>
>
>             Primitive type-test patterns
>
>         Given that patterns include constant expressions, and type
>         tests possibly including generic types; it seems reasonable to
>         consider the possibility of allowing primitive type tests in
>         pattern matching. (This answers a sometimes-requested feature:
>         can |instanceof| support primitive types?)
>
>         However, it is not wholly obvious what this test might mean.
>         One possibility is that a “type-restating” equivalent for
>         primitive type-test patterns is assignment conversion; e.g. if
>         I have
>
>         |case int x:|
>
>         then a target whose static type is |byte|, |short|, |char|, or
>         |int| – or their boxes – will be statically deemed to match.
>
>         A target whose /dynamic/ type can be assigned to the primitive
>         type through a combination of unboxing and widening (again,
>         assignment conversion) matches a primitive type test. So if we
>         have:
>
>         |switch (o) { case int i: ...|
>
>         we have to do |instanceof| tests against
>         {|Integer|,|Short|,|Character|,|Boolean|} to determine a match.
>
>         A primitive type test pattern dominates other primitive type
>         patterns according to assingment compatibility;
>         |int| dominates |byte|/|short|/|char|, |long| dominates
>         |int|/|byte|/|short|/|char|, and |double| dominates |float|.
>
>         A primitive type test pattern is inapplicable (dead) if cast
>         conversion from the static type of the target fails:
>
>         |Map m; switch (m) { case int x: // compile error }|
>
>         The dominance interaction between primitive type-tests and
>         reference type-tests for the wrapper types (and their
>         supertypes) seems messy. Consider the following combinations:
>
>         |case int n: case Integer n: // dead case Integer n: case int
>         n: // not dead -- still matches Short, Byte case Byte b: case
>         byte b: // dead case Number n: case int n: // dead|
>
>         Is there some unifying theory that makes sense here? One
>         possibility is to take a more denotational view: a type is a
>         set of values, so type restatement is really about semantic
>         set inclusion, and dynamic testing is about set membership. Is
>         this adding too much complexity? Do developers really care
>         about this feature?
>
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20171103/15b3dd09/attachment-0001.html>


More information about the amber-spec-experts mailing list