Uploaded image for project: 'Scala Programming Language'
  1. Scala Programming Language
  2. SI-6169

propagate bounds from class type params to existential quantifiers

    Details

      Description

      see attachments

      In java you can write

      Circle circle = CircleBuilder.create().centerX(100).centerY(115).radius(100).build();
      

      This is a builder pattern which make use of existential f-bounds
      The problem is that in scala the skolems get erased after two method calls and so the next method doesn't exist.

      if I javap the java code

      const #33 = NameAndType #51:#52;//  create:()Ljavafx/scene/shape/CircleBuilder;
      const #34 = NameAndType #53:#54;//  centerX:(D)Ljavafx/scene/shape/CircleBuilder
      ;
      const #35 = NameAndType #55:#54;//  centerY:(D)Ljavafx/scene/shape/CircleBuilder
      ;
      const #36 = NameAndType #56:#54;//  radius:(D)Ljavafx/scene/shape/CircleBuilder;
       
      const #37 = NameAndType #57:#58;//  build:()Ljavafx/scene/shape/Circle;
      

      then I can see that the names and types are stored in bytecode (so a sort of runtime type info / refied generics)

      In scala:

      val circle = CircleBuilder.create().centerX(100).centerY(115).radius(100).build()
      

      causes

      C:\scala-2.10.0-M6\myexamples>scalac javafxbuilder.scala
      javafxbuilder.scala:19: error: value centerY is not a member of ?0
            val circle = CircleBuilder.create().centerX(100).centerY(115).radius(100).
      build()
                                                             ^
      one error found
      

      The only way to solve it in scala is to do a downcast after two methods (.asInstanceOf[CircleBuilder[_]]) or implicit conversion or to generate reified skolems _$x beforehand.

      val circlebuilder = CircleBuilder.create().asInstanceOf[CircleBuilder[_ <: CircleBuilder[_ <: CircleBuilder[_ <: CircleBuilder[_]]]]]
      

      which generates $_1, $_2 and $_3 for calling 6 methods (2 per skolem)

      This looks a bit hackish to me and very unscala.

      associated thread:
      https://groups.google.com/forum/?hl=en&fromgroups#!topic/scala-user/Op79HcAoj2M

        Attachments

          Issue Links

            Activity

            Show
            moors Adriaan Moors added a comment - https://github.com/scala/scala/pull/3471
            Hide
            moors Adriaan Moors added a comment -

            Let's see if this subsumes https://github.com/scala/scala/pull/2518/files?w=1#diff-4eab1aad4533a31c10565971e90f73eaR4910
            (so `canEnhanceIdent == false` because we no longer need it)

            Show
            moors Adriaan Moors added a comment - Let's see if this subsumes https://github.com/scala/scala/pull/2518/files?w=1#diff-4eab1aad4533a31c10565971e90f73eaR4910 (so `canEnhanceIdent == false` because we no longer need it)
            Hide
            retronym Jason Zaugg added a comment -

            I've just been building Slick with 2.11.

            https://github.com/retronym/slick/compare/tmp;2.11-compat-2?expand=1

            SI-1786 actually seems to be a step backwards. Before, slick left off a lot of existential bounds, but because it did that across the boards we it actually got away with it.

            Now, depending on compilation order, some bounds are inferred, and others aren't. The inferred bounds are infectious; type errors spring up in other places.

            [error] /Users/jason/code/slick/slick-testkit/src/main/scala/com/typesafe/slick/testkit/tests/JdbcMapperTest.scala:194: class PairShape needs to be abstract, since method copy in class ProductNodeShape of type (shapes: Seq[scala.slick.lifted.Shape[_ <: scala.slick.lifted.ShapeLevel, _, _, _]])scala.slick.lifted.Shape[Level, _, _, _] is not defined
            [error] (Note that Seq[scala.slick.lifted.Shape[_ <: scala.slick.lifted.ShapeLevel, _, _, _]] does not match Seq[JdbcMapperTest.this.tdb.profile.simple.Shape[_, _, _, _]]: their type parameters differ)
            [error]     final class PairShape[Level <: ShapeLevel, M <: Pair[_,_], U <: Pair[_,_], P <: Pair[_,_]](val shapes: Seq[Shape[_, _, _, _]]) extends MappedScalaProductShape[Level, Pair[_,_], M, U, P] {
            [error]
            

            So I can see the attraction of deferring the bounds sharpening until subtype checks.

            Show
            retronym Jason Zaugg added a comment - I've just been building Slick with 2.11. https://github.com/retronym/slick/compare/tmp;2.11-compat-2?expand=1 SI-1786 actually seems to be a step backwards. Before, slick left off a lot of existential bounds, but because it did that across the boards we it actually got away with it. Now, depending on compilation order, some bounds are inferred, and others aren't. The inferred bounds are infectious; type errors spring up in other places. [error] /Users/jason/code/slick/slick-testkit/src/main/scala/com/typesafe/slick/testkit/tests/JdbcMapperTest.scala:194: class PairShape needs to be abstract, since method copy in class ProductNodeShape of type (shapes: Seq[scala.slick.lifted.Shape[_ <: scala.slick.lifted.ShapeLevel, _, _, _]])scala.slick.lifted.Shape[Level, _, _, _] is not defined [error] (Note that Seq[scala.slick.lifted.Shape[_ <: scala.slick.lifted.ShapeLevel, _, _, _]] does not match Seq[JdbcMapperTest.this.tdb.profile.simple.Shape[_, _, _, _]]: their type parameters differ) [error] final class PairShape[Level <: ShapeLevel, M <: Pair[_,_], U <: Pair[_,_], P <: Pair[_,_]](val shapes: Seq[Shape[_, _, _, _]]) extends MappedScalaProductShape[Level, Pair[_,_], M, U, P] { [error] So I can see the attraction of deferring the bounds sharpening until subtype checks.
            Hide
            moors Adriaan Moors added a comment -

            Ok, you have me convinced. I'll revert the fix to SI-1786 and reopen it to receive a fuller fix based on SI-6169 in 2.12

            Show
            moors Adriaan Moors added a comment - Ok, you have me convinced. I'll revert the fix to SI-1786 and reopen it to receive a fuller fix based on SI-6169 in 2.12
            Show
            moors Adriaan Moors added a comment - https://github.com/scala/scala/pull/3509

              People

              • Assignee:
                moors Adriaan Moors
                Reporter:
                davescala DaveScala
              • Votes:
                7 Vote for this issue
                Watchers:
                10 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: