質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.86%

  • Java

    12465questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Kotlin

    184questions

    Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

  • Generics

    15questions

    Genericsはパラメトリックなポリモーフィズムの形態であり、.NET やJavaなど、様々な言語に実装されています。C++のテンプレートと同等の機能を持ち合わせています。

KotlinからJavaのメソッドを呼ぶ際のジェネリクス変性について

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 154

mosa

score 199

いつもありがとうございます。

http://jenetics.io/
こちらにあるJavaのコードをkotlinで記述しようと思っています。

// 2.) Definition of the fitness function.
fun eval(gt: Genotype<BitGene>): Int {
  return gt.chromosome
      .`as`(BitChromosome::class.java)
      .bitCount()
}

fun main(vararg args: String) {

  // 1.) Define the genotype (factory) suitable for the problem.
  val gtf = Genotype.of(BitChromosome.of(10, 0.5))

  // 3.) Create the execution environment.
  val engine = Engine.builder({ gf: Genotype<BitGene> -> eval(gf) }, gtf)

  // 4.) Start the execution (evolution) and collect the result.
  val result = engine.stream()
      .limit(100)
      .collect(EvolutionResult.toBestGenotype())

  println("Hello World:\n$result")

}

「3.」のEngine.builder の部分でコンパイルエラーとなっています。
エラーは以下の通りです。

エラー

呼び出し先のメソッドの定義は以下の通りです。

public static <G extends Gene<?, G>, C extends Comparable<? super C>> Engine.Builder<G, C> builder(Function<? super Genotype<G>, ? extends C> ff, Factory<Genotype<G>> genotypeFactory) {
  return new Engine.Builder(genotypeFactory, ff);
}

ラムダ式  { gf: Genotype<BitGene> -> eval(gf) } の型は (Genotype<BitGene>) -> Int) です。

JavaとKotlinのジェネリクス変性について私が理解できていないか、理解が誤っていることが原因だと思うのですが、何が問題でどう記述するのが正しいかがわかりません。
ちょっと複雑なので混乱しているだけかもしれません。
ご教示いただければと思います。

Kotlin: 1.2.31
Java: 1.8.0_152-release-1136-b27 amd64
IntelliJ IDEA 2018.1.1 (Ultimate Edition) Build #IU-181.4445.78
Windows10 


■追記1

「3.」の部分を以下のように書き換えたところ、コンパイルは通ったのですが、実行時に以下のエラーとなってしまいました。

val engine = Engine.builder(java.util.function.Function { gf: Genotype<BitGene> -> eval(gf) }, gtf).build()

IDEが出力したエラー

Error:Kotlin: [Internal Error] org.jetbrains.kotlin.codegen.CompilationException: Back-end (JVM) Internal error: Error type encountered: (???..???) (FlexibleTypeImpl).
Cause: Error type encountered: (???..???) (FlexibleTypeImpl).
File being compiled at position: (26,3) in C:/Users/mosa/Documents/hoge/src/main/java/HelloWorld.kt
The root cause was thrown at: KotlinTypeMapper.java:122
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:328)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genStatement(ExpressionCodegen.java:372)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.generateBlock(ExpressionCodegen.java:1193)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.generateBlock(ExpressionCodegen.java:1138)
    at org.jetbrains.kotlin.codegen.CodegenStatementVisitor.visitBlockExpression(CodegenStatementVisitor.java:56)
    at org.jetbrains.kotlin.codegen.CodegenStatementVisitor.visitBlockExpression(CodegenStatementVisitor.java:22)
    at org.jetbrains.kotlin.psi.KtBlockExpression.accept(KtBlockExpression.java:44)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:307)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genStatement(ExpressionCodegen.java:372)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:338)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.returnExpression(ExpressionCodegen.java:1590)
        ・
        ・
        ・

■追記2

「3.」の部分を以下のように書き換えたところ、追記1と同じ現象になってしましました。

  val func: java.util.function.Function<Genotype<BitGene>, Int> = java.util.function.Function { gf: Genotype<BitGene> -> eval(gf) }
  val engine = Engine.builder(func, gtf).build()

■追記3

元の問題についてはだいぶわかりました。変性は関係ありませんでした。
当たり前なのかもしれませんが、 Java の Function を引数にとるメソッドに Kotlin のラムダ式を渡そうとしても型が違うのでコンパイルが通らない、ということを理解していませんでした。

// これの型は (Genotype<BitGene>) -> Int
val hoge = { gf: Genotype<BitGene> -> eval(gf) }

// これの型は java.util.function.Function<Genotype<GitGene>, Int>
val piyo = java.util.function.Function { gf: Genotype<BitGene> -> eval(gf) }

■追記4

KSwordOfHasteさんに教えていただいた結果、動作するようにできました。
ご指摘のとおり、kotlinのコンパイラのバグのようです。
Collectorのメソッド型引数を明示的にすることで CompilationException 発生しなくなりました。

// 2.) Definition of the fitness function.
fun eval(gt: Genotype<BitGene>): Int {
  return gt.chromosome
      .`as`(BitChromosome::class.java)
      .bitCount()
}

fun main(vararg args: String) {

  // 1.) Define the genotype (factory) suitable for the problem.
  val gtf = Genotype.of(BitChromosome.of(10, 0.5))

  // 3.) Create the execution environment.
  val engine = Engine.builder(java.util.function.Function<Genotype<BitGene>, Int> { eval(it) }, gtf).build()

  // 4.) Start the execution (evolution) and collect the result.
  val result = engine.stream()
      .limit(100)
      .collect(EvolutionResult.toBestGenotype<BitGene, Int>())

  println("Hello World:\n$result")

}

ちなみに結果は以下のようになり、遺伝的アルゴリズムにより10個体100世代で10bitのうち最もビットが立つものを探索する、というものでした。

Hello World:
[00000011|11111111]

ありがとうございました。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • mosa

    2018/04/16 20:08

    もうちょっとかかります。すみません。

    キャンセル

  • mosa

    2018/04/17 17:11

    別のPCで「追記1」「追記2」を実行してみましたが、同じようにCompilationExceptionが発生してしまいました。 元の問題についてはご指摘いただいたように型を詳しく調べたらだいぶ理解できてきました。ありがとうございます。 「追記3」に記載しました。私のところだけPCを変えてもCompilationExceptionが発生してしまう理由はまだわかりません。

    キャンセル

  • mosa

    2018/04/17 22:41

    追記4を記載しました。ありがとうございました。

    キャンセル

回答 1

checkベストアンサー

+2

追記2の方ですが当方でも再現しました。

そのまま載せても見づらいので、横長にはなりますがコードタグで囲みます。

Information:Kotlin: kotlinc-jvm 1.2.31 (JRE 1.8.0_162-b12)
Information:2018/04/17 17:52 - Compilation completed with 1 error and 0 warnings in 29 s 830 ms
Error:Kotlin: [Internal Error] org.jetbrains.kotlin.codegen.CompilationException: Back-end (JVM) Internal error: Error type encountered: (???..???) (FlexibleTypeImpl).
Cause: Error type encountered: (???..???) (FlexibleTypeImpl).
File being compiled at position: (28,5) in C:/idea2016-3/KotTest2/src/g/gg.kt
The root cause was thrown at: KotlinTypeMapper.java:122
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:328)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.genStatement(ExpressionCodegen.java:372)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.generateBlock(ExpressionCodegen.java:1193)
    at org.jetbrains.kotlin.codegen.ExpressionCodegen.generateBlock(ExpressionCodegen.java:1138)
...省略

Caused by: java.lang.IllegalStateException: Error type encountered: (???..???) (FlexibleTypeImpl).
    at org.jetbrains.kotlin.codegen.state.KotlinTypeMapper$1.processErrorType(KotlinTypeMapper.java:122)
    at org.jetbrains.kotlin.load.kotlin.TypeSignatureMappingKt.mapType(typeSignatureMapping.kt:104)
         ^^^^^^ 多分ここで何かまずいことが起きた

    at org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.mapType(KotlinTypeMapper.java:436)

    at org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.writeGenericArguments(KotlinTypeMapper.java:585)
    at org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.writeGenericArguments(KotlinTypeMapper.java:559)
    at org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.writeGenericType(KotlinTypeMapper.java:501)

当方の再現確認でコンパイラーが死んでしまったのは

File being compiled at position: (28,5) in C:/idea2016-3/KotTest2/src/g/gg.kt

と出ていることから28行目です。そこに書かれているのは以下の行です。

val result = engine.stream()
        .limit(100)
        .collect(EvolutionResult.toBestGenotype())

GitHubには大分先のバージョン(1.3.50)のソースのためか例外が起きたあたりのソースの行番号はずれずれですが、Kotlinの型をJavaの型へマッピングするようなところなのかなぁと何となくですが想像しました。おそらくcollectの結果の型を料理する過程で何かがおきたんじゃないでしょうか。

いずれにせよコンパイラーのバグに思えるので対処は「それが起きないような平易な書き方を探る」ということになると思います。

賢く型推論をしてくれたりするコンパイラーはありがたいはありがたいのですが、コンパイラーがバグっていたのではしかたありません。ガチガチの書き方にしてみてください。例えばtoBestGenotypeに明示的に型引数を指定して見たらどうでしょうか?

残念ながら自分はこのライブラリー(遺伝的アルゴリズムの計算ライブラリーでしょうか?)について何も知らないので、質問者さんがresultにどういう型を期待しておられるのかがわからず、これ以上は試せてません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/17 19:08

    本件には直接からまないかも知れませんが・・・
    { x -> f(x) }
    は冗長な気がします。それよりは(コンパイラーが元気に動いてくれるなら)
    ::f
    と書いた方がよいのではないでしょうか。

    キャンセル

  • 2018/04/17 22:40 編集

    ご指摘の通り調べたところ動くようになりました。「追記4」に記載しました。
    { x -> f(x) } に関しては型推論可能なはずですがしてくれないためラムダ式の引数の型を明示するためにああしていました。
    あのように書くかもしくは、「追記4」のように型引数を明示する形になると思います。
    (kotlinに ::f といった記法はないですよね?)
    とても助かりました。ありがとうございました。

    キャンセル

  • 2018/04/17 22:44

    > kotlinに ::f といった記法はないですよね?
    ちゃんと調べてはないですが
    var x = ::eval
    と書けて、IDEAによれば型はKFunction1<Genotype<BitGene>, Int>らしいので(JavaのFunctionalInterfaceとは相性が悪いかも知れませんが)Kotlin自体での使い方としては
    { x => f(x) }
    でも
    ::f
    でも同じだと思えました。

    キャンセル

  • 2018/04/17 22:55

    あ、 FunctionalInterfaceと互換性がないだけで kotlin に ::f という記法はあるんですね。すみません。知りませんでした。
    ありがとうございます。

    キャンセル

  • 2018/04/17 23:05

    横からですが、コンパイラのバグなら、ココらへんに報告したら、あとあとバグ修正されるかもしれません。
    https://youtrack.jetbrains.com/issues/KT?q=CompilationException

    キャンセル

  • 2018/04/17 23:40 編集

    umyuさん提案に賛成です。ただ、本件の質問の内容では若干不足と思います。関連する全ての型宣言が書かれてないからです(本来はoverloadされているメソッドも含めて関係する宣言全部を書くべきと思います)。自分はその辺り不明だったのでjeneticsをmavenから引っ張ってきて再現させましたが報告する場合はできるだけjeneticsを使わない簡単な再現コードを作った方が先方の対処が早い気がします。jeneticsを使うならバージョンを明記すべきと思います。

    キャンセル

  • 2018/04/18 19:20

    ありがとうございます。InteliJの IDE Fatal Error Report からは報告済みです。(どこに反映されているのかがよくわかっていませんが。。)jenetics.io を抜いた状態で再現する最小のコードがわかりましたら報告してみます。

    キャンセル

  • 2018/04/19 00:22

    >>KSwordOfHasteさんへ
    コメント欄をお借りして失礼しました。返信ありがとうございました。

    >>mosaさんへ
    Issue Trackerへの登録報告ありがとうございました。

    キャンセル

  • 2018/04/19 13:53

    こちらこそありがとうございます。かなり先になるかと思いますが、バグの解消を確認、もしくはバグが再現する最小コードがわかりましたら、こちらにもご報告しようかと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    インスタンス化しないようにする[kotlin]

    前提・実現したいこと javaのようにユーティリティクラスを書くには? 結論 object(Singleton)であれcompanion objectであれ参照が渡される

  • 解決済

    Kotlin(Java?)でのArrayListへの要素の追加についての質問です

    実行環境はKotlin ver1.0.6でJava8です ArrayListを使い,要素の追加・取り出しを行いたいのですが うまくいきません for文の中でmodelをMod

  • 解決済

    RxAndroid エラーについて

    某入門書を購入して写経をしているのですがRxAndroidでつまづいてしまいました。 observeOnのAndroidSchedulers でunresolve refe

  • 解決済

    valとvarのイニシャライザに対する仕様の違い

    var allByDefault: Int? // エラー:明示的なイニシャライザが必要 val simple: Int? // エラーは出ない。コンストラクタ内で初期化が必要

  • 受付中

    kotlinでparcelable

    ArrayList<Any>にparcelableを実装する方法が分かりません。 作成したリストの中にはString型と独自に作成したクラス(UploadedItem)が入っていま

  • 解決済

    Kotlinの型チェックについて

    初歩的な質問です。 Kotlinのwhen文でisを使った型チェックを学んでいるのですが、when文を学習中に下記のコードでよくわからなくなっていて困っています。 (Kotlinに

  • 解決済

    int型またはlong型の文字列変換時の桁区切りについて

    前提・実現したいこと Javaで実装されている既存コードをKotlinへ変換しようとしています。 その際にJavaで実装されたUtilクラスを整理しようとした際に、 以下のint型

  • 解決済

    スレッドセーフで高速なLRUキャッシュ

    いつもありがとうございます。 Kotlin、もしくはJavaで以下の要件を満たすプログラムを考えています。  ■要件 1.与えられたキーに対して処理を行い結果を返す。 2.一度

同じタグがついた質問を見る

  • Java

    12465questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Kotlin

    184questions

    Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

  • Generics

    15questions

    Genericsはパラメトリックなポリモーフィズムの形態であり、.NET やJavaなど、様々な言語に実装されています。C++のテンプレートと同等の機能を持ち合わせています。