Slide 1

Slide 1 text

Satoshi Tagomori (tagomoris) 2024/07/19 Ruby Association Activity Report Namespace on Read Ruby Association Grant Project Report

Slide 2

Slide 2 text

@tagomoris Satoshi Tagomori Maintainer/Founder: OSS: Fluentd, MessagePack, 
 Norikra, Woothee, …
 Event: ISUCON Service: Pathtraq

Slide 3

Slide 3 text

ϓϩδΣΫτৄࡉ͓Αͼ೔ఔ 2023/10 ʙ 2024/03 • 2023/10/25ɿ ϓϩδΣΫτ࠾୒௨஌
 ϝϯλʔܾఆ(·ͭ΋ͱΏ͖ͻΖ͞Μ) • 2023/10/26 ʙ 2023/03/20ɿϓϩδΣΫτਐߦ • ػೳৄࡉͷݕ౼ • ֦ுϥΠϒϥϦͷγϯϘϧղܾ༻ C API ௥Ճ (Ruby 3.3) • ࣮૷ํ๏ͷݕ౼͓Αͼ࣮૷ • 2024/01/11ɿ தؒใࠂఏग़ • 2024/03/20ɿ ࠷ऴใࠂఏग़

Slide 4

Slide 4 text

ϓϩδΣΫτ֓ཁ Namespace on read Rubyʹɺ௨ৗͷάϩʔόϧͳ֊૚Խ໊લۭؒΛ΋ͭϞδϡʔϧ౳ͷϥΠϒϥϦΛɺಡΈࠐΈ࣌ʹن ఆͨ͠Ծ૝తͳτοϓϨϕϧ໊લۭؒʹಡΈࠐΉػೳΛ௥Ճ͢Δ͜ͱΛ໨తͱͯ͠ύον։ൃΛߦ ͏ɻ
 ͜ͷ໊લۭؒʹಡΈࠐ·ΕͨϥΠϒϥϦ͸άϩʔόϧͳ໊લۭؒͱ͸ಠཱͨ͠ଘࡏͱͳΔͨΊɺ໊ લিಥͷճආɺڞ༗͞ΕͨϞδϡʔϧɾΫϥεͷૢ࡞ɾมߋʹؔ͢Δڝ߹ͷճආɺͳΒͼʹকདྷత ʹ͸ΞϓϦέʔγϣϯ͕ґଘ͢ΔϥΠϒϥϦؒͰͷόʔδϣϯڝ߹ͷճආͷ࣮ݱΛՄೳʹ͢Δͱظ ଴͍ͯ͠Δɻ
 
 https://www.ruby.or.jp/ja/news/20231031 https://bugs.ruby-lang.org/issues/19744 https://gist.github.com/tagomoris/559717c6c195f833cd15e08d4010e814

Slide 5

Slide 5 text

Namespace Separating apps/libs into isolated spaces • Load apps/libs in a space • Hide changes from apps/libs in a namespace to other spaces • Run methods de fi ned in a space with de fi nitions in the space

Slide 6

Slide 6 text

Before Namespace: Global Only All classes/modules are shared in the entire Ruby process Ruby Process Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7)

Slide 7

Slide 7 text

Collision: 2 versions of 1 library cause errors Ruby Process Library Code DB::Client (v3) 😵 Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Before Namespace: Global Only

Slide 8

Slide 8 text

Ruby Process Namespace Load apps/libs in a space Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7)

Slide 9

Slide 9 text

Ruby Process Namespace Hide changes from apps/libs in a namespace to other spaces Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Library Code DB::Client (v3) 😀

Slide 10

Slide 10 text

Ruby Process Namespace Run methods de fi ned in a space with de fi nitions in the space Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Namespace Library Code DB::Client (v3) Namespace Application Code App::Func2 User Library Code ActiveSupport (v6) Application Code call call call

Slide 11

Slide 11 text

ػೳৄࡉͷݕ౼ ݴޠػೳͱͯ͠ͷNamespaceͷઃܭ • ϝϯλʔ(·ͭ΋ͱ͞Μ)ͱٞ࿦ • Namespaceͱ͸Կ͔? ԿͰ͋Δ΂͖͔? ԿͳΒ࣮ݱՄೳ͔? • ҆қʹͰ͖ͦ͏ͳ࣮૷ҊʹҾ͖ͣΒΕͳ͍Α͏ʹ஫ҙ͢Δඞཁ͕͋ͬͨ • ػೳɿ Մೳੑͱ࣮ͯ͠૷Ͱ͖ͦ͏ͳػೳΛ࠷େݶϦετΞοϓ • ࣮ݱՄೳੑ͸ͦͷޙͰ୳Δ • είʔϓͱAPIɿ ࣮༻έʔεΛ૝ఆͯ͠Ͳ͏͋Δ΂͖͔Λߟ͑Δ

Slide 12

Slide 12 text

ػೳৄࡉͷݕ౼ ࣮૷͢΂͖ػೳ • require/load .rb • require/load .so • autoload • eval • proc, lambda • Ϋϥε΍Ϟδϡʔϧͷఆٛ • ૊ࠐΈΫϥεͷมߋ • include/prepend • τοϓϨϕϧϝιουఆٛ • άϩʔόϧม਺ͷมߋɺ௥Ճ • ఆ਺ͷมߋɺ௥Ճ • ΫϥεΠϯελϯεม਺ͷมߋɺ௥Ճ • Ϋϥεม਺ͷมߋɺ௥Ճ • ಛҟϝιουͷ௥Ճ

Slide 13

Slide 13 text

ػೳৄࡉͷݕ౼ είʔϓͱAPI • NamespaceఆٛͱಡΈࠐΈͷൣғ • ϑΝΠϧ୯ҐͰͷఆٛ? ϒϩοΫͳͲଞͷέʔε΋? • ݱࡏͷNamespace͸ϨΩγΧϧʹܾఆ? ΋ͬͱಈతʹ? • Namespaceͷఆٛํ๏ͱӅṭείʔϓ • Namespace͸਌ࢠؔ܎Λ࡞Δ? ਌ࢠؔ܎ͷؒͰ͸಺෦ఆ͕ٛࢀরͰ͖Δ? • Namespaceͷ࡞੒ͱಡΈࠐΈͷAPI • Namespace.newɺNamespace#requireɿ ௿ϨϕϧAPI? • Ϣʔβ޲͚ͷߴϨϕϧAPI͸ͲͷΑ͏ͳ΋ͷ͔?

Slide 14

Slide 14 text

ػೳৄࡉͷݕ౼ ߴϨϕϧΠϯλʔϑΣΠεͷఏҊɿPackage API • Namespace on readΛϕʔεʹͨ͠ΑΓ޿͍Ϣʔβ޲͚API • ΑΓ୯७ͳAPIͰϝϦοτΛड͚ΒΕΔΑ͏ʹ͢Δ pkg = require_package('my-awesome-gem') MyAwesomeGem = pkg.export(:MyAwesomeGem) MyAwesomeGem.call_method() • Namespace on read͕Ϛʔδ͞ΕͨΒݕ౼Λܧଓ

Slide 15

Slide 15 text

• ֦ுϥΠϒϥϦͷγϯϘϧղܾ • ಉ໊γϯϘϧΛ࣋ͭϥΠϒϥϦ͕͋Γ͏Δ • ಉϥΠϒϥϦͷҟόʔδϣϯಡΈࠐΈ • ಉҰ .so Λෳ਺ճಡΈࠐΈ • dlopen࣌ͷRTLD_LOCALϑϥάࢦఆ • ैདྷͱҧ͏ํ๏ͰγϯϘϧղܾ • ଞͷ֦ுϥΠϒϥϦʹ௚઀ґଘ͢Δ৔߹ͷΈ • rb_ext_resolve_symbol(fname, symname) Ruby w/ Namespace ֦ுϥΠϒϥϦͷγϯϘϧղܾ γϯϘϧղܾ༻ C API ͷ௥Ճ (Ruby 3.3) Ruby w/o Namespace db_driver_v1.so db_conn_server() query_client.so db_conn_server() db_driver_v1.so db_conn_server() query_client.so db_conn_server() db_driver_v2.so db_conn_server() ❌ rb_ext_resolve_symbol(“db_driver_v2”, “db_conn_server”)

Slide 16

Slide 16 text

Namespaceͷ࣮૷ Namespaceͷσʔλߏ଄: Namespace ͱ rb_namespace_t • Namespace • ModuleͷαϒΫϥε • Namespace#require ΍ Namespace#load • rb_namespace_t (಺෦࣮૷ɺstruct) • LOAD_PATH, LOADED_FEATURES, etc ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call()

Slide 17

Slide 17 text

Namespaceͷ࣮૷ ྫ1: Class/Moduleͷఆٛ • Namespace಺ͰͷClassఆٛ • MyAwesomeΛns::MyAwesomeʹ • .rbͷ৔߹ • load_wrapper() ͕ղܾ • .soͷ৔߹ # my_awesome.rb class MyAwesome; end # my_awesome.c void Init_my_awesome(void) { rb_define_class(“MyAwesome”, rb_cObject) } # app.rb ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call()

Slide 18

Slide 18 text

(no NS) Namespaceͷ࣮૷ ྫ1: Class/Moduleͷఆٛ • Namespace಺ͰͷClassఆٛ • MyAwesomeΛns::MyAwesomeʹ • .rbͷ৔߹ • load_wrapper() ͕ղܾ (1) • .soͷ৔߹ (2) require(“my_awesome.rb”) class MyAwesome; end defineclass .rb C func ISeq vm_find_or_create_class_by_id() rb_define_class_id() declare_under() vm_define_class() vm_declare_class() (1) ns.require(“my_awesome.rb”) class MyAwesome; end load_wrapper() defineclass vm_find_or_create_class_by_id() rb_define_class_id() declare_under() vm_define_class() vm_declare_class() ns:: ns:: ns:: ns::

Slide 19

Slide 19 text

Namespaceͷ࣮૷ ྫ1: Class/Moduleͷఆٛ • Namespace಺ͰͷClassఆٛ • MyAwesomeΛns::MyAwesomeʹ • .rbͷ৔߹ • load_wrapper() ͕ղܾ (1) • .soͷ৔߹ (2) .rb C func ISeq (2) ns.require(“my_awesome.rb”) rb_define_class() rb_define_class_id_under() (no NS) require(“my_awesome.rb”) rb_define_class() ns::

Slide 20

Slide 20 text

ػೳৄࡉͷݕ౼ ࣮૷͢΂͖ػೳ (revisit) • require/load .rb • require/load .so • autoload • eval • proc, lambda • Ϋϥε΍Ϟδϡʔϧͷఆٛ • ૊ࠐΈΫϥεͷมߋ • include/prepend • τοϓϨϕϧϝιουఆٛ • άϩʔόϧม਺ͷมߋɺ௥Ճ • ఆ਺ͷมߋɺ௥Ճ • ΫϥεΠϯελϯεม਺ͷมߋɺ௥Ճ • Ϋϥεม਺ͷมߋɺ௥Ճ • ಛҟϝιουͷ௥Ճ

Slide 21

Slide 21 text

্Լͷ੺͍ଳͷεϥΠυ಺༰͸ ݱࡏͷNamespace࣮૷ʹ͓͍ͯ͸ ࣺͯΒΕ͓ͯΓɺଘࡏ͠·ͤΜ

Slide 22

Slide 22 text

Namespaceͷఆٛ ྫ2: ૊ࠐΈΫϥεఆٛͷมߋ • class String ʹΑΔӨڹൣғͷݶఆ • Namespace಺ͰͷΈ༗ޮʹ͍ͨ͠ • Namespaceͷ֎Ͱ͸ແޮʹ͍ͨ͠ • ಛఆͷൣғͰͷΈ༗ޮͳϝιου
 → Re fi nementsͰ͸? # my_awesome.rb class String def blank?; false; end end class MyAwesome def self.call; “yay”.blank?; end end # app.rb ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call() #=> false “yay”.blank? # NoMethodError

Slide 23

Slide 23 text

Namespaceͷఆٛ ྫ2: ૊ࠐΈΫϥεఆٛͷมߋ: Implicit Re fi nements # app.rb ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call() “yay”.blank? # NoMethodError # my_awesome.rb class String def blank?; false; end end class MyAwesome def self.call = “yay”.blank? end # my_awesome.rb using ns.refiner class String def blank?; false; end end class MyAwesome def self.call = “yay”.blank? end • Namespace͸಺෦ʹϞδϡʔϧ(re fi ner)Λ΋ͬͯImplicit Re fi nementsʹ༻͍Δ • Namespace಺ͰධՁ͞ΕΔ .rb ͸·ͣ
 ҉໧ʹusing͞ΕΔ ಈ࡞͕ಁաతʹ ॻ͖׵͑ΒΕΔ෦෼

Slide 24

Slide 24 text

Namespaceͷఆٛ ྫ2: ૊ࠐΈΫϥεఆٛͷมߋ: Implicit Re fi nements # app.rb ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call() “yay”.blank? # NoMethodError rb false; end me ll = “yay”.blank? # my_awesome.rb using ns.refiner module ns.refiner refine String do def blank?; false; end end end class MyAwesome def self.call = “yay”.blank? end # my_awesome.rb using ns.refiner class String def blank?; false; end end class MyAwesome def self.call = “yay”.blank? end • class StringΛ
 module re fi ner; re fi ne String ʹॻ͖׵͑ͯ
 Re fi nementʹͳΔΑ͏ಡΈସ͑Δ ಈ࡞͕ಁաతʹ ॻ͖׵͑ΒΕΔ෦෼

Slide 25

Slide 25 text

Namespaceͷఆٛ ྫ2: ૊ࠐΈΫϥεఆٛͷมߋ: Implicit Re fi nements # app.rb ns = Namespace.new ns.require(‘my_awesome’) ns::MyAwesome.call() “yay”.blank? # NoMethodError # my_awesome.rb using ns.refiner module ns.refiner refine String do def blank?; false; end end end using ns.refiner class MyAwesome def self.call = “yay”.blank? end # my_awesome.rb using ns.refiner module ns.refiner refine String do def blank?; false; end end end class MyAwesome def self.call = “yay”.blank? end y_awesome.rb ng ns.refiner ss String ef blank?; false; end ss MyAwesome ef self.call = “yay”.blank? • ߋ৽͞ΕͨRe fi nementΛ༗ޮʹ͢ΔͨΊ
 ΋͏͍ͪͲusing͢Δ ಈ࡞͕ಁաతʹ ॻ͖׵͑ΒΕΔ෦෼

Slide 26

Slide 26 text

Namespaceͷ࣮૷ Implicit Re fi nementsʹΑΔ࣮ߦ࣌ఆٛߋ৽ • ϝιου௥Ճ → Implicit Re fi nementsͰ࣮ݱ • ఆ਺௥Ճ → re fi nerϞδϡʔϧʹఆ਺Λ௥Ճͯ͠ࢀরՄೳʹ • τοϓϨϕϧϝιουఆٛ → ObjectΛre fi ne͢Δ͜ͱͰରԠՄೳ

Slide 27

Slide 27 text

ػೳৄࡉͷݕ౼ ࣮૷͢΂͖ػೳ (re-revisit) • require/load .rb • require/load .so • autoload • eval • proc, lambda • Ϋϥε΍Ϟδϡʔϧͷఆٛ • ૊ࠐΈΫϥεͷมߋ • include/prepend • τοϓϨϕϧϝιουఆٛ • άϩʔόϧม਺ͷมߋɺ௥Ճ • ఆ਺ͷมߋɺ௥Ճ • ΫϥεΠϯελϯεม਺ͷมߋɺ௥Ճ • Ϋϥεม਺ͷมߋɺ௥Ճ • ಛҟϝιουͷ௥Ճ ϓϩδΣΫτ಺Ͱ࣮ݱ͞Εͨػೳ

Slide 28

Slide 28 text

Namespaceͷ࣮૷ Implicit Re fi nements࣮૷ͷ੍໿ͱཁվળ఺ • include/prepend ͕࣮ݱͰ͖ͳ͍ • Ϋϥεͷಛҟϝιουఆٛͷ࣮ݱʹແཧ͕͋Δ • ఆٛมߋͷίʔυͱݺͼग़͠Λߦ͏ίʔυͷॱংΛٯసͤ͞ΒΕͳ͍

Slide 29

Slide 29 text

্Լͷ੺͍ଳͷεϥΠυ಺༰͸ ݱࡏͷNamespace࣮૷ʹ͓͍ͯ͸ ࣺͯΒΕ͓ͯΓɺଘࡏ͠·ͤΜ

Slide 30

Slide 30 text

ϓϩδΣΫτͷ੒Ռ Namespace on read • ࣮ݱ͢΂͖ػೳ΍ఏڙ͞ΕΔ΂͖ΠϯλʔϑΣΠεͳͲΛݕ౼ͨ͠ • ࣄલʹ࣮ݱ͓ͯ͘͠΂͖C APIʹ͍ͭͯ͸Ruby 3.3΁ͷಋೖʹ੒ޭͨ͠ • ͔ͳΓͷػೳΛ࣮ࡍʹ࣮ݱͨ͠ • ͍ͬΆ͏ɺRe fi nementsϕʔεͰͷ࣮૷ͷݶք΋໌Β͔ʹͳͬͨ

Slide 31

Slide 31 text

Namespaceͷ࣮૷ 4݄Ҏ߱ɺRubyKaigi 2024Λӽ͑ͯ • https://speakerdeck.com/tagomoris/namespace-what-and-why • Re fi nementsϕʔεͷ࣮૷Λഁغ • classext copyͱ͍͏ख๏Ͱͷ࣮૷ʹํ਑Λస׵
 (RubyKaigi 2024ͷτʔΫ಺༰Λࢀর) • test-all ͕׬૸ɺ10 failures/errors ͱ͍͏͋ͨΓ·Ͱ࣮૷͞Εͭͭ͋Δ
 (2024/07/18) • Implicit Re fi nements ෦෼తʹ෮׆ͷػӡߴ·Δ

Slide 32

Slide 32 text

Special Thanks to Matz Thank you for listening! The Ruby Designer & The Mentor of this project