オーバーロードされたメソッドの曖昧さを Scala で明示的に解決するには?


Java のライブラリに用意されているオーバーロードされたメソッドを Scala で利用しようとしています。

[code]

    class X{
      public <E> void f(E... values){ System.out.println(1); }
      public void f(Object value){ System.out.println(2); }
    }
    
[/code]

しかし Scala ではパラメータの型に互換性がある場合、オーバーロードされたメソッドのどれを使って良いか解決することができずコンパイルエラーが発生します。

[code]

    val x = new X()
    x.f("foo")
    
[/code]

[code]

    error: ambiguous reference to overloaded definition,
    both method f in class X of type (value: Any)Unit
    and  method f in class X of type [E](values: E*)Unit
    match argument types (String)
    
[/code]

呼び出し時のパラメータ部分を `"foo":Object` や `"foo".asInstanceOf[Object]`
などにしても状況に変化はありません。回避策としてリフレクションを使用することはできます。

[code]

    classOf[X].getMethod("f", classOf[Object]).invoke(x, "foo")  // => 2
    
[/code]

根本的に、Scala で 2. 側のメソッドを明示的に呼び出すにはどうすれば良いでしょうか?

Java 11.0.2 / Scala 2.12.8




おそらくですが、Scalaから`setDefault(Object value)`のメソッドを呼び出すことはできません。

dotty(Scala 3.x)では、何かしらの方法により、可能になるかもしれません(?)。  
<https://github.com/lampepfl/dotty/issues/5792>

とりあえず、妥協案が3つほど考えられます。  
(リフレクションで呼び出す方法は質問文に書かれていますので除きました)

**妥協案 1: 他のライブラリの使用を検討する**

  * <https://stackoverflow.com/questions/2315912/best-way-to-parse-command-line-parameters>
  * <https://stackoverflow.com/questions/8112879/scala-command-line-parser-with-subcommand-support>

**妥協案 2:`setDefault(E... value)`のメソッドを呼び出す**

こちらのメソッドであれば、以下のようなコードで呼び出すことができる気がします。

[code]

    arg.setDefault(Seq("foo"): _*)
    
[/code]

ただし、ヘルプで表示されるデフォルト値が、以下のような表示になるかと思います。  
(余計な`[]`が付いてしまう)

[code]

    (default: [foo])
    
[/code]

**妥協案 3: Javaでヘルパーclassを書き、Scalaで使用する**

argparse4jのScalaラッパーである[mdekstrand/argparse4s](https://github.com/argparse4j/argparse4j)で使用されている方法ですが、`src/main/java`配下に

`public static void setDefault(Argument arg, Object dft)`

というメソッドを持つヘルパーclassを定義しておき、このJavaのclassをScalaから使用します。

[`/src/main/java/net/elehack/argparse4s/ArgConfig.java`](https://github.com/mdekstrand/argparse4s/blob/a9178bbdb90888e706da62ac06ac3aaabf07d909/src/main/java/net/elehack/argparse4s/ArgConfig.java)

[code]

    package net.elehack.argparse4s;
    
    import net.sourceforge.argparse4j.inf.Argument;
    
    class ArgConfig {
        public static void setDefault(Argument arg, Object dft) {
            arg.setDefault(dft);
        }
    }
    
[/code]

※このScalaラッパーライブラリ自体は、2019年現在メンテされていないようです

