Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: get default values without creating an object

Suppose there is a class with default values in constructor:

class Adapter(url: String = "127.0.0.1", port: Int = 8080)

Is it possible to get default values for those parameters in runtime without creating an instance of this object?

Please do not ask about a use-case, this is more a question about the language itself.

like image 271
Artem Oboturov Avatar asked Feb 08 '23 08:02

Artem Oboturov


1 Answers

I am assuming that you are mostly interested in how default methods are implemented internally. Here is the javap disassembly of your code (using the very helpful :javap <classname> scala console command:

scala> class Adapter(url: String = "127.0.0.1", port: Int = 8080)
defined class Adapter

scala> :javap -c Adapter$ // Adapter$ because we want the companion object
Compiled from "<console>"
public class Adapter$ {

  ... 

  public java.lang.String $lessinit$greater$default$1();
    Code:
       0: ldc           #16                 // String 127.0.0.1
       2: areturn       

  public int $lessinit$greater$default$2();
    Code:
       0: sipush        8080
       3: ireturn       

  ...

As you can see, the methods that create the default values are encoded as specially named methods in the companion object. So to invoke these methods without restructuring the example, you would have to use reflection:

scala> Adapter.getClass.getMethod("$lessinit$greater$default$1").invoke(Adapter) 
res8: Object = 127.0.0.1

scala> Adapter.getClass.getMethod("$lessinit$greater$default$2").invoke(Adapter) 
res9: Object = 8080

Obviously it is probably not a good idea to do this in production code, since the name mangling details etc. might change. Just use the suggestion from @Sparko in that case.

A note about the name mangling scheme: The scheme is methodName + "$default$" + parameterNumber. The method to be decorated in the case above is the constructor, which is "<init>". So you end up with e.g. "$lessinit$greater" for the method name and "$lessinit$greater$default$0" for the name of the method to calculate the default value of the first argument.

like image 145
Rüdiger Klaehn Avatar answered Feb 10 '23 22:02

Rüdiger Klaehn