You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(This suggestion originated on the mailing list. After some feedback, I converted it into a ticket)
This suggestion is a potential compiler optimization. If implemented properly, it should not change the behavior of any existing scala code, nor introduce any change in scala syntax.
Background:
The scala object system improves on java statics in that it allows for "scoped" statics. That is, singletons which can be globally scoped, scoped to a class, or even a method.
objects defined at the same scope as java statics are implemented using a static MODULE$$ instance of a generated version of the object class (i.e. an object called MyObject will be renamed MyObject$$. The compiler then generates a new class MyObject, and for every method in the original MyObject, the compiler generates a static method which forwards the call to the corresponding method on the static MODULE$$.
The MODULE$$ instance is instantiated in a static constructor section in MyObject$$, so the first code to reference an object method in MyObject will instantiate MODULE$$.
There are two problems with this:
The first is trivial. This implementation means that object methods defined at the same scope as static methods in java will always have a small amount of overhead. However, the overhead is small in and of itself.
The second, less trivial problem is that this implementation causes byte-code optimization tools, such as ProGuard, and possibly the VM itself, to consider every object method as a method which produces a global side effect, namely the instantiation of the static MODULE$$ field. Because of this, these tools consider it unsafe to perform additional optimizations on these methods.
For example, proguard can do algebraic reductions and peephole optimizations on bytecode. If it can inline adjacent calls to static methods (for example, various calls to java.Math static methods), it can perform these optimizations across method call boundaries.
However, because all scala object methods have at least one side-effect outside the body of the methods themselves, it cannot safely inline them, and therefor it cannot perform optimizations across adjacent method calls by inlining them and looking for further reductions. The potential performance gains of such optimizations are of course dependent on the code being optimized, but in some cases may be significant.
The suggestion:
Where it is safe to do so (when there is no externally visible side-effect other than the instantiation of MODULE$$), the scala compiler should implement the methods defined in objects at the static scope as static methods. The methods of the singleton's class would then forward those calls to the static methods, instead of the other way around.
Example:
Given the following scala code (a contrived example):
objectMyObject {
varfield=0defmethod= field *2
}
Would be compiled into the following:
public finalclassMyObject {
public static int field =0;
public static int field() { return field; }
public static void field_eq$$(int value) { field = value; }
public static int method() { returnMyObject.field() *2; }
}
public finalclassMyObject$$extendsScalaObject {
public static finalMODULE$$;
static { new(); }
int field() { returnMyObject.field(); }
void field_eq$$(int value) { MyObject.field_eq$$(value); }
int method() { returnMyObject.method(); }
}
And, the following client code which uses MyObject:
public finalclassClientCode {
public static void clientMethod() {
MyObject.field_eq$$(MyObject.method());
}
}
// ClientCode$$ not shown
This optimization should be done on a case-by-case basis. For example, in the following code, method cannot be promoted to a static method, because the object's constructor has a visible side-effect:
objectMyObjectWithSideEffect {
// there is no benefit to putting this prinln in// a static section of the static MyObjectWithSideEffect class
println("I'm a side effect!")
// So this method might as well be implemented in the// MyObjectWithSideEffect$$ singleton class.defmethod= println("The above println must execute before I do")
}
Also, this would not apply to methods in objects defined at any other scope except for the static scope (although it may be possible to promote such a method to a static method, if it can be determined that it is side-effect free. However, that's beyond the scope of this suggestion).
And finally, if an object is defined as a subclass of another object (aside from ScalaObject, implicitly), or mixes in a trait, it may be more difficult to prove that it has no externally visible side-effects (you have to check each base class constructor). Not impossible, but not trivial either. As a short-cut, it is ok to simply turn off this optimization for methods defined in objects such as this:
objectMyObjectextendsBaseClasswithSomeTrait {...}
The text was updated successfully, but these errors were encountered:
@dragos said:
This is out of scope for a ticket, it is really a SID. It would be interesting to see this developed further, so please start a SID document.
DaveScala (davescala) said:
Will there also be a compiler option to turn this optimization off, for instance:[[BR]]
-nso (no static optimization)[[BR]]
[[BR]]
In this way it easier to compare performance and also to track in which part of the compiler a bug occurs.
(This suggestion originated on the mailing list. After some feedback, I converted it into a ticket)
This suggestion is a potential compiler optimization. If implemented properly, it should not change the behavior of any existing scala code, nor introduce any change in scala syntax.
Background:
The scala object system improves on java statics in that it allows for "scoped" statics. That is, singletons which can be globally scoped, scoped to a class, or even a method.
objects defined at the same scope as java statics are implemented using a static MODULE$$ instance of a generated version of the object class (i.e. an object called MyObject will be renamed MyObject$$. The compiler then generates a new class MyObject, and for every method in the original MyObject, the compiler generates a static method which forwards the call to the corresponding method on the static MODULE$$.
The MODULE$$ instance is instantiated in a static constructor section in MyObject$$, so the first code to reference an object method in MyObject will instantiate MODULE$$.
There are two problems with this:
The first is trivial. This implementation means that object methods defined at the same scope as static methods in java will always have a small amount of overhead. However, the overhead is small in and of itself.
The second, less trivial problem is that this implementation causes byte-code optimization tools, such as ProGuard, and possibly the VM itself, to consider every object method as a method which produces a global side effect, namely the instantiation of the static MODULE$$ field. Because of this, these tools consider it unsafe to perform additional optimizations on these methods.
For example, proguard can do algebraic reductions and peephole optimizations on bytecode. If it can inline adjacent calls to static methods (for example, various calls to java.Math static methods), it can perform these optimizations across method call boundaries.
However, because all scala object methods have at least one side-effect outside the body of the methods themselves, it cannot safely inline them, and therefor it cannot perform optimizations across adjacent method calls by inlining them and looking for further reductions. The potential performance gains of such optimizations are of course dependent on the code being optimized, but in some cases may be significant.
The suggestion:
Where it is safe to do so (when there is no externally visible side-effect other than the instantiation of MODULE$$), the scala compiler should implement the methods defined in objects at the static scope as static methods. The methods of the singleton's class would then forward those calls to the static methods, instead of the other way around.
Example:
Given the following scala code (a contrived example):
Would be compiled into the following:
And, the following client code which uses MyObject:
Would be compiled down to:
This optimization should be done on a case-by-case basis. For example, in the following code, method cannot be promoted to a static method, because the object's constructor has a visible side-effect:
Also, this would not apply to methods in objects defined at any other scope except for the static scope (although it may be possible to promote such a method to a static method, if it can be determined that it is side-effect free. However, that's beyond the scope of this suggestion).
And finally, if an object is defined as a subclass of another object (aside from ScalaObject, implicitly), or mixes in a trait, it may be more difficult to prove that it has no externally visible side-effects (you have to check each base class constructor). Not impossible, but not trivial either. As a short-cut, it is ok to simply turn off this optimization for methods defined in objects such as this:
The text was updated successfully, but these errors were encountered: