Slide 1

Slide 1 text

Ruby 
 ܕผᒾҰ޻۩؆հ John Lin (@johnlinvc)

Slide 2

Slide 2 text

᮫ԙզ • John Lin • تᓣ Ruby & Swiftɻओ㭎Swift Taipei Meetupɻ • Twitter: @johnlinvc • Blog: https://johnlin.vc/ • Principle Solution Architect @ West Pharmaceutical Service (੢ࣜဌऱ)

Slide 3

Slide 3 text

ڧྗ㐸࠽த • ୆๺ओཁੋ၏ᬭྍᢛ޻ۀ IoT ɻूᅶᚙలॏ৺೭Ұɻ • google "cake resume west"ɼ༗ෟ਋ࢿൣᅴɻ • ౤ཤ㑖త࣌㘸ੋ John Lin հ঺తɻိత࿩ referral bonus ෼㟬Ұ൒ɻ • Coscup ᩶ॿ঎

Slide 4

Slide 4 text

Agenda • Ruby తܕผܥ౷ • ܕผᒾҰత޷႔ • Ruby ܕผᒾҰ޻۩తಛ৭ • Sorbet • Steep • ൺֱ Ruby తܕผᒾҰ޻۩ • Q&A

Slide 5

Slide 5 text

Ruby తܕผܥ౷ • ڧܕผ Strong Type • ಈଶܕผ Dynamic Type • יࢠܕผ Duck typing • ॴ༗౦੢౎ੋ෺݅ Everything is object • ᄸҰ៺ঝ Single Inheritance • Mixin • nil

Slide 6

Slide 6 text

ܕผᒾҰత޷႔ • ᒾҰଧࣈࡨޡ • ᒾҰჩᏐၚᬇࡨޡ • ఏߴఔࣜᛰతՄᯪੑ • ՄҎॱศఏڙఔࣜᛰతࢿ㘤څ IDEɻ

Slide 7

Slide 7 text

Ruby ܕผᒾҰ޻۩తڞಉಛ৭ • ᔒ༗׭ํతܕผᒾҰ޻۩ • ઴ਐࣜܕผᒾҰ Gradual type checker. • ܕผఆٛ䈕 Type def fi les

Slide 8

Slide 8 text

ᔒ༗׭ํతܕผᒾҰ޻۩ • ᔒ༗׭ํతܕผᒾҰ޻۩ɻ • ୠੋ༗׭ํతܕผඪ஫ɼRuby Signature (RBS) ɻ • Python & javascript ໵ੋҰᒬɻ

Slide 9

Slide 9 text

RBS ܕผఆٛ䈕 • Ruby ׭ํతܕผఆٛ֨ࣜɻ • ᘐཱ䈕Ҋɻ • ՄҎኺݪ࢝ᛰࣗಈ㗞ੜൣຊɻ

Slide 10

Slide 10 text

઴ਐࣜܕผᒾҰ Gradual Type Check • ՄҎ୞ᒾҰ෦෼తఔࣜᛰɻ • ߱௿ಋೖ೉౓ɻ • Python(mypy) & TypeScript ౎ੋɻ

Slide 11

Slide 11 text

ܕผఆٛ䈕 • ᘐཱత䈕Ҋɻ • ఆٛྃܕผɼৗᏐɼํ๏ɼݸᱪᏓᏐతܕผɻ • class Foo def bar(s); end end class Foo def bar: (s: String) -> String end

Slide 12

Slide 12 text

ܕผ஫ᩄ (type annotation) • ࡏఔࣜᛰதՃ্Ḽղ҃ੋֹ֎తඪࣔɻ • ૾ੋ C++, Python ҃ Typescript ౎ੋɻ class Foo sig{params(s: String).returns(String)} def bar(s) end end

Slide 13

Slide 13 text

ܕผఆٛ䈕త༏᠍ᴍ • ᠍ᴍɿఔࣜ࿨ܕผఆٛࡏෆಉ䈕ҊɼՄೳ။๨هվɻ • ༏ᴍɿఔࣜޠ๏ൺֱᄸ७ɻ

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

ܕผఆٛ䈕 V.S. ܕผ஫ᩄ (type annotation) • Matz: • ఔࣜෆधཁܕผඪࣔब။ಈɻtype annotation ҧ൓ྃ DRY(Don't Repeat Yourself) ݪଇɻ • ະိՊٕ଍ⴺਐ㑊ޙɼ༗Մೳ׬શෆधཁܕผఆٛ䈕ɻ

Slide 16

Slide 16 text

Ruby ܕผ෼ੳ޻۩ • Sorbet • Steep

Slide 17

Slide 17 text

Sorbet • ༝ Stripe ։ᚙɼ༻ C++ & Rubyሜతɻ • ᯩଶᒾҰ ˍ ಈଶᒾҰ • 㚎ݐޠݴ࢕෰ثڠఆ(Language Server Protocol, LSP) • ෆಉ౳ڃత઴ਐࣜᒾҰ • ಉ࣌ࢧԉ ܕผ஫ᩄ(Type Annotation) ᢛ RBI ܕผఆٛ䈕ɻ

Slide 18

Slide 18 text

ᯩଶᒾҰ • ࣥߦsorbet ိᒾҰܕผɼෆधཁਅతࣥߦఔࣜɻ • ࢖༻৘ڥɿሜఔࣜதɼ౥഑ lsp serverɻ࿈᠃੔߹(CI)ɻ

Slide 19

Slide 19 text

ಈଶᒾҰ • ࣥߦఔࣜత࣌ީɼSorbet ။ᒾҰܕผฒ׌㗞ੜࡨޡ҃Log • ࢖༻৘ڥɿ࿈᠃੔߹(CI)தతᄸݩଌࢼ҃੔߹ଌࢼɻ༬උ؀ ڥ(Staging)ɻਖ਼ࣜ؀ڥɻ

Slide 20

Slide 20 text

㚎ݐޠݴ࢕෰ثڠఆ • ౥഑ VSCode ҃ Emacs ౳ࢧԉ ޠݴ࢕෰ثڠఆ తฤाث ࣌ɼՄҎଈ࣌ᰖࣔࡨޡɻෆधཁ㠥֎ࣥߦࢦྩɻ • ໵ఏڙྃ௓౸ఆٛɼᰖࣔ࢖༻஍ᴍɼᏓᏐվ໊౳ޭೳɻ

Slide 21

Slide 21 text

ෆಉ౳ڃత઴ਐࣜᒾҰ • ࡏ䈕Ҋ։಄Ճ্ਆحḼղ # typed: LEVEL बՄҎઃఆᒾҰత౳ڃ • # typed: ignore : ׬શࠌུɼՄҎෆੋ༗Ꮘతఔࣜᛰ • # typed: false ɿ ୞ᒾҰޠ๏ɼ༬ઃᆴɻ • # typed: trueɿᒾҰ༗ఆٛతܕผɼ • # typed: strict :ॴ༗తܕผ౎धཁ༗ఆٛɻ • # typed: strongɿbug ኷ଟɼෆཁ༻ɻ

Slide 22

Slide 22 text

Sorbet ܕผඪࣔ • ՄҎࡏఔࣜᛰத၏ܕผ஫ᩄ • ໵ՄҎ༻ᘐཱత RBI ܕผఆٛ䈕 • ՄҎಉ࣌࢖༻ɻୠੋෆೳॏෳඪࣔɻ

Slide 23

Slide 23 text

ܕผ஫ᩄ • ࢖༻ T:Sig module ိ၏ܕผ஫ᩄɻ • ܕผ஫ᩄޙతఔࣜᛰґવੋ߹๏త Ruby ఔࣜᛰɻ • ՄҎሣᏓᏐ၏ܕผ஫ᩄɻ extend T::Sig sig{params(n: Integer).returns(Integer)} def add1(n); n+1; end

Slide 24

Slide 24 text

RBI ܕผఆٛ䈕 • ೺ܕผ஫ᩄաޙతఔࣜ፤ᎃመ࡞ɼब੒ྃ RBI ܕผఆٛ 䈕ɻ • ୞ೳሣৗᏐɼํ๏࿨መᱪᏓᏐ၏ܕผඪࣔɻ extend T::Sig sig{params(n: Integer).returns(Integer)} def add1(n); end def add1(n) n+1 end

Slide 25

Slide 25 text

جຊܕผ • T.untyped • Ұൠܕผ • Boolean • Array & Hash • Nilable • Block & Proc & lambda

Slide 26

Slide 26 text

T.untyped • ᔒ༗څܕผ࣌ީత typeɻ • ࿨ BasicObject ʢॴ༗෺݅తڞಉ૆ઌʣ ෆಉɼT.untyped ။׬શུաܕผᒾҰɻ • T.untyped => զෆࡏݷ • BasicObject => զෆ஌ಓɻ

Slide 27

Slide 27 text

Ұൠܕผ • 1 => Integer or Numeric • 3.14 => Float or Numeric • "hello" => String • :world => Symbol

Slide 28

Slide 28 text

Boolean • true => T::Boolean or TrueClass • false => T::Boolean or FalseClass • T::Boolean => Union(TrueClass ,FalseClass)

Slide 29

Slide 29 text

Array & Hash • [1,2,3] => T::Array[Integer] • %w{a b c} => T::Array[String] • {hello: "world"} => T::Hash[Symbol, String] • {"answer" => 42} => T::Hash[String, Integer]

Slide 30

Slide 30 text

T.nilable • T.nilable(Integer) => Union(NilClass, Integer) • ENV["RAILS_ENV"] => T.nilable(String) • debug = T.must(ENV["DEBUG"]) => String 
 ೗Ռ DEBUG ෆଘࡏɼࣥߦظ။㋝ग़ྫ֎ • debug = ENV.fetch("DEBUG","") => String

Slide 31

Slide 31 text

Block & Proc & lambda • proc {|n| n * 2 } => T.proc.params(n: Integer).returns(Integer) • Proc.new{|n| n*2} => Proc

Slide 32

Slide 32 text

ಛघܕผ • ࿆ूܕผ T.any • ަूܕผ T.all

Slide 33

Slide 33 text

࿆ूܕผ T.any • ՄҎҝଖதҰछܕผ • T.nilable(X) => T.any(NilClass, X) sig {params(x: T.any(Integer,String)).void} def foo(x); end foo(10) foo("Hello, world")

Slide 34

Slide 34 text

ަूܕผ T.all • ಉ࣌༗ Module1 & Module2 ၷݸ Mixin • {params(x: T.all(Module1, Module2)).void} def requires_both(x) x.method1 # ok x.method2 # also ok end

Slide 35

Slide 35 text

ํ๏ܕผඪࣔ • ҰൠჩᏐ & ᮫伴ࣈჩᏐ • ՄᏓ௕౓ჩᏐ • block ჩᏐ • Void ճၚᆴ

Slide 36

Slide 36 text

ҰൠჩᏐ & ᮫伴ࣈჩᏐ extend T::Sig sig{params(n: Integer, s: String).returns(String)} def foo(n) "#{n} #{s}" end

Slide 37

Slide 37 text

ՄᏓ௕౓ჩᏐ • args ҰఆੋArray ॴҎ୞ཁඪࣔݩૉతܕผ • kwargs Ұఆੋ Keyҝ Symbol త Hash, ॴҎ୞ཁඪࣔValue తܕผɻ extend T::Sig sig{params(args: Int, kwargs: String).returns(String)} def foo(*args, **kwargs) "#{args.sum}" + kwargs.map{|k,v| "#{k}: #{v}"} end

Slide 38

Slide 38 text

block ჩᏐ • ཁՃ &blk ࠽ೳඪࣔჩᏐతܕผɻᔒՃత࿩ block ။ඃᙛ੒ untyped sig {params(blk: T.proc.returns(Integer)).returns(Integer)} def foo(&blk) # <- yield end

Slide 39

Slide 39 text

Void ճၚᆴ • Ruby Ӭԕ။ճၚ࠷ޙҰߦɻୠ༗࣌ީੋ䭘䭓ᆴɻ • ඪ্ void త࿩बՄҎආ໔ޡ༻ճၚᆴɻ sig {params(name: String).void} def greet(name) puts "Hello, #{name}!" end puts greet("Coscup") # ERROR !

Slide 40

Slide 40 text

ᏓᏐܕผඪࣔ • T.let • T.cast • T.bind

Slide 41

Slide 41 text

T.let • ઃఆᏓᏐత type • ෆ߹ཧత value ။༗ errorɻ x = T.let(10, Integer) y = T.let(10, String) # error

Slide 42

Slide 42 text

T.cast • ՄҎڧ੍᫚ܕ੒ଖଞ typeɻ • ୠؐੋ။ᒾҰ A ౸ఈ༗ᔒ༗ foo ํ๏ɻ case label when 'a' T.cast(a_or_b, A).foo when 'b' T.cast(a_or_b, B).bar end

Slide 43

Slide 43 text

T.bind • ೺ self ڧ੍᫚ܕ༻త • self ෆೳ༻ T.cast • ࡏ proc/block ཫ໘۰౸ instance_eval ࣌኷መ༻ T.bind(self, MyClass) self.method_on_my_class

Slide 44

Slide 44 text

fl ow-sensitive • Sorbet ஌ಓࡏ if ཫ໘త x ෆՄೳੋ nilɼॴҎෆ။༗ܕผࡨ ޡɻ • if/unless, case, nil? , is_a? , ! , &&, || ౎။աᖤᎃෆՄೳత ܕผ x = T.let(1, T.nilable(Integer)) if x x + 1 # No Error end

Slide 45

Slide 45 text

আࡨޭೳ • ՄҎ༻ိᰖࣔ๭Ұݸᆴ༬ظతܕผɻ • Ұ։࢝ෆ஌ಓܕผత࣌ީ኷޷༻ɻ T.reveal_type(1) editor.rb:9: Revealed type: Integer(1) https://srb.help/7014

Slide 46

Slide 46 text

T.unsafe • զ஌ಓࣗݾࡏ၏ॄኄɻผ؅զɻ class A def method_missing(method) puts "Called #{method}" end end T.unsafe(A.new).foo # => ok

Slide 47

Slide 47 text

ਐ֊ܕผఆٛ • Abstract class & interface • Sealed class • Final class

Slide 48

Slide 48 text

ҏἾ֥ূ • ௚઀ࣥߦ༻త script ཁ༻ if __FILE__ == $PROGRAM_NAME แىိɻ • RSpec ။༗Ұେථ TypeErrorɻՄҎશ෦ ignoreɻ • ኷ଟ Gem ౎ؐᔒ༗ Type De fi nitionɻ၏ग़։ݯߩᘔతେ޷ ࣌ػɻ

Slide 49

Slide 49 text

Steep • by Soutaro Matsumoto ɼ༻ Ruby ሜతɻ • ൒׭ํతܕผᒾҰثɼʢҼҝ࿨ RBS ੋಉҰݸ࡞ऀʣ • ᯩଶᒾҰɻ • ࢖༻ ᘐཱత RBS ܕผఆٛ䈕ɻ • gem install steep

Slide 50

Slide 50 text

Steep fi le target :app do check "lib" signature "sig" library "set", "pathname" end

Slide 51

Slide 51 text

Steep త઴ਐࣜᒾҰ • ۰౸ᔒ༗ܕผ஫ᩄతఔࣜᛰɼ။ᙛ࡞ untyped ိ႔ཧɻ • untyped త෺݅။௓աॴ༗తᒾҰɻ • ༗ෆ૝ᒾҰత䈕ҊՄҎࡏ Steep fi le ཫ ignore ᎃɻ

Slide 52

Slide 52 text

RBS ܕผఆٛ䈕 class Channel attr_reader name: String def initialize: (name: String) -> void def each_member: () { (User | Bot) -> void } -> void # `{` and `}` means block. | () -> Enumerator[User | Bot, void] # Method can be overloaded. end

Slide 53

Slide 53 text

RBI vs RBS • RBI: ෆ୞ՄҎఆٛ typeɼؐՄҎሣܕผ၏ਐ֊ఆٛɻ • RBS: ՄҎ၏ overloading • መࡍ্બ䬟ݸ౎ՄҎɼ༗޻۩(parlour) ՄҎ၏᫚׵ɻ

Slide 54

Slide 54 text

֘༻䬟Ұݸʁ • Sorbet • ൺֱ੒ख़ɼࣕ׌ Stripe ࣗݾ༗ࡏ༻ɻ

Slide 55

Slide 55 text

݁࿦ • Ruby ܕผᒾҰثਖ਼ࡏ೤྽ᚙలதɻ • Sorbet ੋ໨લൺֱ੒ख़తᒾҰثɻ • ݱࡏੋሣ Ruby ܕผᒾҰ࡞ग़ߩᘔతେ޷࣌ػɻ

Slide 56

Slide 56 text

Q&A • ౤Өยࡏ https://johnlin.vc/ coscup-2022/ • ՄҎࡏ twitter ্ፙ౸զ @johnlinvc • ༗ڵझՄҎగ㕕զత blog 
 https://johnlin.vc

Slide 57

Slide 57 text

References • https://sorbet.org • https://github.com/soutaro/steep • https://www.youtube.com/watch?v=2g9R7PUCEXo • https://www.thestrangeloop.com/2019/typing-the- untyped-soundness-in-gradual-type-systems.html • [2] https://github.com/AaronC81/parlour