Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static method of object disappears after compilation #7225

Open
scabug opened this issue Mar 7, 2013 · 6 comments
Open

Static method of object disappears after compilation #7225

scabug opened this issue Mar 7, 2013 · 6 comments

Comments

@scabug
Copy link

scabug commented Mar 7, 2013

Using this very simple piece of code

    import java.util.Properties

    class MyProperties extends Properties

    object MyProperties {
    
        def get(): MyProperties = new MyProperties
    
        def anotherMethod(): MyProperties = new MyProperties
    
    }

the get() method is missing in the compiled code; a Java decompilation of the MyProperties class yields (scala signature omitted)

    import java.util.Properties;
    import scala.reflect.ScalaSignature;

    public class MyProperties extends Properties
    {
      public static MyProperties anotherMethod()
      {
        return MyProperties..MODULE$.anotherMethod();
      }
    }

If MyProperties does not extend java.util.Properties however, the get() method is generated.

java.util.Properties inherits the public V get(Object key) from java.util.Dictionary but that is a non static method with a different signature and this "works" in Java

    import java.util.Properties;

    public class MyPropertiesjava extends Properties {
  
        private static final long serialVersionUID = 1L;
	
        public static MyProperties get() {
    	
    	    return new MyProperties();
        }
    
        public static MyProperties antotherMethod() {
    	
    	    return new MyProperties();
        }
    }

A suggested workaround using type (author Régis Jean-Gilles) is stated below, but there does not seem to be a JVM related reason no to generate the get method

    import java.util.Properties

    type MyProperties = MyPropertiesImpl

    class MyPropertiesImpl extends Properties

    object MyProperties {    
        def get(): MyProperties = new MyPropertiesImpl
        def anotherMethod(): MyProperties = new MyPropertiesImpl
    }

(sorry for the lack of rendered formatting)

@scabug
Copy link
Author

scabug commented Mar 7, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7225?orig=1
Reporter: Bruno Grieder (bgrieder)
Affected Versions: 2.10.0, 2.10.1-RC2, 2.10.1

@scabug
Copy link
Author

scabug commented Mar 12, 2013

@adriaanm said:
This is due to a Java limitation. In your original code, there's an inherited get method from HashTable that differs only in result type. http://stackoverflow.com/questions/9439379/why-does-java-enforce-return-type-compatibility-for-overridden-static-methods

Please experiment with variations on the following minimal example to see the error more directly.

class Super {
  // uncomment this and comment the last definition of get for the original report
  // def get(): Any = null
}

class Foo extends Super

object Foo {
  // no static forwarder generated in Foo when there's already one in Super
  def get(): Foo = new Foo
  // can't have two static methods with signatures that differ only in their return type
  def get(): Any = null
}

@scabug
Copy link
Author

scabug commented Mar 13, 2013

Bruno Grieder (bgrieder) said (edited on Mar 13, 2013 4:38:24 PM UTC):
I re-open this because get() is NOT a static method on HashMap. What you describe is true for static methods collisions only.

Actually, this is exactly the opposite: it is a Scala limitation; java does not have this limitation. For proof consider this

In Scala

import java.util.HashMap

class HashMapScala extends HashMap[ String, String ] {

}

object HashMapScala {
    
    def get() : String = "dummy"
}

In java

import java.util.HashMap;


public class HashMapJava extends HashMap<String, String> {

    private static final long serialVersionUID = 1L;

	public static String get() {
		
		return "dummy";
	}
}

In java, the static get() method is available in the the compiled code along with the non static get() method inherited from Hashmap.
The static get() method is not available in the compiled code generated by the Scala compiler.

My bet is that the scala compiler only checks for method name collisions but does not check, as it should and javac does, for the methods signature: method name AND arguments. Only in the latter case you cannot have both a static and non static method generated.

@scabug
Copy link
Author

scabug commented Mar 13, 2013

@retronym said:
Yes, that's what it does:

https://github.com/scala/scala/blob/v2.10.0/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala#L1161

The method is accessible to Java via MyProperties.MODULE$.get().

@scabug
Copy link
Author

scabug commented Mar 14, 2013

Bruno Grieder (bgrieder) said (edited on Mar 14, 2013 6:00:36 AM UTC):
I am no going to discuss the fact that it has been moved to Minor (your choice) but just want to make you aware of the consequences of this issue.

When you port Java code to Scala you may be caught in a situation where you have to port a Java Class that implements such a static method - and you can't. This is exactly what happened to us. You are then left with 2 choices if you want avoid breaking the rest of the code

  • implement the type workaround described above, and since the Object and Class have different names, hope that the rest of the code never tries to cast to the Object name when doing a get e.g; in Java : (MyMap) MyMap.get
  • refactor the rest of the code to either import the type or completely change the name of the static get() method

Unfortunately, you cannot always refactor the rest of the code and you are just doomed.
One of the big marketing stints of Scala is that it is completely inter-operable with Java; well, as we discovered, not completely, no.

@scabug
Copy link
Author

scabug commented Mar 14, 2013

@adriaanm said:
Bruno, thanks for bearing with us. I'm sorry your porting experience was less than ideal.

We're aware that Scala's approach to static methods is not ideal in the context of java interop. We've recently been discussing a new approach for code generation of methods in objects: https://groups.google.com/d/msg/scala-internals/vOps4k8CADY/-1k-08KRBzkJ

I agree our interop story needs work here, so I've adjusted the priority.

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

No branches or pull requests

1 participant