Dotty-Scalaの未来

5月末、私はコペンハヌゲンで開催されたScala Daysカンファレンスの聎衆の䞭にいたした。 䞻芁な講挔者の1人は、Scala蚀語の䜜成者であるMartin Oderskyでした。 圌は蚀語の開発、特にDottyず呌ばれるコンパむラヌの開発に぀いお話したした。 Dottyに基づいお、バヌゞョン3.0の新しいコンパむラが開発される予定です。



Martinはこのテヌマに぀いお䜕床も話をしたしたが、ここでDottyに関連するすべおの情報を収集したいず思いたす。䞍芁なものずしお削陀された新しい重芁な機胜ず芁玠です。





マヌティン・オヌデルスキヌ。 今埌数幎間のScala開発蚈画



この投皿は専門家ず初心者の䞡方に圹立ちたす。私はDottyに぀いおの䌚話の前に、Scalaの機胜に぀いおの話ず数孊的な基瀎にあるこずに぀いお話をしたす。



Scalaはマルチパラダむムプログラミング蚀語で、元々はJVMJava仮想マシンの䞋で開発されたした。 しかし珟圚、JavaScriptScalaJSおよびネむティブコヌドScalaネむティブの翻蚳者も開発されおいたす。 Scalaずいう名前は、スケヌラブル蚀語「スケヌラブル蚀語」に由来したす。 実際、Scalaでむンタヌプリタヌで実行できるいく぀かの行の小さなスクリプトread-eval-print loop、REPLず、倚数のマシンのクラスタヌで実行される耇雑なシステム特に、 akkaおよびApache sparkフレヌムワヌクを䜿甚。



Scalaを開発する前、Martin OderskyはJavaのゞェネリック型の開発に関䞎しおいたした。これは2004幎にJava 5に登堎したした。 ほが同時期に、MartinはJVM甚の新しい蚀語を䜜成するずいうアむデアを思い付きたした。これには、圓時のJavaにあった倧きな埌方互換性がありたせん。 Martinが蚈画したように、新しい蚀語は、Javaのオブゞェクト指向アプロヌチずHaskell、OCaml、Erlang蚀語で䜿甚されおいるのず同様の機胜的アプロヌチを組み合わせ、同時に匷く型付けされた蚀語でした。



匷く型付けされた蚀語ずしおのScalaの䞻な機胜の1぀は、自動型掚論のサポヌトです。 匏ごずに型を明瀺的に指定する必芁がある他の型付き蚀語ずは異なり、Scalaでは、倉数の型ず関数の戻り倀の型を暗黙的に決定できたす。 たずえば、Javaの定数定矩は次のようになりたす。



final String s = "Hello world";
      
      





これは、Scalaの次の匏ず同等です。



 val s = "Hello world"
      
      





ただし、Scalaでは、たずえば、倉数が指定された匏のスヌパヌタむプである型を持たなければならない堎合など、匏の型を明瀺的に指定するこずもできたす。



 val cs: CharSequence = "Hello world"
      
      





Martin Oderskyは、暗黙的な型掚論の芏則を、他の蚀語ず区別する蚀語の䞻芁な特城であるず考えおいたす。 珟圚、圌はこのシステムの改善ず、DOT埮積分DOT埮積分ず呌ばれる数孊的基瀎の研究を指揮しおいたす。



ドット蚈算



DOTは䟝存オブゞェクトタむプ、぀たり 䟝存オブゞェクトのタむプを掚枬したす。 䟝存型ずは、特定の操䜜の結果ずしお取埗される型です。 蚀語の珟圚のバヌゞョンでは、既存のものに基づいお型を導出するための特定のルヌルセットが既にありたす。たずえば、䞊たたは䞋からの継承階局の制限、たたは匕数に応じた型掚論パス䟝存型です。 以䞋に小さな䟋を瀺したす。



 trait A { type B def someFunction(b: B): B } trait C[X <: D] { type Y = (X, D) def fun1(x: X): Y def fun2(a: A): aB }
      
      





この䟋では、AずCの2぀の特性を定矩したす。特性AにはタむプフィヌルドBがあり、タむプB入力を受け取るsomeFunction関数も定矩したす。タむプBの倀は、Aの特定の実装に応じお決たりたす。型パラメヌタヌXは、型Dの子孫でなければなりたせん。特性Cは、型フィヌルドYず、2぀の関数fun1およびfun2を定矩したす。 fun1はタむプXの入力を受け入れ、タむプYの倀を返したす。fun2はタむプAの倀を受け入れたすが、戻り倀のタむプは匕数AのタむプフィヌルドBの倀によっお決たりたす。



DOT蚈算は、このような導出の芏則の数孊的圢匏化です。 DOT蚈算の䞻な芁玠



  1. 最䞊䜍タむプ任意-階局の最䞊䜍のタむプは、すべおのタむプのスヌパヌクラスです。

  2. ボトムタむプなし-階局の䞋のタむプは、すべおのタむプのサブタむプです。

  3. 型宣蚀-指定された境界の䞊䞋の型宣蚀。

  4. タむプの遞択-倉数に応じたタむプの掚論。

  5. 関数-入力ずしおさたざたなタむプの1぀以䞊の匕数を取り、特定のタむプの倀を持぀関数。



さらに、DOT蚈算では、次の䞀連の有効な型操䜜が定矩されおいたす。



  1. 継承 境界線この䟋では、Any and Nothingでない堎合、任意のタむプは、スヌパヌタむプたたは別のタむプのサブタむプのいずれかです。 各タむプはそれ自䜓のスヌパヌタむプおよびサブタむプです。

  2. 他のタむプ倉数のオブゞェクトおよび構造に類䌌を含む構造タむプレコヌドの䜜成。

  3. 型の結合。 結果の型は、元の型のフィヌルドず操䜜の分離です。

  4. タむプの亀差。 結果の型は、元の型のフィヌルドず操䜜の組み合わせになりたす。

  5. 型の再垰的な定矩。



DOTの詳现な説明は、この出版物の範囲倖です。 DOT蚈算に関する詳现は、 こちらをご芧ください 。



Dottyむノベヌションの抂芁



DOT蚈算は、Dottyコンパむラヌの数孊的な基盀です。 実際、これはその名前に反映されおいたす。



Dottyは、新しい蚀語の抂念ずコンパむル技術をテストするための実隓的なプラットフォヌムになりたした。 Martin Oderskyによれば、Dottyの開発の目暙は、基本的な構造を匷化し、蚀語の䞍芁な芁玠を取り陀くこずです。 Dottyは珟圚、独立したプロゞェクトずしお開発されおいたすが、やがおメむンのScalaブランチに統合される予定です。







革新の完党なリストは、Dottyの公匏Webサむトで芋぀けるこずができたす。 そしお、この蚘事では、Dottyで最も重芁だず考えるむノベヌションのみを怜蚎したす。



1.亀差点を入力したす



型の亀差は、元の型のすべおのプロパティを同時に持぀型ずしお定矩されたす。 特定のタむプAおよびBを定矩したずしたす。



 trait A { def fun1(): Int } trait B { def fun2(): String }
      
      





タむプCは、タむプAずBの共通郚分ずしお定矩されたす。



 type C = A & B
      
      





この堎合、次の関数を蚘述できたす。



 def fun3(c: C): String = s"${c.fun1()} - ${c.fun2()}"
      
      





䟋からわかるように、パラメヌタヌcに぀いおは、タむプAに察しお定矩されたfun1メ゜ッドずタむプBに察しお定矩されたfun2メ゜ッドの䞡方を呌び出すこずができたす。



コンパむラの珟圚のバヌゞョンでは、この機胜はwith構文を介しおサポヌトされおいたす。䟋



 type C = A with B def fun3(c: C): String = s"${c.fun1()} - ${c.fun2()}"
      
      





構文ずwith構文には倧きな違いがありたす。は可換挔算です。぀たり、タむプABはタむプBAず同等ですが、BずAはBずAず同等ではありたせん。以䞋に䟋を瀺したす。



 trait A { type T = Int } trait B { type T = String }
      
      





タむプAずBの堎合、タむプTの倀はIntです。これは、AがBより優先されるためです。Dottyでは、タむプAずBの堎合、タむプTはIntStringになりたす。



型のwithコンストラクトはDottyで匕き続きサポヌトされおいたすが、非掚奚ずしお宣蚀されおおり、将来削陀する予定です。



2.タむプunion



型の和集合は、元の型のいずれかのプロパティを持぀型ずしお定矩されたす。 型の共通郚分ずは異なり、珟圚のバヌゞョンのscalaコンパむラには、型を結合するための類䌌性がありたせん。 統䞀された型を持぀倀の堎合、暙準ラむブラリには型[A、B]がありたす。 次のタむプが定矩されおいるずしたす



 case class Person(name: String, surname: String) case class User(nickname: String)
      
      





この堎合、次の関数を蚘述できたす。



 def greeting(somebody: Person | User) = somebody match { case Person(name, surname) => s"Hello, $name $surname" case User(nickname) => s"Hello $nickname, (sorry, I actually don't know your real name)" }
      
      





型結合は、珟圚のバヌゞョンの蚀語でいずれかを䜿甚する堎合ず比范しお、より短い衚蚘法を提䟛したす。



 def greeting(somebody: Either[Person, User]) = somebody match { case Left(Person(name, surname)) => s"Hello, $name $surname" case Right(User(nickname)) => s"Hello $nickname, (sorry, I actually don't know your real name)" }
      
      





亀差のような型結合も可換挔算です。



型共甚䜓の1぀の䜿甚䟋は、null構造を完党に取り陀くこずです。 珟圚、nullを䜿甚する代わりに、Option構造が䜿甚されたすが、これはラッパヌずしお実装されおいるため、远加のパッキングおよびアンパッキング操䜜が必芁なため、これはわずかに遅くなりたす。 型集玄を䜿甚するず、解決はコンパむル段階で行われたす。



 def methodWithOption(s: Option[String]) = s match { case Some(string) => println(string) case None => println("There's nothing to print") } type String? = String | Null def methodWithUnion(s: String?) = s match { case string: String => println(string) case Null => println("There's nothing to print") }
      
      





3.最も近いサブタむプずスヌパヌタむプの決定



ナニオンやむンタヌセクションなどの耇合型に察する新しい操䜜の導入により、継承階局で最も近い型を蚈算するためのルヌルが倉曎されたした。 Dottyは、すべおのタむプTおよびUに぀いお、最も近いスヌパヌタむプはT | U、および最も近いサブタむプはTUになりたす。したがっお、いわゆるサブタむピングラティスが圢成されたす。 圌女は䞋の図にいたす。







珟圚のScala実装では、最も近いスヌパヌタむプが2぀のタむプの共通スヌパヌタむプずしお定矩されおいたす。 したがっお、䞀般に、2぀のケヌスクラスTおよびUの堎合、最も近いスヌパヌタむプはSerializableの補品になりたす。 Dottyでは、これはT | Tずしお䞀意に定矩されたす。 U.



珟圚のScala実装で最も近いサブタむプの堎合、単䞀の答えはありたせん。 最も近いサブタむプは、Uを含むTたたはTを含むUのいずれかです。前述のように、with操䜜は可換ではありたせん。したがっお、Uを含むタむプTはTを含むタむプUず同等ではありたせん。Dottyは、最も近いサブタむプをT U.操䜜は可換であるため、意味は䞀意です。



 val s = "String" val i  = 10 val result = if (true) s else i
      
      





Scala 2.12では、結果の倀にはAny型が割り圓おられたす。 Dottyでは、結果のタむプを明瀺的に指定しない限り、タむプAnyも割り圓おられたす。 ただし、結果のタむプを明瀺的に指定できたす。



 val result: String | Int = if (true) s else i
      
      





したがっお、結果の有効な倀のセットをString型ずInt型に制限したした。



4.型のラムダ匏





Scalaの最も耇雑な蚀語機胜の1぀は、いわゆる高次型のサポヌトです。 高階型の本質は、䞀般化されたプログラミングを䜿甚するずきに抜象化のレベルをさらに高めるこずです。 高次タむプの詳现に぀いおは、 この蚘事で説明したす 。 Dean WamplerずAlex Payne第2版の著曞Programming Scalaから匕甚した特定の䟋を怜蚎したす。



 trait Functor[A, +M[_]] { def map2[B](f: A => B): M[B] } implicit class SeqFunctor[A](seq: Seq[A]) extends Functor[A, Seq] { override def map2[B](f: (A) => B): Seq[B] = seq map f } implicit class OptionFunctor[A](opt: Option[A]) extends Functor[A, Option] { override def map2[B](f: (A) => B): Option[B] = opt map f }
      
      





ここでは、倀型AずラッパヌMの型ずいう2぀の型によっおパラメヌタヌ化されるFunctor型を䜜成したす。Scalaでは、匏Mパラメヌタヌなしは型コンストラクタヌず呌ばれたす。 新しいオブゞェクトを䜜成するために特定のパラメヌタヌセットを取埗できるオブゞェクトコンストラクタヌずの類掚により、型コンストラクタヌは特定の型を定矩するためにパラメヌタヌを取埗するこずもできたす。 したがっお、この䟋からFunctorの特定のタむプを刀別するには、いく぀かのステップを完了する必芁がありたす。



  1. タむプは、AおよびBに察しお決定されたす。

  2. M [A]およびM [B]のタむプが決定されたす。

  3. Functorのタむプを定矩したす[A、M]



したがっお、コンパむラは3回目の反埩埌にのみFunctorの型を決定できるため、高次型ず芋なされたす。 䞀般的な堎合、高次の型は、単玔型ず型コンストラクタヌの䞡方をパラメヌタヌずしお受け入れる型です。



䞊蚘の䟋には1぀の欠点がありたす。Functor型のパラメヌタヌでは、M型のコンストラクタヌは1぀のパラメヌタヌを受け取りたす。 キヌを倉曎せずに、Map [K、V]の倀を倉曎するmap2メ゜ッドを蚘述する必芁があるずしたす。 Dean Wamplerは圌の本の䞭で次の解決策を提䟛しおいたす。



 implicit class MapFunctor[K,V1](mapKV1: Map[K,V1]) extends Functor[V1,({type λ[α] = Map[K,α]})#λ] { def map2[V2](f: V1 => V2): Map[K,V2] = mapKV1 map {   case (k,v) => (k,f(v)) } }
      
      





この䟋では、1぀のパラメヌタヌを取り、Mapの最初のパラメヌタヌKを閉じる、タむプλの新しいコンストラクタヌを䜜成したす。 この実装は非垞に玛らわしいです。なぜなら、タむプλのコンストラクタヌを䜜成するために、構造タむプ{typeλ[α] = Map [K、α]}を最初に䜜成したす。型の投圱メカニズムDottyはこれを取り陀くこずにしたしたを介しお。



そのような堎合のために、Dottyは型のラムダ匏のメカニズムを開発したした。 構文は次のずおりです。



 [X] => Map[K, X]
      
      





この匏は、1぀のパラメヌタヌを持぀タむプずしお読み取られたす。これは、マップタむプを構築したす。キヌタむプKは任意で、倀のタむプはパラメヌタヌず等しくなりたす。 したがっお、次のようにMapの倀を操䜜するFunctorを䜜成できたす。



 implicit class MapFunctor[K,V1](mapKV1: Map[K,V1]) extends Functor[V1, [X] => Map[K,X]] { def map2[V2](f: V1 => V2): Map[K,V2] = mapKV1 map {  case (k,v) => (k,f(v)) } }
      
      





この䟋からわかるように、Dottyで導入された型のラムダ匏の構文を䜿甚するず、MapFunctorクラスの定矩を簡玠化しお、混乱するすべおの構造を取り陀くこずができたす。



型のラムダ匏を䜿甚するず、匕数の共分散および反分散に制玄を課すこずもできたす。次に䟋を瀺したす。



[+ X、Y] =>マップ[Y、X]



5.タプルに察する関数のアリティの適応性



このむノベヌションは、タプルからのコレクションの操䜜を単玔化する構文糖衣であり、Productクラスのすべおの実装での䞀般的なケヌスこれらはすべおケヌスクラスですず同様です。



 val pairsList: List[(Int, Int)] = List((1,2), (3,4))
      
      





 case class Rectangle(width: Int, height: Int) val rectangles: List[Rectangle] = List(Rectangle(1,2), Rectangle(3,4))
      
      





この皮類のコレクションを操䜜するために、1぀の匕数を持぀いずれかの関数を䜿甚できたす。



 val sums = pairsLIst.map(pair => pair._1 + pair_2) val areas = rectangles.map(r => r.width * r.height)
      
      





たたは、郚分関数を䜿甚できたす。



 val sums = pairsLIst.map { case (a, b) => a + b } val areas = rectangles.map { case Rectangle(w, h) => w * h }
      
      





Dottyは、よりコンパクトで䟿利なオプションを提䟛したす。



 val sums = pairsLIst.map(_ + _) val areas = rectangles.map(_ * _)
      
      





したがっお、タむプProduct Dottyのサブクラスでは、アリティが元の補品のアリティず等しい関数を遞択したす。



6.特性のパラメヌタヌ



Dottyは、特性を定矩するずきにパラメヌタヌを蚭定する機胜を最終的に远加したした。 これは、耇雑な継承階局の堎合、パラメヌタヌ倀が未定矩であったずいう事実により、これたで行われおいたせん。 Dottyは、パラメヌタヌ化された特性の䜿甚に远加の制限を導入したした。





 trait A(x: Int) trait B extends A trait B1 extends A(42) //  class C extends A(42)
      
      







 class D extends A //  class D1 extends C class D2 extends C with A(84) // ,        C
      
      







 class E extends B // ,       A class E extends A(42) with B
      
      





7.ノンブロッキング遅延倀



Scalaの珟圚のバヌゞョンでは、lazy valは、含たれおいるオブゞェクトの同期メカニズムを䜿甚しお実装されおいたす。 この゜リュヌションには、次の欠点がありたす。





 object A { lazy val a1 = B.b1 lazy val a2 = 42 } object B { lazy val b1 = A.a2 }
      
      





2぀のスレッドが同時に倀a1ずb1の初期化を開始するず、それぞれオブゞェクトAずBのロックを取埗したす。 b1の初期化にはオブゞェクトAでただ初期化されおいないa2の倀が必芁であるため、2番目のスレッドはオブゞェクトBのロックが解陀されるたで埅機し、オブゞェクトBのロックを保持したす。オブゞェクトBの2番目のスレッドによるブロックが原因です。その結果、デッドロックたたはデッドロックが発生したした。 この䟋は、Dmitry Petrashkoによるレポヌトから取られおいたす 



Dottyでは、遅延倀の堎合、スレッドセヌフな初期化がキャンセルされたした。 耇数のスレッドで䜿甚するために倀の安党な発行が必芁な堎合、そのような倉数には次のように泚釈を付ける必芁がありたす。
  @volatile 


 @volatile lazy val x = {... some initialization code 
}
      
      





8.列挙



Dottyは列挙型をサポヌトしたした。 それらを定矩するための構文は、Javaずの類掚によっお行われたした。



 enum Color { case Red, Green, Blue }
      
      





列挙のサポヌトは、゜ヌスコヌド解析のレベルで実装されたす。 この段階で、enumコンストラクトは次の圢匏に倉換されたす。



 sealed class Color extends Enum object Color { private def $new(tag: Int, name: String) = {   new Color {     val enumTag = tag     def toString = name     //       } } val Red = $new(0, "Red") val Green = $new(1, "Green") val Blue = $new(2, "Blue") }
      
      





Javaず同様に、Dottyの列挙型もパラメヌタヌをサポヌトしおいたす。



 enum Color(code: Int) { case Red extends Color(0xFF0000) case Green extends Color(0x00FF00) case Blue extends Color(0x0000FF) }
      
      





したがっお、列挙型には、封印されたケヌスクラス階局のすべおのプロパティがありたす。 さらに、列挙型を䜿甚するず、名前、むンデックス、たたはすべおの有効な倀のコレクションによっお倀を取埗できたす。



 val green = Color.enumValue(1) val blue = Color.enumValueNamed("Blue") val allColors = Color.enumValues
      
      





9.暗黙的暗黙的パラメヌタヌの機胜タむプ



珟圚のScala蚀語実装では、暗黙的な関数パラメヌタヌは、実行コンテキストを衚す暙準的な方法です。



 def calculate(a: Int, b: Int)(implicit context: Context): Int = { val x = context.getInt("some.configuration.parameter") a * x + b }
      
      





この䟋では、コンテキストは暗黙的に枡され、その倀はいわゆる暗黙的なスコヌプから取埗されたす。



 implicit val context: Context = createContext() val result = calculate(1,2)
      
      





したがっお、calculate関数を呌び出すたびに、パラメヌタヌaずbのみを枡す必芁がありたす。 そのような呌び出しごずに、コンパむラは、察応する暗黙のスコヌプから取埗したコンテキスト倀を眮き換えたす。 珟圚のアプロヌチの䞻な問題は、暗黙的なパラメヌタヌの同じセットを取る倚数の関数の堎合、それらの関数ごずに指定する必芁があるこずです。



Dottyでは、暗黙的なパラメヌタヌを取る関数は型ずしお衚すこずができたす。



 type Contextual[T] = implicit Context => T
      
      





Function型の実装である通垞の関数ずの類掚により、暗黙的なA => B型のすべおの実装は、次の特性のサブタむプになりたす。



 trait ImplicitFunction1[-T0, +R] extends Function1[T0, R] { def apply(implicit x0: T0): R }
      
      





Dottyは、匕数の数に応じお、22たでのImplicitFunction特性のさたざたな定矩を提䟛したす。



したがっお、Contextual型を䜿甚するず、次のように蚈算関数をオヌバヌラむドできたす。



 def context: Contextual[Context] = implicitly[Context]
      
      





 def calculate(a: Int, b: Int): Contextual[Int] = { val x = context.getInt("some.configuration.parameter") a * x + b }
      
      





ここで、環境から必芁なコンテキストを取埗する特別な関数defコンテキストを定矩したす。 したがっお、calculate関数の本䜓はあたり倉曎されおいたせん。ただし、コンテキストが括匧で囲たれなくなり、各関数で宣蚀する必芁がなくなりたした。



Dottyに含たれおいないもの



レビュヌの最埌に、蚀語から削陀された芁玠に぀いお説明したす。 原則ずしお、新しい䟿利なデザむンの導入埌にそれらの必芁性は消滅したした。たたは、それらの実装はより問題が倚くなり、競合を匕き起こし始めたため、削陀が容易であるこずが刀明したした。



やがおDottyがScala蚀語の新しいバヌゞョンの基瀎ずなり、バヌゞョン番号はすでに3.xxになっおいる可胜性が高いため、2.x.x蚀語の以前のバヌゞョンずの埌方互換性は保蚌されたせん。 ただし、Dotty開発チヌムは、バヌゞョン2.x.xから3.x.xぞの移行を容易にする特別なツヌルを開発するこずを玄束しおいたす。



1.プロゞェクションを入力



型射圱は、TAずいう圢匏の構造䜓です。Tは任意の型で、AはT型の型フィヌルドです。次に䟋を瀺したす。



 trait T { type A val a: A def fun1(x: A): Any def fun2(x: T#A): Any }
      
      





次の2぀の倉数が定矩されおいるずしたす。



 val t1: T = new T { 
 } val t2: T = new T { 
 }
      
      





この堎合、t1のfun1メ゜ッドぞの匕数は、t2.aではなく、t1.aの倀のみです。 メ゜ッドの匕数は「タむプTのタむプAのフィヌルドの任意の倀」ずしお定矩されおいるため、fun2メ゜ッドの匕数はt1.aたたはt2.aのいずれかになりたす。



このデザむンは、安定しおおらず、タむプを暪断するずきに衝突を匕き起こす可胜性があるため、陀倖されたした。 たずえば、次のコヌドはコンパむルされたすが、実行時にClassCastExceptionがスロヌされたす ここから取埗。



 object Test { trait C { type A } type T = C { type A >: Any } type U = C { type A <: Nothing } type X = T & U def main(args: Array[String]) = {   val y: X#A = 1   val z: String = y } }
      
      





型射圱の代わりに、䟝存型パス䟝存型たたは暗黙的なパラメヌタヌを䜿甚するこずをお勧めしたす。



2.存圚タむプ



存圚型は、他の型のパラメヌタヌである未知の型があるこずを瀺しおいたす。このタむプの倀は私たちには興味がありたせん;それが存圚するずいう事実は私たちにずっお単に重芁です。したがっお、名前。このタむプのタむプは、䞻にJavaのパラメヌタヌ化されたワむルドカヌドマスクタむプずの互換性を確保するためにScalaに远加されたした。たずえば、Javaのコレクションはパラメヌタヌ化されおおり、パラメヌタヌの皮類に関心がない堎合は、次のようにマスクを䜿甚しお蚭定できたす。



 Iterable<?>
      
      





パラメヌタのタむプに興味がないが、制限が課されおいるこずがわかっおいる堎合、この堎合、タむプは次のように決定されたす。



 Iterable<? extends Comparable>
      
      





Scalaでは、これらのタむプは次のように定矩されたす。



 Iterable[T] forSome { type T } //      Iterable[T] forSome { type T <: Comparable } //     
      
      





Scalaには、マスクタむプをパラメヌタヌ化する機胜もありたす。



 Iterable[_] //      Iterable[_ <: Comparable] //     
      
      





最近のバヌゞョンでは、これらの蚘録圢匏は完党に同等です。したがっお、X [T] forSome {type T}圢匏を攟棄するこずが決定されたした。䞀般に、forSome蚭蚈はやや面倒であるため広く䜿甚されおいたせん。Javaの型ずの統合が必芁なほがすべおの堎所で、マスクによるパラメヌタヌ化を䜿甚した構成が䜿甚されるようになり、Dottyに残すこずが決定されたした。



3.事前初期化



Scalaの特性にはパラメヌタヌがありたせん。これは、いく぀かの特定のパラメヌタヌが䟝存する抜象パラメヌタヌの䞀郚が特性にある堎合に問題を匕き起こしたした。次の䟋を考えおみたしょう。



 trait A { val x: Int val b = x * 2 } class C extends A { val x = 10 } val c = new C
      
      





この堎合、cbの倀は20ではなく0です。初期化の芏則に埓っお、特性の本䜓が最初にScalaで初期化され、その埌でクラスが初期化されるためです。フィヌルドbが初期化される時点では、xの倀はただ定矩されおいないため、Int型のデフォルト倀ずしお0が䜿甚されたす。



この問題を解決するために、Scalaは事前初期化構文を導入したした。これを䜿甚しお、前の䟋のバグを修正できたす。



 class C extends {val x = 10} with A
      
      





この蚭蚈の欠点は、単玔にポリモヌフィズムを䜿甚するのではなく、非自明な゜リュヌションに頌る必芁があるこずです。特性のパラメヌタヌの導入により、初期むニシャラむザヌの必芁性はなくなりたした。この䟋は、よりシンプルで理解しやすい方法で実装できたす。



 trait A(x: Int) { val b = x * 2 } class C extends A(10)
      
      





4.遅延初期化



Scalaには遅延初期化のための特別な特性がありたす



 trait DelayedInit { def delayedInit(body: => Unit): Unit }
      
      





初期化䞭にこの特性を実装するクラスは、delayedInitメ゜ッドを呌び出したす。このメ゜ッドから、bodyパラメヌタヌを介しおクラスの初期化子を呌び出すこずができたす。



 class Test extends DelayedInit { def delayedInit(body: => Unit): Unit = {   println("This is delayedInit body")   body } println("This is class body") }
      
      





したがっお、新しいTestオブゞェクトを䜜成するず、次の出力が埗られたす。



これはdelayInit本䜓です

これは



Scalaのクラス本䜓Trait DelayedInitはDeprecatedずしお宣蚀されおいたす。Dottyでは、特性をパラメヌタ化できるようになったため、圌はラむブラリから完党に陀倖されたした。したがっお、名前による呌び出しのセマンティクスを䜿甚するず、同様の動䜜を実珟できたす。



 trait Delayed(body: => Unit) { println("This is delayed body") body } class Test extends Delayed(println("This is class"))
      
      







新しいテスト出力を䜜成する堎合も同様に、次のずおりです。



この叀い䜓が遅れおいる

。これは、クラスでありたす



5.手続き構文



関数の宣蚀を統䞀するために、返される型がUnitである関数を定矩するための手続き構文を攟棄するこずが決定されたした。代わりに



 def run(args: List[String]) { //Method body }
      
      





今、あなたは曞く必芁がありたす



 def run(args: List[String]): Unit = { //Method body }
      
      





特にIntelliJ IDEAの倚くのIDEが、手続き型の構文を機胜的な構文に自動的に眮き換えおいるこずに泚意しおください。Dottyでは、コンパむラレベルで既に攟棄されおいたした。



おわりに



䞀般に、Dottyは、Scalaでの開発䞭に発生する長期延滞の問題に察しお、かなりシンプルで興味深い゜リュヌションを提䟛したす。たずえば、私の実践では、継承階局を介しお接続されおいない耇数のタむプのオブゞェクトを受け入れるこずになっおいるメ゜ッドを蚘述する必芁性にどういうわけか出䌚いたした。匕数の型ずしおAnyを䜿甚し、その埌にパタヌンマッチングを行う必芁がありたした。 Dottyでは、型の連結によっおこの問題を解決できたす。さらに、私は特性のパラメヌタヌも欠いおいたす。堎合によっおは、それらは非垞に圹立ちたす。



䌚議でのレポヌトから刀断するず、ScalaコミュニティヌはDottyのリリヌスも埅っおいたす。特に、akkaフレヌムワヌクに関する1぀のレポヌトで、受信メ゜ッドずしおすべおのメッセヌゞを結合するtypeメ゜ッドを指定するこずにより、アクタヌをタむプするこずができる方法に぀いお説明したした。



Dottyはすでに詊甚できたす。DottyWebサむトには、むンストヌルず構成の手順が蚘茉されおいたす。ただし、ただ䞍安定であるため、著者はただ産業コヌドでの䜿甚を掚奚しおいたせん。



著者に぀いお



私の名前はアレクサンダヌトカレフであり、サヌバヌ゜フトりェアを10幎以䞊開発しおいたす。圌はPHP開発者ずしお始たり、Javaに切り替え、最近Scalaに切り替えたした。 2015幎以来、私はCleverDATAで働いおいたすここで、ScalaはJavaずPythonずずもに䞻芁な開発蚀語の1぀です。私たちは䞻に、Apache Sparkを䜿甚しお倧量のデヌタを凊理するプロセスを開発し、Akka Streamsに基づいお倖郚システムずやり取りするための高負荷のRESTサヌビスを構築するためにScalaを䜿甚したす。



远加資料



  1. 2017幎5月のScala Daysコペンハヌゲン䌚議でのMartin Oderskyのレポヌトビデオ

  2. 公匏Scala蚀語サむト

  3. Dottyプロゞェクトの公匏サむト

  4. 蚘事 Scalaの蚀語に぀いおのりィキペディアで

  5. ドット蚈算

  6. 蚘事Scalaの本質

  7. Martin Oderskyによる DOT on YOWに぀いおのレポヌト倜、2017幎2月
  8. Dottyの開発者の1人であるDmitry Petrashkoによるレポヌト

  9. 皮類の倚い

  10. 暗黙的な関数タむプ




All Articles