Skip to content
This repository was archived by the owner on Sep 1, 2020. It is now read-only.

@reorderable vals as an alternative to lazy vals #20

Closed
propensive opened this issue Sep 5, 2014 · 6 comments
Closed

@reorderable vals as an alternative to lazy vals #20

propensive opened this issue Sep 5, 2014 · 6 comments

Comments

@propensive
Copy link

As @paulp points out, most lazy vals don't need to be double-locked lazy vals because it's only used as a cheap (lazy?) way of guaranteeing safe initialization order, but comes with a performance cost for every subsequent access. In many cases static analysis could avoid this by choosing a safe initialization order at compile time.

@reorderable would be used in place of lazy for these cases, and the compiler would generate warnings (or errors?) where the dependencies can't be determined statically.

aloiscochard pushed a commit to aloiscochard/scala that referenced this issue Sep 5, 2014
Use _2.11 as the snapshot binary version, rather then _2.11.0.
@odersky
Copy link

odersky commented Sep 6, 2014

Note that we plan to fix this in Don Giovanni the other way round. lazy will mean single-threaded access. You will need to write @volatile lazy if you want to cater to multi-threaded access. The source rewriting tool will rewrite all existing occurrences of lazy to @volatile lazy, unless it can prove that access is single-threaded.

@ijuma
Copy link

ijuma commented Sep 6, 2014

@odersky, is it really wise to make the safe case more verbose (@volatile lazy) than the unsafe one (lazy)? Particularly given that developers have been trained to expect lazy val to be as safe as val in the face of concurrent access (lazy vals can cause deadlocks but vals can cause NPEs due to initialisation order).

@propensive
Copy link
Author

I think changing the default behavior is fine, but it's only justified with a rewriting tool, which doesn't exist yet...

@ijuma
Copy link

ijuma commented Sep 7, 2014

Note that supporting multiple Scala versions will be harder even with the source rewriting tool. Anyway, my main concern is making things less safe for questionable benefit. With Invokedynamic, it's possible to avoid the volatile read after the value is initialised.

Having said that, I like the ideas being discussed in #10.

@aryairani
Copy link

@odersky +1 for having the safe case be the default, if reusing existing keywords.
A source-rewriting tool is nice; but to @ijuma's point, a brain-rewriting tool is needed here.

We're off-topic though, and @propensive's point is still good.

folone pushed a commit that referenced this issue Aug 14, 2015
Calls to synthetic case class apply methods are inlined to the
underlying constructor invocation in refchecks.

However, this can lead to accessibility errors if the constructor
is private.

This commit ensures that the constructor is at least as accessible
as the apply method before performing this tranform.

I've manually checked that other the optimization still works in other
cases:

scala> class CaseApply { Some(42)  }
defined class CaseApply

    scala> :javap -c CaseApply
    Compiled from "<console>"
    public class CaseApply {
      public CaseApply();
        Code:
           0: aload_0
           1: invokespecial #9                  // Method java/lang/Object."<init>":()V
           4: new           #11                 // class scala/Some
           7: dup
           8: bipush        42
          10: invokestatic  #17                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
          13: invokespecial #20                 // Method scala/Some."<init>":(Ljava/lang/Object;)V
          16: pop
          17: return
    }
milessabin pushed a commit that referenced this issue Aug 12, 2016
This corrects an error in the change to the trait encoding
in scala#5003: getters in traits should have empty bodies and
be emitted as abstract.

```
% ~/scala/2.12.0-M4/bin/scalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public int x();
    Code:
       0: aload_0
       1: invokeinterface #15,  1           // InterfaceMethod x:()I
       6: ireturn

  public int y();
    Code:
       0: aload_0
       1: invokeinterface #20,  1           // InterfaceMethod y:()I
       6: ireturn

  public void y_$eq(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokeinterface #24,  2           // InterfaceMethod y_$eq:(I)V
       7: return

  public void $init$();
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface #29,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface #24,  2           // InterfaceMethod y_$eq:(I)V
      16: return
}

% qscalac sandbox/test.scala && javap -c T
Compiled from "test.scala"
public interface T {
  public abstract void T$_setter_$x_$eq(int);

  public abstract int x();

  public abstract int y();

  public abstract void y_$eq(int);

  public static void $init$(T);
    Code:
       0: aload_0
       1: bipush        42
       3: invokeinterface #21,  2           // InterfaceMethod T$_setter_$x_$eq:(I)V
       8: aload_0
       9: bipush        24
      11: invokeinterface #23,  2           // InterfaceMethod y_$eq:(I)V
      16: return

  public void $init$();
    Code:
       0: aload_0
       1: invokestatic  #27                 // Method $init$:(LT;)V
       4: return
}
```
@milessabin
Copy link
Member

To resurrect this issue, please rework it as an issue/PR against Lightbend Scala (ie. scala/scala).

@milessabin milessabin added this to the Parked milestone Aug 12, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants