SlideShare a Scribd company logo
自由平
Eugene Yokota (@eed3si9n)
等Equality in Scala
1998年
OOPSLA: 1998

Growing a Language

Guy Steele
「言語を成長させる」
small vs large language
1. Small language: short time to learn
2. Large language: more vocabulary to use
小さい言語は習うのが容易
大きい言語はより多くの語彙を使うことができる
primitive
• "A primitive is a word for which we can take it for
granted that we all know what it means."
プリミティブとは、それが何を意味するのか自明とできる言葉
language that can grow
1. APL: users cannot define symbols
2. LISP: user-defined words look like the primitives
APL は優れた言語だが、ユーザはシンボル演算子を定義不可
LISP はユーザ定義でプリミティブ的なものを作れる
language that can grow
1. Cathedral (one design) vs Bazaar (no one plan)
2. plan can change to meet the user
寺院設計は 1つの大計画、商店街は複数の計画を持つ
ユーザのニーズに応えて計画を変更することができる
making Java growable
1. Generic types
2. Operator overload
Java を成長させる
ジェネリック型と演算子のオーバーロード
複素数
OOPSLA 1998
「過去のために将来を安全なものにする」
Newspeak 作者、小田好先生、Haskell 作者
Java virtual machine
https://www.artima.com/insidejvm/ed2/jvmP.html
int c = a + b;
iload_0 // push local var0
iload_1 // push local var0
iadd
istore_2
https://www.artima.com/insidejvm/ed2/jvmP.html
int a = 1;
java.util.Vector xs = new java.util.Vector();
xs.add(java.lang.Integer.valueOf(1));
primitive types
boxed primitives
スタックに直に積めるのがプリミティブデータ型
ヒープ上にオブジェクトとして包むことをボックス化と言う
1
2001年
Lightweight Language
1. Easy to learn and use
2. Widely-used languages are coming from industry
3. Perl, Python, Ruby, (Scheme)
http://ll1.ai.mit.edu/cfp.html
LL言語とは何だったのか。実用言語が産業側から来てるとい
うアカデミアにおける危機感。ライトなのは学びやすさ。
2008年
a scalable language
スケーラブルな言語
"The name Scala stands for scalable language.
The language is so named because it was
designed to grow with the demands of its users.
You can apply Scala to a wide range of
programming tasks, from writing small scripts to
building large systems."
'Programming in Scala', Odersky, Spoon, Venners
Scala という名前は「スケーラブルな言語」を意味する
ユーザーの求めに応じて成長していけるように設計されている
Scala: a scalable language
"Guy Steele noted in a talk on "growing a
language" that the same distinction can be
applied to language design. Scala is much more
like a bazaar than a cathedral, in the sense that it
is designed to be extended and adapted by the
people programming in it."
'Programming in Scala', Odersky, Spoon, Venners
Guy Steele は「言語を成長させる」という講演の中で
言語設計も「伽藍とバザール」が区別できると言っている
Scala: a scalable language
Scala
1. Abstract types
2. Operator overload
抽象型
演算子オーバーロード
purely object-oriented
1. Everything-is-a- object, message passing
1 + 2
1.+(2)
純粋オブジェクト指向言語
全てがオブジェクト、全てがメッセージ・パッシング
purely object-oriented
https://www.scala-lang.org/files/archive/spec/2.13/12-the-scala-standard-library.html
1. Everything-is-a- object, message passing
complex number in Scala (Spire)
scala> import spire.implicits._, spire.math._
import spire.implicits._
import spire.math._
scala> Complex(1.0, 2.0) + Complex(3.0, 5.0)
val res0: spire.math.Complex[Double] = (4.0 + 7.0i)
scala> Complex(1.0, 2.0) * Complex(3.0, 5.0)
val res1: spire.math.Complex[Double] = (-7.0 + 11.0i)
Scala における複素数
Scala
1. Intuitive and OO number types, like Python/Ruby
2. Extensibility
直観的かつオブジェクト指向な数値型
拡張性
==
what is equality?
•substitution property
•for any a, b, and f(x): a == b ⇒ f(a) == f(b)
•equivalence relation
等価性とは代入原理を満たす同値関係の1つ
equivalence
• reflexive
• for any a (except NaN): a == a
• symmetric
• for any a, b: a == b ⇒ b == a
• transitive
• for any a, b, and c: a == b && b == c ⇒ a == c
同値関係は反射律、対称律、推移律
equivalent, but not equal
合同な図形は同値関係にあるが等しくは無い
these shapes are congruent
in some context they could be considered "same"
https://www.artima.com/insidejvm/ed2/jvmP.html
• boolean
• char
• byte, short, int, long float, double
primitive types in Java
プリミティブ型
1.if either operand is double, widen both to double
2.else if either operand is float, widen both to float
3.else if either operand is long, widen both to long
4.else widen both operands to int
numeric promotion in == operation
== 演算における数値昇格
double や long など広い方の型に拡張変換する
1 == 1.0
https://www.artima.com/insidejvm/ed2/jvmP.html
primitive types
equality in Java
プリミティブ型は == を用いて比較。数値昇格が行われる。
128 == 128 // true
// true via numeric promotion JLS 15.21.1
1 == 1L
https://www.artima.com/insidejvm/ed2/jvmP.html
// false
Integer.valueOf(128) == Integer.valueOf(128)
// Error: incomparable types: java.lang.Integer and java.lang.Long
Integer.valueOf(128) == Long.valueOf(128L)
// true
Integer.valueOf(128).equals(Integer.valueOf(128))
// false
Integer.valueOf(1).equals(Long.valueOf(1L))
primitive types
boxed primitives
equality in Java
128
128
ボックス型は equals を用いて比較。数値昇格は無し。
128 == 128 // true
// true via numeric promotion JLS 15.21.1
1 == 1L
// true
Integer.valueOf(128).equals(Integer.valueOf(128))
// 128
Integer.valueOf(128).hashCode()
// 128
Integer.valueOf(128).hashCode()
reference types
equals and hashCode
128
128
2つのオブジェクトが equal な場合は
同じ hashCode() を返す約束
•if two objects are equals, they must return the
same hash codes
== in Scala
1. For value types, it uses numerical equality
2. For reference types, java.lang.Object#equals
that can be overridden
https://www.scala-lang.org/docu/files/ScalaOverview.pdf
値型は数値的等価性を用いる
参照型はオーバーライド可能な Object#equals を使う
eq in Scala
1. For reference types, use eq for reference
equality.
参照的等価性を使いたい場合は eq メソッドを使う
cooperative equality
協調的等価性 == の実装レベルでボックス型でも数値昇格を
エミュレート。さらっとボックス化するための仕組み。
scala> java.lang.Integer.valueOf(128) == java.lang.Long.valueOf(128L)
val res1: Boolean = true
scala> (128: Any).getClass
val res2: Class[_] = class java.lang.Integer
scala> (128: Any) == (128L: Any)
val res3: Boolean = true
scala> Set(128, 128L, "foo")
val res4: scala.collection.immutable.Set[Any] = Set(128, foo)
== emulates numeric promotion of boxed primitives
cooperative equality cont.
== は equal(...) と異なることに注意
hashCode() の代わりに ## というものが用意されている
scala> (128: Any) == (128L: Any)
val res3: Boolean = true
scala> (128: Any).equals(128L: Any)
val res5: Boolean = false
== is different from equals(...)
## is different from hashCode()
scala> (1.0: Any).hashCode()
val res6: Int = 1072693248
scala> (1.0: Any).##
val res7: Int = 1
scala/bug#11551
Scala 2.13.0-RC3 の段階で吉田さんが Set のバグを発見
https://twitter.com/xuwei_k/status/1134972015226449920 https://twitter.com/not_xuwei_k/status/1135372481156526081
scala/bug#11551
scala> Set[AnyVal](1L, 2L, 3L, 4L, 5L) + 1
res1: scala.collection.immutable.Set[AnyVal] = HashSet(5, 2, 3, 4, 1, 1)
1 is duplicated!
集合なのに1が重複しまっている
scala/bug#11551
scala> Set[AnyVal](1L, 2L, 3L, 4L, 5L) + 1
res1: scala.collection.immutable.Set[AnyVal] = HashSet(5, 2, 3, 4, 1, 1)
1 is duplicated!
修正は equals(...) を == で置き換えること
scala/bug#11551
警告機能の提言
Display warning on equals comparing non-
references #8120
Scala 2.13.4 から警告を出すようにしました
scala> def check[A](a1: A, a2: A): Boolean = a1.equals(a2)
^
warning: comparing values of types A and A using `equals` is
unsafe due to cooperative equality; use `==` instead
check: [A](a1: A, a2: A)Boolean
I implemented the warning
BCodeBodyBuilder
プリミティブ型の比較は Java 同様数値昇格が行われる
val tk = tpeTK(l).maxType(tpeTK(r))
genLoad(l, tk)
genLoad(r, tk)
genCJUMP(success, failure, op, tk, targetIfNoJump)
primitive type == is handled by genComparisonOp(...)
same numeric promotion as Java
BCodeBodyBuilder cont.
参照型の比較は、異なるボックス型の場合 BoxesRunTime
その他の場合は null 比較もしくは equals を用いる
reference type == is handled by genEqEqPrimitive(...)
1.if both sides are different boxed primitive types are
boxed floating point, use scala.runtime.BoxesRunTime.
2.if LHS is null literal, RHS eq null
3.if RHS is null literal, LHS eq null
4.if statically non-null (like "foo"), use Object#equals
5.otherwise, if (null eq this) null eq that
else this.equals(that)
universal equality
1. scala.Any (compiler fiction) defines == and
equals
2. since all values are a member of scala.Any, they
can be compared using ==
普遍的等価性
全ての値同士を == を用いて比較できる
unsound equality
絶対に真を返すことのできない式を書ける
これを不健全 (unsound) であると言う
scala> 1 == "1"
^
warning: comparing values of types Int and String using `==` will
always yield false
val res0: Boolean = false
scala> Option(1) == Option("1")
val res1: Boolean = false
== admits expressions that can never be true
unsound equality
Java の == は強い型付けを持っている
数値の取り扱いをナイスにする代わりに型安全性が犠牲に
scala> Option(1) == Option("1")
val res1: Boolean = false
Java has static and strongly-typed ==
java.util.Optional.of(1) == java.util.Optional.of("1");
| Error:
| incomparable types: java.util.Optional<java.lang.Integer> and
java.util.Optional<java.lang.String>
| java.util.Optional.of(1) == java.util.Optional.of("1");
| ^----------------------------------------------------^
scala> (128: Any) == (128L: Any)
val res3: Boolean = true
all for numeric niceness?
2010年
Eq typeclass
Scalaz は型クラスを用いた独自の === 等号を導入
コンパイル時に検査をするようになったが、Someを扱えない
trait Equal[A] { self =>
def equal(a1: A, a2: A): Boolean
}
scala> 1 === 1
val res0: Boolean = true
scala> 1 === "foo"
<console>:37: error: type mismatch;
found : String("foo")
required: Int
1 === "foo"
^
• Scalaz implemented
typeclass-based equality
• === is checked at
compile-time
• invariant version does
not handle Some(...)
vs None
2011年
"Rethinking equality"
等価性の再考
現行の実装は長く見れば見るほど醜く見える
•"Now that 2.9 is almost out the door, we have the
luxury to think of what could come next. One thing I
would like to address is equality. The current
version did not age well; the longer one looks at it,
the uglier it gets. In particular it is a great
impediment for DSL design. Witness the recent
popularity of === as an alternative equality
operator."
https://groups.google.com/g/scala-internals/c/MhIR30mYt-M/m/MHD0VHhMqoQJ
2016年
multiversal equality
多元的等価性
multiversal equality
sealed trait Eql[-L, -R]
scala> Option(1) == Option(1)
1 |Option(1) == Option(1)
|^^^^^^^^^^^^^^^^^^^^^^
|Values of types Option[Int] and Option[Int] cannot be compared with == or !=
scala> given eqlOption[A1, A2](using eq: Eql[A1, A2]) as Eql[Option[A1],
Option[A2]] = Eql.derived
scala> Option(1) == Option(1)
val res0: Boolean = true
scala> Option(1) == Some(1)
val res1: Boolean = true
scala> Option(1) == Option("foo")
1 |Option(1) == Option("foo")
|^^^^^^^^^^^^^^^^^^^^^^^^^^
|Values of types Option[Int] and Option[String] cannot be compared with == or !=.
|I found:
|
| eqlOption[Int, String](/* missing */summon[Eql[Int, String]])
• opt-in with -language:strictEquality flag or

import scala.language.strictEquality
コンパイラオプションによって使用可能となる
コンパイル時に型検査。自分で Option の型クラス導出する?
https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html
multiversal equality still supports numeric promotion
sealed trait Eql[-L, -R]
object Eql {
object derived extends Eql[Any, Any]
// Instances of `Eql` for common Java types
given eqlNumber as Eql[Number, Number] = derived
given eqlString as Eql[String, String] = derived
}
scala> 128 == 128L
val res3: Boolean = true
多元的等価性は数値昇格を行ってしまっている
これは外すべき機能
https://github.com/lampepfl/dotty/blob/0.27.0-RC1/library/src/scala/Eql.scala
we should remove eqlNumber instance
2020年
cooperative equality is closed-world
scala> import spire.math._
scala> Complex(1.0, 0.0) == 1.0
1 | Complex(1.0, 0.0) == 1.0
|^^^^^^^^^^^^^^^^^^^^^^^^^
|Values of types spire.math.Complex[Double] and Double cannot be compared
with == or !=
協調的等価性は ## の実装で協調するため閉じた世界
そのためライブラリは参加できない
•requires ## implementations to be aware of
each other
•libraries like Spire cannot participate in this!
equality in Valhalla
Valhalla の値の等価性は置換意味論を用いる
参照値の等価性は == であるインラインオブジェクトの参照
•Valhalla is an experimental OpenJDK project to
develop value types
•"Two object references are equal if they are both
null, or are both references to the same identity
object, or are both references to inline objects that
are == to each other. This extends
the substitutability semantics of == to all values –
two values are == only if it is not possible to
distinguish between them in any way (excepting
the legacy behavior of NaN.)"
https://cr.openjdk.java.net/~briangoetz/valhalla/sov/02-object-model.html
equality in Valhalla
Java 的には数値昇格は == の前に起こっていることのなので
Valhalla 後も数値昇格はそのままっぽい
•numeric promotion
is likely to stay in
Java
https://twitter.com/eed3si9n/status/1317150368380428292
making Scala 3 growable
多元的等価性を導入するタイミングで協調的等価性を外すこと
ができれば Scala 3 をより成長させることができる
•let's remove cooperative equality under strict
equality mode
•let's restore == and equals(...)
final def == (that: Any): Boolean =
if (null eq this) null eq that
else this.equals(that)
thanks and stay healthy
ご清聴ありがとうございます
metropolitan house supply
(2020.09 mixtape)

More Related Content

What's hot

BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
演習:プログラミング言語処理をやってみよう (ver.1.01)
演習:プログラミング言語処理をやってみよう (ver.1.01)演習:プログラミング言語処理をやってみよう (ver.1.01)
演習:プログラミング言語処理をやってみよう (ver.1.01)
Takashi Ishio
 
Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Ra Zon
 
What Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミットWhat Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミット
Taisuke Oe
 
演習:プログラミング言語処理をやってみよう
演習:プログラミング言語処理をやってみよう演習:プログラミング言語処理をやってみよう
演習:プログラミング言語処理をやってみよう
Takashi Ishio
 
JavaScriptクイックスタート
JavaScriptクイックスタートJavaScriptクイックスタート
JavaScriptクイックスタート
Shumpei Shiraishi
 
プログラミングHaskell(第1章)
プログラミングHaskell(第1章)プログラミングHaskell(第1章)
プログラミングHaskell(第1章)yaju88
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術
Naoki Aoyama
 
プログラミング言語Scala
プログラミング言語Scalaプログラミング言語Scala
プログラミング言語Scala
TanUkkii
 
Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス
Takuya Tsuchida
 
初心者講習会資料(Osaka.R#5)
初心者講習会資料(Osaka.R#5)初心者講習会資料(Osaka.R#5)
初心者講習会資料(Osaka.R#5)Masahiro Hayashi
 
磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!
Ra Zon
 
「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)
「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)
「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)
parrotstudio
 
Functional Programming in Swift
Functional Programming in SwiftFunctional Programming in Swift
Functional Programming in SwiftKaz Yoshikawa
 
AuxパターンをDottyで解決する
AuxパターンをDottyで解決するAuxパターンをDottyで解決する
AuxパターンをDottyで解決する
Taisuke Oe
 
Phantom Type in Scala
Phantom Type in ScalaPhantom Type in Scala
Phantom Type in Scala
Yasuyuki Maeda
 

What's hot (16)

BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
演習:プログラミング言語処理をやってみよう (ver.1.01)
演習:プログラミング言語処理をやってみよう (ver.1.01)演習:プログラミング言語処理をやってみよう (ver.1.01)
演習:プログラミング言語処理をやってみよう (ver.1.01)
 
Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]Scalaで萌える関数型プログラミング[完全版]
Scalaで萌える関数型プログラミング[完全版]
 
What Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミットWhat Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミット
 
演習:プログラミング言語処理をやってみよう
演習:プログラミング言語処理をやってみよう演習:プログラミング言語処理をやってみよう
演習:プログラミング言語処理をやってみよう
 
JavaScriptクイックスタート
JavaScriptクイックスタートJavaScriptクイックスタート
JavaScriptクイックスタート
 
プログラミングHaskell(第1章)
プログラミングHaskell(第1章)プログラミングHaskell(第1章)
プログラミングHaskell(第1章)
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術
 
プログラミング言語Scala
プログラミング言語Scalaプログラミング言語Scala
プログラミング言語Scala
 
Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス
 
初心者講習会資料(Osaka.R#5)
初心者講習会資料(Osaka.R#5)初心者講習会資料(Osaka.R#5)
初心者講習会資料(Osaka.R#5)
 
磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!磯野ー!関数型言語やろうぜー!
磯野ー!関数型言語やろうぜー!
 
「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)
「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)
「再代入なんて、あるわけない」 ~ふつうのプログラマが関数型言語を知るべき理由~ (Gunma.web #5 2011/05/14)
 
Functional Programming in Swift
Functional Programming in SwiftFunctional Programming in Swift
Functional Programming in Swift
 
AuxパターンをDottyで解決する
AuxパターンをDottyで解決するAuxパターンをDottyで解決する
AuxパターンをDottyで解決する
 
Phantom Type in Scala
Phantom Type in ScalaPhantom Type in Scala
Phantom Type in Scala
 

Similar to Equality in Scala (ScalaMatsuri 2020)

夏だからJava再入門
夏だからJava再入門夏だからJava再入門
夏だからJava再入門
Katsumi Honda
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
Ransui Iso
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
ゼロから始めるScala文法 (再)
ゼロから始めるScala文法 (再)ゼロから始めるScala文法 (再)
ゼロから始めるScala文法 (再)
Suguru Hamazaki
 
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章
Narimichi Takamura
 
RSpecのここがすごい!
RSpecのここがすごい!RSpecのここがすごい!
RSpecのここがすごい!
mitim
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門
Yasuko Ohba
 
Introduction to Spray at Kansai Functional Programming
Introduction to Spray at Kansai Functional ProgrammingIntroduction to Spray at Kansai Functional Programming
Introduction to Spray at Kansai Functional Programming
Suguru Hamazaki
 
Javaプログラミング入門【第2回】
Javaプログラミング入門【第2回】Javaプログラミング入門【第2回】
Javaプログラミング入門【第2回】
Yukiko Kato
 
オブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programmingオブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional ProgrammingTomoharu ASAMI
 
Cvpr2011 reading-tsubosaka
Cvpr2011 reading-tsubosakaCvpr2011 reading-tsubosaka
Cvpr2011 reading-tsubosaka正志 坪坂
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
Shinichi Kozake
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックスTomoharu ASAMI
 
初心者講習会資料(Osaka.R#7)
初心者講習会資料(Osaka.R#7)初心者講習会資料(Osaka.R#7)
初心者講習会資料(Osaka.R#7)
Masahiro Hayashi
 
Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値
Takuya Tsuchida
 
Thinking in Cats
Thinking in CatsThinking in Cats
Thinking in Cats
Eugene Yokota
 
すごい配列楽しく学ぼう
すごい配列楽しく学ぼうすごい配列楽しく学ぼう
すごい配列楽しく学ぼう
xenophobia__
 
第3回輪講
第3回輪講第3回輪講
第3回輪講
mh_amako
 

Similar to Equality in Scala (ScalaMatsuri 2020) (20)

夏だからJava再入門
夏だからJava再入門夏だからJava再入門
夏だからJava再入門
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
 
ATN No.2 Scala事始め
ATN No.2 Scala事始めATN No.2 Scala事始め
ATN No.2 Scala事始め
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
ゼロから始めるScala文法 (再)
ゼロから始めるScala文法 (再)ゼロから始めるScala文法 (再)
ゼロから始めるScala文法 (再)
 
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章
【Topotal輪読会】JavaScript で学ぶ関数型プログラミング 1 章
 
RSpecのここがすごい!
RSpecのここがすごい!RSpecのここがすごい!
RSpecのここがすごい!
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門
 
Introduction to Spray at Kansai Functional Programming
Introduction to Spray at Kansai Functional ProgrammingIntroduction to Spray at Kansai Functional Programming
Introduction to Spray at Kansai Functional Programming
 
Javaプログラミング入門【第2回】
Javaプログラミング入門【第2回】Javaプログラミング入門【第2回】
Javaプログラミング入門【第2回】
 
オブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programmingオブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programming
 
Cvpr2011 reading-tsubosaka
Cvpr2011 reading-tsubosakaCvpr2011 reading-tsubosaka
Cvpr2011 reading-tsubosaka
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックス
 
初心者講習会資料(Osaka.R#7)
初心者講習会資料(Osaka.R#7)初心者講習会資料(Osaka.R#7)
初心者講習会資料(Osaka.R#7)
 
Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値
 
Thinking in Cats
Thinking in CatsThinking in Cats
Thinking in Cats
 
すごい配列楽しく学ぼう
すごい配列楽しく学ぼうすごい配列楽しく学ぼう
すごい配列楽しく学ぼう
 
第3回輪講
第3回輪講第3回輪講
第3回輪講
 

More from Eugene Yokota

sbt: core concepts and updates (Scala Love 2020)
sbt: core concepts and updates (Scala Love 2020)sbt: core concepts and updates (Scala Love 2020)
sbt: core concepts and updates (Scala Love 2020)
Eugene Yokota
 
Analysis of Zinc (nescala 2020)
Analysis of Zinc (nescala 2020)Analysis of Zinc (nescala 2020)
Analysis of Zinc (nescala 2020)
Eugene Yokota
 
Analysis of Zinc (ScalaSphere 2019)
Analysis of Zinc (ScalaSphere 2019)Analysis of Zinc (ScalaSphere 2019)
Analysis of Zinc (ScalaSphere 2019)
Eugene Yokota
 
sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)
Eugene Yokota
 
pull requests I sent to scala/scala (ny-scala 2019)
pull requests I sent to scala/scala (ny-scala 2019)pull requests I sent to scala/scala (ny-scala 2019)
pull requests I sent to scala/scala (ny-scala 2019)
Eugene Yokota
 
sbt 1
sbt 1sbt 1
sbt server (LSP discussion, 2018 Jan)
sbt server (LSP discussion, 2018 Jan)sbt server (LSP discussion, 2018 Jan)
sbt server (LSP discussion, 2018 Jan)
Eugene Yokota
 
sbt, history of JSON libraries, microservices, and schema evolution (Tokyo ver)
sbt, history of JSON libraries, microservices, and schema evolution (Tokyo ver)sbt, history of JSON libraries, microservices, and schema evolution (Tokyo ver)
sbt, history of JSON libraries, microservices, and schema evolution (Tokyo ver)
Eugene Yokota
 
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
Eugene Yokota
 
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
Eugene Yokota
 
Road to sbt 1.0: Paved with server (2015 Amsterdam)
Road to sbt 1.0: Paved with server (2015 Amsterdam)Road to sbt 1.0: Paved with server (2015 Amsterdam)
Road to sbt 1.0: Paved with server (2015 Amsterdam)
Eugene Yokota
 
Road to sbt 1.0 paved with server
Road to sbt 1.0   paved with serverRoad to sbt 1.0   paved with server
Road to sbt 1.0 paved with server
Eugene Yokota
 

More from Eugene Yokota (12)

sbt: core concepts and updates (Scala Love 2020)
sbt: core concepts and updates (Scala Love 2020)sbt: core concepts and updates (Scala Love 2020)
sbt: core concepts and updates (Scala Love 2020)
 
Analysis of Zinc (nescala 2020)
Analysis of Zinc (nescala 2020)Analysis of Zinc (nescala 2020)
Analysis of Zinc (nescala 2020)
 
Analysis of Zinc (ScalaSphere 2019)
Analysis of Zinc (ScalaSphere 2019)Analysis of Zinc (ScalaSphere 2019)
Analysis of Zinc (ScalaSphere 2019)
 
sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)
 
pull requests I sent to scala/scala (ny-scala 2019)
pull requests I sent to scala/scala (ny-scala 2019)pull requests I sent to scala/scala (ny-scala 2019)
pull requests I sent to scala/scala (ny-scala 2019)
 
sbt 1
sbt 1sbt 1
sbt 1
 
sbt server (LSP discussion, 2018 Jan)
sbt server (LSP discussion, 2018 Jan)sbt server (LSP discussion, 2018 Jan)
sbt server (LSP discussion, 2018 Jan)
 
sbt, history of JSON libraries, microservices, and schema evolution (Tokyo ver)
sbt, history of JSON libraries, microservices, and schema evolution (Tokyo ver)sbt, history of JSON libraries, microservices, and schema evolution (Tokyo ver)
sbt, history of JSON libraries, microservices, and schema evolution (Tokyo ver)
 
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver)
 
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaMatsuri ver)
 
Road to sbt 1.0: Paved with server (2015 Amsterdam)
Road to sbt 1.0: Paved with server (2015 Amsterdam)Road to sbt 1.0: Paved with server (2015 Amsterdam)
Road to sbt 1.0: Paved with server (2015 Amsterdam)
 
Road to sbt 1.0 paved with server
Road to sbt 1.0   paved with serverRoad to sbt 1.0   paved with server
Road to sbt 1.0 paved with server
 

Equality in Scala (ScalaMatsuri 2020)

  • 3. OOPSLA: 1998 Growing a Language Guy Steele 「言語を成長させる」
  • 4. small vs large language 1. Small language: short time to learn 2. Large language: more vocabulary to use 小さい言語は習うのが容易 大きい言語はより多くの語彙を使うことができる
  • 5. primitive • "A primitive is a word for which we can take it for granted that we all know what it means." プリミティブとは、それが何を意味するのか自明とできる言葉
  • 6. language that can grow 1. APL: users cannot define symbols 2. LISP: user-defined words look like the primitives APL は優れた言語だが、ユーザはシンボル演算子を定義不可 LISP はユーザ定義でプリミティブ的なものを作れる
  • 7. language that can grow 1. Cathedral (one design) vs Bazaar (no one plan) 2. plan can change to meet the user 寺院設計は 1つの大計画、商店街は複数の計画を持つ ユーザのニーズに応えて計画を変更することができる
  • 8. making Java growable 1. Generic types 2. Operator overload Java を成長させる ジェネリック型と演算子のオーバーロード
  • 11. Java virtual machine https://www.artima.com/insidejvm/ed2/jvmP.html int c = a + b; iload_0 // push local var0 iload_1 // push local var0 iadd istore_2
  • 12. https://www.artima.com/insidejvm/ed2/jvmP.html int a = 1; java.util.Vector xs = new java.util.Vector(); xs.add(java.lang.Integer.valueOf(1)); primitive types boxed primitives スタックに直に積めるのがプリミティブデータ型 ヒープ上にオブジェクトとして包むことをボックス化と言う 1
  • 14. Lightweight Language 1. Easy to learn and use 2. Widely-used languages are coming from industry 3. Perl, Python, Ruby, (Scheme) http://ll1.ai.mit.edu/cfp.html LL言語とは何だったのか。実用言語が産業側から来てるとい うアカデミアにおける危機感。ライトなのは学びやすさ。
  • 17. "The name Scala stands for scalable language. The language is so named because it was designed to grow with the demands of its users. You can apply Scala to a wide range of programming tasks, from writing small scripts to building large systems." 'Programming in Scala', Odersky, Spoon, Venners Scala という名前は「スケーラブルな言語」を意味する ユーザーの求めに応じて成長していけるように設計されている Scala: a scalable language
  • 18. "Guy Steele noted in a talk on "growing a language" that the same distinction can be applied to language design. Scala is much more like a bazaar than a cathedral, in the sense that it is designed to be extended and adapted by the people programming in it." 'Programming in Scala', Odersky, Spoon, Venners Guy Steele は「言語を成長させる」という講演の中で 言語設計も「伽藍とバザール」が区別できると言っている Scala: a scalable language
  • 19. Scala 1. Abstract types 2. Operator overload 抽象型 演算子オーバーロード
  • 20. purely object-oriented 1. Everything-is-a- object, message passing 1 + 2 1.+(2) 純粋オブジェクト指向言語 全てがオブジェクト、全てがメッセージ・パッシング
  • 22. complex number in Scala (Spire) scala> import spire.implicits._, spire.math._ import spire.implicits._ import spire.math._ scala> Complex(1.0, 2.0) + Complex(3.0, 5.0) val res0: spire.math.Complex[Double] = (4.0 + 7.0i) scala> Complex(1.0, 2.0) * Complex(3.0, 5.0) val res1: spire.math.Complex[Double] = (-7.0 + 11.0i) Scala における複素数
  • 23. Scala 1. Intuitive and OO number types, like Python/Ruby 2. Extensibility 直観的かつオブジェクト指向な数値型 拡張性
  • 24. ==
  • 25. what is equality? •substitution property •for any a, b, and f(x): a == b ⇒ f(a) == f(b) •equivalence relation 等価性とは代入原理を満たす同値関係の1つ
  • 26. equivalence • reflexive • for any a (except NaN): a == a • symmetric • for any a, b: a == b ⇒ b == a • transitive • for any a, b, and c: a == b && b == c ⇒ a == c 同値関係は反射律、対称律、推移律
  • 27. equivalent, but not equal 合同な図形は同値関係にあるが等しくは無い these shapes are congruent in some context they could be considered "same"
  • 28. https://www.artima.com/insidejvm/ed2/jvmP.html • boolean • char • byte, short, int, long float, double primitive types in Java プリミティブ型
  • 29. 1.if either operand is double, widen both to double 2.else if either operand is float, widen both to float 3.else if either operand is long, widen both to long 4.else widen both operands to int numeric promotion in == operation == 演算における数値昇格 double や long など広い方の型に拡張変換する 1 == 1.0
  • 30. https://www.artima.com/insidejvm/ed2/jvmP.html primitive types equality in Java プリミティブ型は == を用いて比較。数値昇格が行われる。 128 == 128 // true // true via numeric promotion JLS 15.21.1 1 == 1L
  • 31. https://www.artima.com/insidejvm/ed2/jvmP.html // false Integer.valueOf(128) == Integer.valueOf(128) // Error: incomparable types: java.lang.Integer and java.lang.Long Integer.valueOf(128) == Long.valueOf(128L) // true Integer.valueOf(128).equals(Integer.valueOf(128)) // false Integer.valueOf(1).equals(Long.valueOf(1L)) primitive types boxed primitives equality in Java 128 128 ボックス型は equals を用いて比較。数値昇格は無し。 128 == 128 // true // true via numeric promotion JLS 15.21.1 1 == 1L
  • 32. // true Integer.valueOf(128).equals(Integer.valueOf(128)) // 128 Integer.valueOf(128).hashCode() // 128 Integer.valueOf(128).hashCode() reference types equals and hashCode 128 128 2つのオブジェクトが equal な場合は 同じ hashCode() を返す約束 •if two objects are equals, they must return the same hash codes
  • 33. == in Scala 1. For value types, it uses numerical equality 2. For reference types, java.lang.Object#equals that can be overridden https://www.scala-lang.org/docu/files/ScalaOverview.pdf 値型は数値的等価性を用いる 参照型はオーバーライド可能な Object#equals を使う
  • 34. eq in Scala 1. For reference types, use eq for reference equality. 参照的等価性を使いたい場合は eq メソッドを使う
  • 35. cooperative equality 協調的等価性 == の実装レベルでボックス型でも数値昇格を エミュレート。さらっとボックス化するための仕組み。 scala> java.lang.Integer.valueOf(128) == java.lang.Long.valueOf(128L) val res1: Boolean = true scala> (128: Any).getClass val res2: Class[_] = class java.lang.Integer scala> (128: Any) == (128L: Any) val res3: Boolean = true scala> Set(128, 128L, "foo") val res4: scala.collection.immutable.Set[Any] = Set(128, foo) == emulates numeric promotion of boxed primitives
  • 36. cooperative equality cont. == は equal(...) と異なることに注意 hashCode() の代わりに ## というものが用意されている scala> (128: Any) == (128L: Any) val res3: Boolean = true scala> (128: Any).equals(128L: Any) val res5: Boolean = false == is different from equals(...) ## is different from hashCode() scala> (1.0: Any).hashCode() val res6: Int = 1072693248 scala> (1.0: Any).## val res7: Int = 1
  • 37. scala/bug#11551 Scala 2.13.0-RC3 の段階で吉田さんが Set のバグを発見 https://twitter.com/xuwei_k/status/1134972015226449920 https://twitter.com/not_xuwei_k/status/1135372481156526081
  • 38. scala/bug#11551 scala> Set[AnyVal](1L, 2L, 3L, 4L, 5L) + 1 res1: scala.collection.immutable.Set[AnyVal] = HashSet(5, 2, 3, 4, 1, 1) 1 is duplicated! 集合なのに1が重複しまっている
  • 39. scala/bug#11551 scala> Set[AnyVal](1L, 2L, 3L, 4L, 5L) + 1 res1: scala.collection.immutable.Set[AnyVal] = HashSet(5, 2, 3, 4, 1, 1) 1 is duplicated! 修正は equals(...) を == で置き換えること
  • 41. Display warning on equals comparing non- references #8120 Scala 2.13.4 から警告を出すようにしました scala> def check[A](a1: A, a2: A): Boolean = a1.equals(a2) ^ warning: comparing values of types A and A using `equals` is unsafe due to cooperative equality; use `==` instead check: [A](a1: A, a2: A)Boolean I implemented the warning
  • 42. BCodeBodyBuilder プリミティブ型の比較は Java 同様数値昇格が行われる val tk = tpeTK(l).maxType(tpeTK(r)) genLoad(l, tk) genLoad(r, tk) genCJUMP(success, failure, op, tk, targetIfNoJump) primitive type == is handled by genComparisonOp(...) same numeric promotion as Java
  • 43. BCodeBodyBuilder cont. 参照型の比較は、異なるボックス型の場合 BoxesRunTime その他の場合は null 比較もしくは equals を用いる reference type == is handled by genEqEqPrimitive(...) 1.if both sides are different boxed primitive types are boxed floating point, use scala.runtime.BoxesRunTime. 2.if LHS is null literal, RHS eq null 3.if RHS is null literal, LHS eq null 4.if statically non-null (like "foo"), use Object#equals 5.otherwise, if (null eq this) null eq that else this.equals(that)
  • 44. universal equality 1. scala.Any (compiler fiction) defines == and equals 2. since all values are a member of scala.Any, they can be compared using == 普遍的等価性 全ての値同士を == を用いて比較できる
  • 45. unsound equality 絶対に真を返すことのできない式を書ける これを不健全 (unsound) であると言う scala> 1 == "1" ^ warning: comparing values of types Int and String using `==` will always yield false val res0: Boolean = false scala> Option(1) == Option("1") val res1: Boolean = false == admits expressions that can never be true
  • 46. unsound equality Java の == は強い型付けを持っている 数値の取り扱いをナイスにする代わりに型安全性が犠牲に scala> Option(1) == Option("1") val res1: Boolean = false Java has static and strongly-typed == java.util.Optional.of(1) == java.util.Optional.of("1"); | Error: | incomparable types: java.util.Optional<java.lang.Integer> and java.util.Optional<java.lang.String> | java.util.Optional.of(1) == java.util.Optional.of("1"); | ^----------------------------------------------------^ scala> (128: Any) == (128L: Any) val res3: Boolean = true all for numeric niceness?
  • 48. Eq typeclass Scalaz は型クラスを用いた独自の === 等号を導入 コンパイル時に検査をするようになったが、Someを扱えない trait Equal[A] { self => def equal(a1: A, a2: A): Boolean } scala> 1 === 1 val res0: Boolean = true scala> 1 === "foo" <console>:37: error: type mismatch; found : String("foo") required: Int 1 === "foo" ^ • Scalaz implemented typeclass-based equality • === is checked at compile-time • invariant version does not handle Some(...) vs None
  • 50. "Rethinking equality" 等価性の再考 現行の実装は長く見れば見るほど醜く見える •"Now that 2.9 is almost out the door, we have the luxury to think of what could come next. One thing I would like to address is equality. The current version did not age well; the longer one looks at it, the uglier it gets. In particular it is a great impediment for DSL design. Witness the recent popularity of === as an alternative equality operator." https://groups.google.com/g/scala-internals/c/MhIR30mYt-M/m/MHD0VHhMqoQJ
  • 53. multiversal equality sealed trait Eql[-L, -R] scala> Option(1) == Option(1) 1 |Option(1) == Option(1) |^^^^^^^^^^^^^^^^^^^^^^ |Values of types Option[Int] and Option[Int] cannot be compared with == or != scala> given eqlOption[A1, A2](using eq: Eql[A1, A2]) as Eql[Option[A1], Option[A2]] = Eql.derived scala> Option(1) == Option(1) val res0: Boolean = true scala> Option(1) == Some(1) val res1: Boolean = true scala> Option(1) == Option("foo") 1 |Option(1) == Option("foo") |^^^^^^^^^^^^^^^^^^^^^^^^^^ |Values of types Option[Int] and Option[String] cannot be compared with == or !=. |I found: | | eqlOption[Int, String](/* missing */summon[Eql[Int, String]]) • opt-in with -language:strictEquality flag or
 import scala.language.strictEquality コンパイラオプションによって使用可能となる コンパイル時に型検査。自分で Option の型クラス導出する? https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality.html
  • 54. multiversal equality still supports numeric promotion sealed trait Eql[-L, -R] object Eql { object derived extends Eql[Any, Any] // Instances of `Eql` for common Java types given eqlNumber as Eql[Number, Number] = derived given eqlString as Eql[String, String] = derived } scala> 128 == 128L val res3: Boolean = true 多元的等価性は数値昇格を行ってしまっている これは外すべき機能 https://github.com/lampepfl/dotty/blob/0.27.0-RC1/library/src/scala/Eql.scala we should remove eqlNumber instance
  • 56. cooperative equality is closed-world scala> import spire.math._ scala> Complex(1.0, 0.0) == 1.0 1 | Complex(1.0, 0.0) == 1.0 |^^^^^^^^^^^^^^^^^^^^^^^^^ |Values of types spire.math.Complex[Double] and Double cannot be compared with == or != 協調的等価性は ## の実装で協調するため閉じた世界 そのためライブラリは参加できない •requires ## implementations to be aware of each other •libraries like Spire cannot participate in this!
  • 57. equality in Valhalla Valhalla の値の等価性は置換意味論を用いる 参照値の等価性は == であるインラインオブジェクトの参照 •Valhalla is an experimental OpenJDK project to develop value types •"Two object references are equal if they are both null, or are both references to the same identity object, or are both references to inline objects that are == to each other. This extends the substitutability semantics of == to all values – two values are == only if it is not possible to distinguish between them in any way (excepting the legacy behavior of NaN.)" https://cr.openjdk.java.net/~briangoetz/valhalla/sov/02-object-model.html
  • 58. equality in Valhalla Java 的には数値昇格は == の前に起こっていることのなので Valhalla 後も数値昇格はそのままっぽい •numeric promotion is likely to stay in Java https://twitter.com/eed3si9n/status/1317150368380428292
  • 59. making Scala 3 growable 多元的等価性を導入するタイミングで協調的等価性を外すこと ができれば Scala 3 をより成長させることができる •let's remove cooperative equality under strict equality mode •let's restore == and equals(...) final def == (that: Any): Boolean = if (null eq this) null eq that else this.equals(that)
  • 60. thanks and stay healthy ご清聴ありがとうございます