Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
型なし言語のための型
Search
Soutaro Matsumoto
November 03, 2019
Programming
7
13k
型なし言語のための型
富山Ruby会議01
Soutaro Matsumoto
November 03, 2019
Tweet
Share
More Decks by Soutaro Matsumoto
See All by Soutaro Matsumoto
API for docs
soutaro
4
3k
Rubyの標準添付ライブラリを開発する
soutaro
2
210
Embedding it into Ruby code
soutaro
4
25k
Parsing RBS
soutaro
0
1.8k
Ruby programming with types in action
soutaro
4
960
IDE Development with Ruby
soutaro
4
1.1k
Ruby 3の新機能としての静的型検査の開発
soutaro
4
7.6k
An Introduction to Static Typing in Ruby 3
soutaro
3
450
The State of Ruby 3 Typing
soutaro
0
730
Other Decks in Programming
See All in Programming
堅牢なフロントエンドテスト基盤を構築するために行った取り組み
shogo4131
8
2.3k
ViewファーストなRailsアプリ開発のたのしさ
sugiwe
0
430
「コードは上から下へ読むのが一番」と思った時に、思い出してほしい話
panda728
PRO
38
25k
Cell-Based Architecture
larchanjo
0
100
著者と進める!『AIと個人開発したくなったらまずCursorで要件定義だ!』
yasunacoffee
0
120
Tinkerbellから学ぶ、Podで DHCPをリッスンする手法
tomokon
0
120
FluorTracer / RayTracingCamp11
kugimasa
0
220
複数人でのCLI/Infrastructure as Codeの暮らしを良くする
shmokmt
5
2.2k
JETLS.jl ─ A New Language Server for Julia
abap34
1
200
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
120
LLMで複雑な検索条件アセットから脱却する!! 生成的検索インタフェースの設計論
po3rin
2
650
AWS CDKの推しポイントN選
akihisaikeda
1
240
Featured
See All Featured
Making the Leap to Tech Lead
cromwellryan
135
9.7k
The Power of CSS Pseudo Elements
geoffreycrofte
80
6.1k
Facilitating Awesome Meetings
lara
57
6.7k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.5k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
15k
How to Ace a Technical Interview
jacobian
280
24k
Designing for humans not robots
tammielis
254
26k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
196
69k
[RailsConf 2023] Rails as a piece of cake
palkan
58
6.1k
Transcript
ܕͳ͠ݴޠͷͨΊͷܕ দຊफଠ !TPVUBSP
@soutaro
@soutaro
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::Conference
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::Conference () { (::Talk) -> void } -> self
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::String ::Conference () { (::Talk) -> void } -> self
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language ༻ ༻
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language ༻ ༻ Ruby3ʹಉࠝ ͖ͳͷΛΠϯετʔϧ
3#4SVCZTJHOBUVSF w 3#4ΛಡΜͰɺΫϥεఆٛͷใΛॲཧ͢ΔϥΠϒϥϦ w ৄ͘͠དྷिͷ3VCZ)BDL$IBMMFOHF)PMJEBZͰ IUUQTSIDDPOOQBTTDPNFWFOU class Set[A] def initialize:
(_Each[A, untyped]) -> void | () -> void def intersection: (_Each[A, untyped]) -> self ... end
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
ܕͳ͠ݴޠͷͨΊͷܕ w ܕ w ίϯύΠϧ࣌ʹ໌͢Δࣜͷଐੑ w ͋ΔछͷޡΓΛݕग़Ͱ͖Δʢܕݕࠪʣ w ܕͳ͠ݴޠ w
ίϯύΠϧ࣌ʹܕݕࠪ͞Εͳ͍ݴޠʢ㲈ಈతܕ͚ݴޠʣ w 3VCZͱ͔
ίʔυฤू ίϯύΠϧ ࣮ߦ ܕݕࠪ ίʔυฤू ίϯύΠϧ ࣮ߦ ܕݕࠪ
class Person def name @name end def name=(value) @name =
value end end if rand(10) < 5 person = Person.new person.nme = "Soutaro Matsumoto" # NoMethodError end w ܕݕࠪʹΑͬͯɺཏతʹʢJGͷதʣݕࠪ͞Εͯɺ࣮ ߦલʹ͕ݕग़͞ΕΔʢίϯύΠϧ࣌ʣ w ܕݕࠪ͠ͳ͍߹ʹɺϓϩάϥϜͷ࣮ߦঢ়گʹΑͬ ͯɺ͕ݟ͔ͭΒͳ͍ʢ࣮ߦ࣌ʣ
ܕݕࠪͷಘࣦ w ͕ࣄલʹݕग़Ͱ͖Δ w ཏతͳݕࠪʢ࣮ߦͷύεʹґଘ͠ͳ͍ʣ w ॻ͚ΔϓϩάϥϜʹ੍ݶ͕ՃΘΔ w ࣮ࡍʹ࣮ߦ͞Εͳ͍ύεʹ͍ͭͯݕࠪ͞Εͯ͠·͏
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
.-ͷܕਪ w ʮ࠙ஸೡʹશ෦ͷࣜʹܕΛॻ͔ͳͯ͘ྑ͍ʯͱ͍͏ൃݟ w ύϥϝʔλଟ૬ʢେମ(FOFSJDTͷ͜ͱʣ # let rec map f
xs = match xs with [] -> [] | x::xs -> f x :: map f xs;; val map : ('a -> 'b) -> 'a list -> 'b list = <fun>
4PGU5ZQJOH w ܕͳ͠ͷݴޠʹܕΛ͚͍ͨ w ܕ͕͍ͭͨ෦Τϥʔ͕ݕग़Ͱ͖Δ w Θ͔Βͳ͍ͷ࣮ߦ࣌ʹݕࠪ͢Δ w ಈ͘ϓϩάϥϜͰ͖Δ͚ͩͦͷ··ܕݕࠪΛ௨͍ͨ͠ w
ܕऍઈରॻ͖ͨ͘ͳ͍
6OJPOUZQFT def f(x) if x 1 else "2" end end
6OJPOUZQFT def f(x) if x 1 else "2" end end
(bool) -> (Integer | String)
'MPXTFOTJUJWF5ZQJOH def g(n) n.abs # NoMethodError n.bytes # n: Integer
| String case n when Integer n.abs # n: Integer when String n.bytes # n: String end end (Integer | String) -> Integer
4PGU5ZQJOH w 4DIFNFϓϩάϥϜͷܕ͚ʹඞཁͳͷ͕Θ͔ͬͨ w 6OJPOUZQFT 'MPXTFOTJUJWFUZQJOH w ࣮ w
.-ͷܕਪʹجͮ͘ͷ w ϑϩʔղੳ͢Δͷ
ͬͱۙతͳݴޠͰʁ w +BWB4DSJQUͱ͔3VCZͱ͔< > w ΦϒδΣΫτʹର͢Δଟ૬ੑ BLBμοΫλΠϐϯά w ʮ͋Δϝιου͕ఆٛ͞Ε͍ͯΔҙͷΫϥεʯΈ͍ͨͳܕ
def add(x, y) x + y end def add: [A, B] ({ +: (A) -> B }, A) -> B
3VCZͰࢼͨ͠ͱ͜Ζ w ͬͺΓݫ͍͠ w .-ͷܕਪͰॲཧͰ͖ͳ͍ఆ͕ٛͰͯ͘Δ "SSBZNBQ w Ϋϥεఆ໋͕ٛྩతʹมΘ͍ͬͯ͘ͷ͕ݫ͍͠ʢϝλϓϩάϥϛϯάʣ w
ͦͦյΕ͍ͯΔఆ͕ٛͨ͘͞Μ͋Δ w "SSBZTFMFDUWT0CKFDUTFMFDU w )BTIΛฦ͢IBTIΛఆٛͨ͜͠ͱ͕ͳ͍ਓ
"SSBZJTB0CKFDU w 0CKFDUʹରͯ͠ಈ͘ϓϩάϥϜ"SSBZʹରͯ͠ಈ͘ʁʁ class Object def use_select select [STDIN], [],
[] end end "".use_select # OK [1,2,3].use_select # ????
4PGU5ZQJOH͔ΒಘΒΕͨݟ w จͰޭ͍ͯ͠ΔΑ͏ʹݟ͑Δ͕࣮༻Ϩϕϧͷͷͳ͍ w ඞཁͦ͏ͳܕγεςϜͷػೳΘ͔͖ͬͯͨ w Ή͠ΖܕΛॻ͍ͨํ͕ྑ͍ͷͰʁʁ w ϓϩάϥϚͷҙਤΛܕͰදݱ͢Δ w
ҙਤͱҰக͠ͳ͍ίʔυΛݕग़͢Δ
(SBEVBM5ZQJOH w ਐతܕ͚ w ܕͳ͠ͷίʔυͱܕ͖ͭͷίʔυΛࠞͥΔ w ͩΜͩΜܕΛ͚͍ͯ͘ w ܕॻ͘
ܕͳ͠ݴޠͷͨΊͷܕ w ͦΕͳΓʹڧྗͳܕγεςϜ w 6OJPOUZQFT qPXTFOTJUJWFUZQJOH HFOFSJDT w μοΫλΠϐϯά
w ߏత෦ܕ w ΫϥεͷܧঝؔΛ͋ͱͰมߋͰ͖ΔΈ )BTLFMM 4XJGU $ w (SBEVBM5ZQJOH
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
࠷ۙͷྲྀߦ w ܕ͖ͭͷํݴ w 5ZQF4DSJQU 5ZQFE4DIFNF w ܕऍͷαϙʔτ w 1ZUIPO
1)1
5ZQF4DSJQU w ݱࡏͰҰ൪উ͍ͬͯΔܕ͖ͭํݴ w λʔήοτݴޠ+4ʢϥϯλΠϜ+4ʣ class Drawer<ClothingType> { contents: ClothingType[]
= []; add(object: ClothingType) { this.contents.push(object); } } interface Sock { color: string } interface TShirt { size: "s" | "m" | "l" } const drawer: Drawer<Sock> = new Drawer() drawer.push({ color: "white" }) drawer.push({ size: "s" })
5ZQF4DSJQUͷ͍͢͝ͱ͜Ζ w ܕͳ͠ݴޠʹܕΛ͚Δਓྨͷເ͕ͬͨ w ΈΜͳܕΛॻ͍͍ͯΔͷ͕͍͢͝ w ߏతͳܕ͚ͩͰͳΜͱ͔ͳͬͯΔͷ͕͍͢͝ w 6OJPOUZQFTͱ͔qPXTFOTJUJWFUZQFTͱ͔MPHJDBMUZQFTͱ͔͠Εͬͱ ೖͬͯΔͷ͕͍͢͝
w ϥϯλΠϜͱͷ੍ΛΓӽ͑ͯಈ͍ͯΔͷ͕͍͢͝
ܕॻ͔ͳ͍͚ͯ͘ͳ͍ w ΑͬΆͲࣗ໌ͳͷҎ֎ॻ͘ w ϥΠϒϥϦͷܕEFpOJUFMZUZQFEʹू·͍ͬͯΔ const numbers: number[] = [1,2,3]
numbers.map<string>(x => x.toString())
jQuery.d.ts
ߏతͳܕ w ΫϥεͷܧঝؔͰͳ͘ɺϝιουͷू߹Ͱ෦ܕؔΛఆ͢Δ w ߏతͳܕ͚ͩͱ͍͏ͷ͍͠ w ͋Δ interface ForEach<A> {
forEach: (fun: (a: A) => void) => void } const x: ForEach<number> = [1,2,3]
ͨ·ͨ·ಉ͡ߏ͕͋ͬͨΒʁ w 5γϟπͱζϘϯ͕۠ผͰ͖ͳ͘ͳΔ w #SBOEFEUZQFͰରԠ͢Δ interface TShirt { size: "s"
| "m" | "l"; } interface Pants { size: "s" | "m" | "l"; }
ͨ·ͨ·ಉ͡ߏ͕͋ͬͨΒʁ w 5γϟπͱζϘϯ͕۠ผͰ͖ͳ͘ͳΔ w #SBOEFEUZQFͰରԠ͢Δ interface TShirt { size: "s"
| "m" | "l"; } interface Pants { size: "s" | "m" | "l"; } interface TShirt { type: "tshirt" size: "s" | "m" | "l"; } interface Pants { type: "pants" size: "s" | "m" | "l"; }
6OJPO5ZQFT'MPXTFOTJUJWF5ZQJOH w OVMMVOEFpOFEͱ͏·͘ΕΔΑ͏ʹͳͬͨ const x: string | undefined = ...
// Object is possibly 'undefined'. x.toUpperCase() if (x) { x.toUpperCase() }
ϥϯλΠϜͷ੍ w +4ͷϥϯλΠϜʹͰ͖ͳ͍͜ͱ54ͰͰ͖ͳ͍ w ʮ͋Δ͕ΠϯλʔϑΣʔεʹద߹͍ͯ͠Δ͔ݕ͍ࠪͨ͠ʯ w Ϣʔβʔ͕ࣗͷͰݕূ͢Δ -PHJDBMUZQFT •
function isPants(object: any): object is Pants { return object.type == "pants" }
ݟ w ਓؒܕΛॻ͘ w ʢܕΛॻ͖ͨ͘ͳ͍ਓ5ZQF4DSJQUΛΘͳ͍ͷͰ؍ଌͰ͖ͳ͍ʣ w େମ+BWB4DSJQUͷίʔυʹܕ͕ͭ͘ w 6OJPOUZQFTͱ͔qPXTFOTJUJWFUZQJOHͱ͔͕ॏཁ w
ߏత෦ܕಈ͘ w ϥϯλΠϜͷ੍ݶΛΓӽ͑ΔͨΊ JTܕ
1ZUIPO 1)1 w ϝιουͷܕΛॻ͘ه๏͕ಋೖ͞Εͨ w ܕݕ࣮ࠪߦ࣌ w ϝιουݺͼग़͠ͷͱ͖ʹܕݕࠪ͢Δ w ੩తͳܕݕࠪث։ൃ͞Ε͍ͯΔ
function sum(int $a, int $b) { return $a + $b; }
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
3VCZͷͨΊͷܕ w 4PGUUZQJOHͷݟˠਪΛؤுΔͷઓతʢ!NBNFʣ w 5ZQF4DSJQUͷݟ w ਓྨܕΛॻ͘ w ͦΕͳΓʹڧྗͳܕγεςϜ͕͋Ε্ख͘Εͦ͏ w
1ZUIPO 1)1ͷݟ w ܕऍܾΊͳ͍ͱ͍͚ͳ͍ w ܕݕࠪثผπʔϧʹ͢Δ
ܕऍͷه๏ 3#4 w গͳ͘ͱϥΠϒϥϦͷܕΛॻ͘ํ๏͕ඞཁ w ܕݕࠪπʔϧ͕ͦΕͧΕʹ༻ҙ͢Δͷ͔ͳΓݫ͍͠ w ϥϯλΠϜͷݕ͕ࠪͰ͖Δ͚ͩͰͦΕͳΓʹخ͍͠Ͱʁ w ιʔείʔυʹຒΊࠐΉߏจ࠾༻͠ͳ͍
ΈࠐΈͷܕऍߏจʢෆ࠾༻ʣ class Box extend T::Sig extend T::Generic Elem = type_member
sig {returns(Elem)} # @type var box: Box[Integer] box = Box.new box.x = "hello" &NCFEEFE%4- 4PSCFU $PNNFOUT 4UFFQ class Box [A] def value: A; ...; end def value=(value: A): A; ...; end end a: Box[Integer] = Box.new
ͦΕͳΓʹϦονͳܕ w λϓϧɺϨίʔυ [Integer, Symbol] w Ϧςϥϧܕ 1, "hello", :world
w 6OJPOUZQFT Integer | String w 0QUJPOBMUZQFTɺ(FOFSJDTʜ Array[String]? w յΕ͍ͯΔͷJODPNQBUJCMF incompatible def select: [A] () { (Elem) -> A
μοΫλΠϐϯά w JOUFSGBDFΛఆٛͯ͠ɺཁٻ͞ΕΔϝιουͷू߹Λॻ͘ w ϝιου͕͋Δ͔ͳ͍͔Ͱݕࠪ͞ΕΔ interface _Push def <<: (String)
-> void end def foo: (_Push) -> void def foo(a) a << "hello" end foo [] foo "" foo 3 # Τϥʔ
࣮ߦ࣌ݕ͚ࠪͩͰ w γάωνϟΛॻ͍ͨΒɺϢχοτςετͰςετ͢Δํ๏Λఏڙ w ϝιουݺͼग़͠ͷલޙʹܕݕࠪΛૠೖ w IUUQTSIDDPOOQBTTDPNFWFOU $ RBS_TEST_TARGET='Goodcheck::*' \
RBS_TEST_RAISE=true \ RUBYOPT='-rbundler/setup -rruby/signature/test/setup' \ RBS_TEST_OPT='-rset -rpathname -Isig' \ bundle exec rake test
IUUQTHJUIVCDPNTJEFSHPPEDIFDLUSFFSCT
·ͱΊ w 4PGUUZQJOHΈ͍ͨʹਪΛؤுΔͷ߹ཧతͰͳ͍ w ܕΛॻ͔ͳ͍ͷݫ͍͠ w ਓؒܕΛॻ͘ʢ͜͜ͰಘΒΕͨݟʣ w 3VCZͷͨΊͷܕ w
ΘΓͱϦονͳܕ(FOFSJDTɺ6OJPOUZQFTɺ'MPXTFOTJUJWFUZQJOH w μοΫλΠϐϯάؤுΔʢߏత෦ܕʣ
w <$BSUXSJHIU >3$BSUXSJHIUBOE.'BHBO4PGUUZQJOH w <.BUTVNPUP >4.BUTVNPUPBOE:.JOBNJEF5ZQF*OGFSFODFGPS3VCZ 1SPHSBNTCBTFEPO1PMZNPSQIJD3FDPSE5ZQFT w <+FOTFO >4)+FOTFOBOE".MMFSBOE15IJFNBOO
5ZQF"OBMZTJTGPS +BWB4DSJQU w <4JFL >+4JFLBOE85BIB (SBEVBM5ZQJOHGPS0CKFDUT w <)PDITUBEU >45)PDITUBEU 5ZQFE4DIFNF'SPN4DSJQUTUP1SPHSBNT w