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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Generics

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

Java

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

Kotlin

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

Q&A

解決済

1回答

708閲覧

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

mosa

総合スコア218

Generics

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

Java

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

Kotlin

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

0グッド

2クリップ

投稿2018/04/15 08:18

編集2018/04/17 13:35

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

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

Kotlin

1// 2.) Definition of the fitness function. 2fun eval(gt: Genotype<BitGene>): Int { 3 return gt.chromosome 4 .`as`(BitChromosome::class.java) 5 .bitCount() 6} 7 8fun main(vararg args: String) { 9 10 // 1.) Define the genotype (factory) suitable for the problem. 11 val gtf = Genotype.of(BitChromosome.of(10, 0.5)) 12 13 // 3.) Create the execution environment. 14 val engine = Engine.builder({ gf: Genotype<BitGene> -> eval(gf) }, gtf) 15 16 // 4.) Start the execution (evolution) and collect the result. 17 val result = engine.stream() 18 .limit(100) 19 .collect(EvolutionResult.toBestGenotype()) 20 21 println("Hello World:\n$result") 22 23}

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

エラー

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

Java

1public 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) { 2 return new Engine.Builder(genotypeFactory, ff); 3}

ラムダ式 { 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.」の部分を以下のように書き換えたところ、コンパイルは通ったのですが、実行時に以下のエラーとなってしまいました。

Kotlin

1val 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と同じ現象になってしましました。

Kotlin

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

###■追記3

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

Kotlin

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

###■追記4

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

Kotlin

1// 2.) Definition of the fitness function. 2fun eval(gt: Genotype<BitGene>): Int { 3 return gt.chromosome 4 .`as`(BitChromosome::class.java) 5 .bitCount() 6} 7 8fun main(vararg args: String) { 9 10 // 1.) Define the genotype (factory) suitable for the problem. 11 val gtf = Genotype.of(BitChromosome.of(10, 0.5)) 12 13 // 3.) Create the execution environment. 14 val engine = Engine.builder(java.util.function.Function<Genotype<BitGene>, Int> { eval(it) }, gtf).build() 15 16 // 4.) Start the execution (evolution) and collect the result. 17 val result = engine.stream() 18 .limit(100) 19 .collect(EvolutionResult.toBestGenotype<BitGene, Int>()) 20 21 println("Hello World:\n$result") 22 23}

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

Hello World: [00000011|11111111]

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2018/04/15 12:13 編集

関係ないかもしれませんが、JDKのバージョンとKotlinのバージョンを一応明記しておいた方がよいかも知れません。
mosa

2018/04/15 11:57

ありがとうございます。 Kotlin 1.2.31、 Java 1.8.0 です。
KSwordOfHaste

2018/04/15 12:16 編集

当方Kotlin 1.2.31-release-95, JDK 1.8.0_162 IntelliJ IDEA 2018.1(Community Ed.)ですが追記1の現象が再現しませんでした。 (追記:Kotlin-stdlibのMANIFEST.MFの中身がImplementation-Version: 1.2.31-release-95, Build-Jdk: 1.8.0_151,...となっていたという意味です。自分もバージョンの見方がわかりませんでした><)
mosa

2018/04/15 12:54

検証ありがとうございます。「3.」以降を記述しました。表示されますでしょうか。追記1のエラーはまた別問題な気がしてきました。IntelliJ で Rebuild Project をしただけで同じエラーが発生しました。Invalidate Cache → Maven clean をした後でも同様です。
KSwordOfHaste

2018/04/15 13:32 編集

追記1は当方ではおきませんね・・・。元々の型エラーは型推論にまかせずに変数の型を意図したものに明示的に宣言したりbuilderメソッドに型引数を明記したりすればどこが推論できてないか(推論結果と不一致か)が絞れないでしょうか?
mosa

2018/04/15 14:34

ありがとうございます。「追記2」を追加しました。変数の型を明示するとやはりコンパイルは通りますが、org.jetbrains.kotlin.codegen.CompilationException が発生してしまいます。org.jetbrains.kotlin.codegen.CompilationException はコードそのものの問題ではなさそうに思えます。明日、別のPCで検証可能ですので検証してみます。
mosa

2018/04/16 11:08

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

2018/04/17 08:11

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

2018/04/17 13:41

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

回答1

0

ベストアンサー

追記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行目です。そこに書かれているのは以下の行です。

Kotlin

1val result = engine.stream() 2 .limit(100) 3 .collect(EvolutionResult.toBestGenotype()) 4

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

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

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

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

投稿2018/04/17 10:03

編集2018/04/17 10:05
KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2018/04/17 10:08

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

2018/04/17 13:40 編集

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

2018/04/17 13:44

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

2018/04/17 13:55

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

2018/04/17 14:40 編集

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

2018/04/18 10:20

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

2018/04/18 15:22

>>KSwordOfHasteさんへ コメント欄をお借りして失礼しました。返信ありがとうございました。 >>mosaさんへ Issue Trackerへの登録報告ありがとうございました。
mosa

2018/04/19 04:53

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問