Skip to content

SI-9076 REPL wrap is App#4349

Closed
som-snytt wants to merge 3 commits intoscala:2.12.xfrom
som-snytt:issue/9076-2.12
Closed

SI-9076 REPL wrap is App#4349
som-snytt wants to merge 3 commits intoscala:2.12.xfrom
som-snytt:issue/9076-2.12

Conversation

@som-snytt
Copy link
Contributor

The PR title reminds me of Whitney Houston's infamous declaration, "Crack is whack."

This updates #4311 for 2.12.

Avoid class initialization traps in the object wrapper by
extending App.

Previously, the following line would hang in the REPL
because the parallel operation was started from the constructor
of the wrapping object, i.e., from the static initializer of
the class. Class-loading the closure would deadlock on loading
the wrapper, which in turn blocks on completion of the par.map.

```
scala> def i = 42 ; List(1, 2, 3).par.map(x => x + i)
```

Any user code that starts a thread could deadlock, including
innocent experiments with Futures in for comprehensions.

The App object is initialized in the usual place, namely
the print method of the eval object, by invoking main.
(A lazy `compute` accommodates two paths of evaluation:
`print` for REPL, `result` for script engine.)

A compiler option `-YreplWrap` takes values "class", "object"
and "app" (default) to select the wrapper template.

```
scala> 42 // show
object $read extends scala.AnyRef {
  def <init>() = {
    super.<init>;
    ()
  };
  object $iw extends App {
    def <init>() = {
      super.<init>;
      ()
    };
    val res0 = 42
  };
}
[[syntax trees at end of                     typer]] // <console>
package $line3 {
  object $read extends scala.AnyRef {
    def <init>(): $line3.$read.type = {
      $read.super.<init>();
      ()
    };
    object $iw extends AnyRef with App {
      def <init>(): type = {
        $iw.super.<init>();
        ()
      };
      private[this] val res0: Int = 42;
      <stable> <accessor> def res0: Int = $iw.this.res0
    }
  }
}

[[syntax trees at end of                     typer]] // <console>
package $line3 {
  object $eval extends scala.AnyRef {
    def <init>(): $line3.$eval.type = {
      $eval.super.<init>();
      ()
    };
    <stable> <accessor> lazy def compute: Unit = $line3.$read.$iw.main(null);
    lazy private[this] var $result: Int = _;
    <stable> <accessor> lazy def $result: Int = {
      $eval.this.$result = {
        $eval.this.compute;
        $line3.$read.$iw.res0
      };
      $eval.this.$result
    };
    lazy private[this] var $print: String = _;
    <stable> <accessor> lazy def $print: String = {
      $eval.this.$print = {
        $eval.this.compute;
        "res0: Int = ".+(scala.runtime.ScalaRunTime.replStringOf($line3.$read.$iw.res0, 1000))
      };
      $eval.this.$print
    }
  }
}

res0: Int = 42

```
`-Yrepl-wrap:object` is the default.
Now `valueOfTerm` drills down reflectively using
the `fullName` of the desired symbol.

It respects a prefix of static modules, but switches
to instance mirrors as required.

The target is an accessor on the last enclosing instance.
@scala-jenkins scala-jenkins added this to the 2.12.0-M1 milestone Feb 20, 2015
@som-snytt
Copy link
Contributor Author

Check reduced nesting against the behavior in https://issues.scala-lang.org/browse/SI-9208 ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants