ml.ruby-lang.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

ruby-core

Thread Start a new thread
Download
Threads by month
  • ----- 2026 -----
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
ruby-core@ml.ruby-lang.org

July 2026

  • 4 participants
  • 159 discussions
[ruby-core:125933] [Ruby Misc#22180] Provide official Windows (mswin) binary packages and a version manager
by hsbt (Hiroshi SHIBATA) 05 Jul '26

05 Jul '26
Issue #22180 has been updated by hsbt (Hiroshi SHIBATA). Status changed from Open to Assigned PoC is here: * https://github.com/ruby/ruby/pull/17662 * https://github.com/ruby/actions/pull/133 ---------------------------------------- Misc #22180: Provide official Windows (mswin) binary packages and a version manager https://bugs.ruby-lang.org/issues/22180#change-117899 * Author: hsbt (Hiroshi SHIBATA) * Status: Assigned * Assignee: hsbt (Hiroshi SHIBATA) ---------------------------------------- Japanese version of this proposal: https://gist.github.com/hsbt/552b01f2aac616af6f8056148407900a ## Background Ruby used to ship official Windows binaries. https://ftp.ruby-lang.org/pub/ruby/binaries/mswin32/ still has mswin32 zips from the 1.6 to 1.9-preview era, and they were discontinued around 1.9. One reason is that a bare zip was not usable as a distribution. https://bugs.ruby-lang.org/issues/999 reports that the `ruby-1.9.1-preview1` mswin32 zip was missing the OpenSSL and zlib DLLs, so `gem update` did not work at all. Since then, installing Ruby on Windows has depended on third-party distributions. The mswin platform, which is what `ruby/ruby` CI actually builds and tests with MSVC, has had no end-user distribution at all. https://bugs.ruby-lang.org/issues/19325 shows how the current state is perceived by Windows users. The technical ground has changed. Over the last few months I fixed all the tests that remained broken on mswin myself: `nmake check`, `test-bundler` and `test-bundled-gems` are green now, and `nmake exam`, which runs all of the test suites, completes as well. The build manages its C dependencies with a pinned vcpkg manifest (`vcpkg.json`), and CI covers VS 2022, VS 2026 and `windows-11-arm`. MSVC ABI (`vcruntime140`) has been stable since 2015. The missing piece is distribution, not build quality. Timing also matters. In the era of writing code with AI, the people who need a working Ruby on Windows are increasingly ordinary users who let a coding assistant set up the environment for them, and consumer AI tools operate natively on Windows, not through WSL. An assistant working unattended needs a runtime that installs without elevation and without GUI dialogs, exposes a machine-readable version index, and is relocatable so that installs are deterministic. Unattended provisioning is already the norm in CI (`setup-ruby` exists precisely for this), and AI assistants bring the same requirement to end-user machines. Python reached the same conclusion with PEP 773, described below. Ruby has no official answer to this on Windows today. ## Proposal I propose to provide an official Windows distribution based on the mswin platform, made of three components. All of them, including the test-suite fixes above, are work I implemented and verified myself. Nothing below is a design on paper. **1. `ruby/ruby`: a `binary-package` target.** A new nmake-only target packages the installed tree together with the vcpkg runtime DLLs, the VC runtime and the license terms of everything redistributed into a relocatable zip, with build-machine specific paths scrubbed from `rbconfig.rb`. Thanks to `LOAD_RELATIVE` the tree runs from any location. I will submit the pull request shortly. This is implemented and verified. The package passes a smoke test with `PATH` restricted to `System32` (openssl, fiddle, psych, zlib and RubyGems all work), and C extensions compile with VS Build Tools. In a survey of the 500 most-downloaded gems on rubygems.org forced to build from source, 21 of the 44 gems with a native extension built and loaded. All 23 failures were gem-side or environment-side issues (gcc-only code, POSIX-only source, missing third-party libraries), none caused by the package or by ruby itself, with identical results on 3.3.11, 3.4.10 and 4.0.5. **2. `ruby/actions`: building and publishing.** Automation builds the zips and publishes them together with sha256 checksums: daily builds of master and release builds of the maintained series. Released series (3.3, 3.4, 4.0) are built from their release tarballs with the same packaging script applied externally, so no change to the stable branches is required. This also enables re-packaging revisions (`-1`, `-2`) when a bundled dependency such as OpenSSL needs a security update without a new Ruby release. This part is already working too: in addition to master, zips of 3.3.11, 3.4.10 and 4.0.5 have been built and verified this way, and they are the packages the gem survey above was run on. **3. `rbmanager`: a version manager for Windows.** The same shape as Python's install manager (PEP 773, https://peps.python.org/pep-0773/) A single native executable (the `rb` command) installs a zip from a URL or a local path, extracts it under `%LOCALAPPDATA%`, switches versions with an NTFS junction, and needs one user-level `PATH` entry and no elevation. A working prototype written in C# is already complete and verified on a real machine: ``` > rb install ruby-4.1.0-x64-mswin64_140.zip Extracting ruby-4.1.0-x64-mswin64_140 ... Installed ruby-4.1.0-x64-mswin64_140 > ruby -v ruby 4.1.0dev (2026-06-29T22:22:44Z master 2ce6b8e54a) +PRISM [x64-mswin64_140] > rb list ruby-3.3.11-x64-mswin64_140 ruby-3.4.10-x64-mswin64_140 ruby-4.0.5-x64-mswin64_140 * ruby-4.1.0-x64-mswin64_140 > rb use 4.0 Now using ruby-4.0.5-x64-mswin64_140 > ruby -v ruby 4.0.5 (2026-05-20 revision 64336ffd0e) +PRISM [x64-mswin64_140] ``` The example installs from a local zip today. Once the official version index described below is published, `rb install 4.1` will resolve the version, download the zip and verify its checksum by itself. ## What building on the platform vendor's toolchain enables This proposal is complementary to the existing gcc-based distributions and does not compete with them. Some capabilities are decided by third-party vendors rather than by Ruby, because their SDKs assume the MSVC toolchain and ABI, and those become reachable with an official MSVC-built runtime. Machine-learning runtime assets become directly reusable: the prebuilt Windows packages of ONNX Runtime, libtorch and OpenCV are MSVC binaries with C++ ABIs, and CUDA's `nvcc` accepts only `cl.exe` as its host compiler on Windows, so Ruby extensions binding GPU and ML runtimes need an MSVC-built Ruby to link cleanly. PDB symbols connect Ruby to the standard Windows diagnostics stack: WinDbg and Visual Studio can debug a mixed stack of Ruby and vendor DLLs, WER minidumps from end users become analyzable, and publishing official symbol packages becomes possible for the first time. And extension authors can pull C dependencies from the same vcpkg ecosystem that `ruby/ruby` itself already uses through `vcpkg.json`. ## What I ask to decide First, make these official distribution artifacts: announce them on the www.ruby-lang.org download page and host the zips, checksums and a static version index (the equivalent of pymanager's `index-windows.json`) on ruby-lang.org infrastructure. GitHub Releases can serve as the initial hosting during the preview period. Second, sign the published binaries with a project identity (for example SignPath Foundation issues OSS code-signing certificates) rather than an individual certificate. Third, host `rbmanager` as a repository under the `ruby` organization. The concrete zip layout and naming rule are implementation details. I will work them out with @nobu and document the result in `doc/distribution/windows.md`, so they are not something to decide on this ticket. ## Scope and non-goals This proposal does not replace or deprecate any existing third-party distribution. It adds an official channel for the platform the core team itself builds and tests. I already operate the official snap distribution and the entire release pipeline including security releases, and these artifacts ride on the same automation and the same operator, so this proposal does not change the current maintenance level. Pure-Ruby gems work with no toolchain. Building a C extension requires VS Build Tools, which Microsoft has licensed for building open-source dependencies without a paid Visual Studio license since 2022, and a `ridk`-like bootstrap (`win32/install-buildtools.cmd` is the seed) is follow-up work. Precompiled `x64-mswin64` gems across the ecosystem are long-term work and not a prerequisite. The survey above identified 12 gems that already support Windows with `x64-mingw-ucrt` precompiled binaries and only lack a working MSVC source path, a concrete and small upstream fix list. That list includes nokogiri and ffi, so applications depending on them (Rails, for example) do not work on this distribution yet. The fixes are tractable: I have already verified a one-line fix for msgpack locally and will send these upstream. TLS trust anchors are not bundled in the zip. `rbmanager` provisions certificates from the Windows certificate store at install time, and I will separately propose `OpenSSL::X509::Store#add_store` support for the OpenSSL 3.2+ `org.openssl.winstore://` store in ruby/openssl as the permanent solution. x64 comes first. arm64 (`arm64-mswin64`) already builds in CI and will follow once its test suite is green. ## Roadmap The rollout is incremental rather than tied to a single date. Zips for the released series (3.3, 3.4, 4.0) will be published progressively for their existing releases. For 4.1, nightly zips of master are published continuously, and a zip follows each preview release as soon as it is out. Only the GA of `rbmanager` and the distribution mechanism as a whole is aligned with the Ruby 4.1 release in December. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:125930] [Ruby Bug#22178] Regexp#== regression: regexps built via the `rb_reg_new` C API are no longer equal to an identical literal
by watson1978 (Shizuo Fujita) 04 Jul '26

04 Jul '26
Issue #22178 has been reported by watson1978 (Shizuo Fujita). ---------------------------------------- Bug #22178: Regexp#== regression: regexps built via the `rb_reg_new` C API are no longer equal to an identical literal https://bugs.ruby-lang.org/issues/22178 * Author: watson1978 (Shizuo Fujita) * Status: Open * ruby -v: ruby 4.1.0dev (2026-06-24T22:57:54Z master d663de3fc4) +PRISM [x86_64-linux] * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- On current master, two `Regexp` objects that have the same options, the same regexp encoding (`Regexp#encoding`), and byte-identical sources are no longer `==` if their *source strings* have different encodings (e.g. `ASCII-8BIT` vs `US-ASCII`). This worked on 4.0 and earlier. Such a regexp is produced by the public C API `rb_reg_new()`, which does not normalize the source encoding, so an ASCII-only pattern keeps an `ASCII-8BIT` source instead of being promoted to `US-ASCII`. ## Reproduction ```ruby require "fiddle" libruby = Fiddle.dlopen(nil) RB_REG_NEW = Fiddle::Function.new( libruby["rb_reg_new"], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_LONG, Fiddle::TYPE_INT], Fiddle::TYPE_VOIDP ) def reg_via_c_api(src, options = 0) # what a C extension using ptr = RB_REG_NEW.call(Fiddle::Pointer[src], src.bytesize, options) Fiddle.dlunwrap(ptr.to_i) # rb_reg_new() produces end c = reg_via_c_api("^[0-9]") # rb_reg_new() -> source ASCII-8BIT lit = /^[0-9]/ # literal -> source US-ASCII p c.source.encoding # ASCII-8BIT p lit.source.encoding # US-ASCII p c.encoding # US-ASCII p lit.encoding # US-ASCII p(c.options == lit.options) # true p(c.source == lit.source) # true (byte-identical) p(c == lit) # 4.0: true / master: false ``` Output on master: ``` #<Encoding:ASCII-8BIT> #<Encoding:US-ASCII> #<Encoding:US-ASCII> #<Encoding:US-ASCII> true true false # <-- was true on 4.0.5 ``` ## Cause Bisects to commit **d663de3fc43a8bb54bbdde12764b54bff4369da0** ("re.c: Simplify rb_reg_equal", 2026-06-24). Confirmed by building the two adjacent commits. | commit | `c == lit` | |--------|-----------| | `bb75c2893a` (parent) | `true` | | `d663de3fc4` | `false` | `rb_reg_equal` changed from comparing regexp encoding + source **content** to comparing the source **fstring identity**: ```c // before if (RREGEXP_SRC_LEN(re1) != RREGEXP_SRC_LEN(re2)) return Qfalse; if (ENCODING_GET(re1) != ENCODING_GET(re2)) return Qfalse; return RBOOL(memcmp(RREGEXP_SRC_PTR(re1), RREGEXP_SRC_PTR(re2), RREGEXP_SRC_LEN(re1)) == 0); // after if (RREGEXP_SRC(re1) != RREGEXP_SRC(re2)) return Qfalse; // fstring pointer compare return RBOOL(ENCODING_GET(re1) == ENCODING_GET(re2)); ``` Because fstring interning is encoding-sensitive, a `US-ASCII` `"^[0-9]"` and an `ASCII-8BIT` `"^[0-9]"` are distinct fstrings, so the new pointer comparison returns `false` where the old content+encoding comparison returned `true`. ## Question Is this behavior change intentional, or a side effect of the optimization? The commit message describes d663de3fc4 as a pure optimization and doesn't mention making the source string's encoding significant to Regexp#==, so it reads like an unintended side effect: the optimization assumes every regexp source is a normalized fstring, but rb_reg_new() can produce one whose source is a valid fstring with a non-normalized (`ASCII-8BIT`) encoding. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:125924] [Ruby Bug#22176] [Feature] TracePoint#defined_box: get the Ruby::Box where a method is defined
by udzura (Uchio KONDO) 04 Jul '26

04 Jul '26
Issue #22176 has been reported by udzura (Uchio KONDO). ---------------------------------------- Bug #22176: [Feature] TracePoint#defined_box: get the Ruby::Box where a method is defined https://bugs.ruby-lang.org/issues/22176 * Author: udzura (Uchio KONDO) * Status: Open * ruby -v: ruby 4.1.0dev (2026-07-04T01:14:12Z master 870c8d6a50) +PRISM [arm64-darwin25] * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- ## Summary In `TracePoint` events such as `:call` / `:c_call` / `:return` / `:c_return`, I'd like to propose adding an attribute `TracePoint#defined_box`, which returns the `Ruby::Box` in which the called method was defined. Currently, `tp.defined_class` correctly returns a distinct class/module object per Box, but there is no direct way to know which Box that object belongs to. ## Background / Motivation With `Ruby::Box`, the same class name and the same source file can be loaded independently in multiple Boxes. In this situation, tools that observe and record method calls via TracePoint (profilers, security auditing tools, test support tools, etc.) run into a practical problem: they cannot distinguish "which Box the called method was defined in." ### Reproduction sample1.rb: ```ruby b = Ruby::Box.new b.require_relative 'sample2' require_relative 'sample2' tp = TracePoint.new(:call) do |tp| if tp.method_id == :method1 puts "Calling #{tp.defined_class}##{tp.method_id} from #{tp.path}:#{tp.lineno}" end end tp.enable ins1 = Sample2.new ins1.method1 ins2 = b::Sample2.new ins2.method1 ``` sample2.rb: ```ruby class Sample2 def method1 puts "This is method 1" end end ``` Output: ``` $ RUBY_BOX=1 ./miniruby ./sample1.rb ./miniruby: warning: Ruby::Box is experimental, and the behavior may change in the future! See https://docs.ruby-lang.org/en/master/Ruby/Box.html for known issues, etc. Calling Sample2#method1 from /path/to/sample2.rb:2 This is method 1 Calling Sample2#method1 from /path/to/sample2.rb:2 This is method 1 ``` There is no way to distinguish the two calls using `tp.defined_class`, `tp.method_id`, `tp.path`, or `tp.lineno`. I have confirmed that the class returned by `tp.defined_class` does in fact have a different object id in each case, but there is no way to check which Box it is associated with. ### Known workarounds and their issues #### 1. `tp.binding.eval "Ruby::Box.current.inspect"` It's possible to obtain the Box indirectly by evaluating `Ruby::Box.current` through `tp.binding`. However, `:c_call` / `:c_return` (calls into methods implemented in C) have no corresponding Ruby-level binding, so `tp.binding` itself is unavailable, and this workaround cannot be used there. #### 2. `tp.self.method(tp.method_id).box.inspect` Re-obtaining an `Object#method` reference does work, and this also works for C methods. However, it has the downside of re-constructing a `Method` object inside the TracePoint block every time, which adds overhead, and it isn't very intuitive. ## Proposed API Add `TracePoint#defined_box`, paired with `tp.defined_class`, returning the `Ruby::Box` instance in which the method/class was defined (or `nil` when `RUBY_BOX` is disabled). ```ruby tp = TracePoint.new(:call, :c_call) do |tp| puts "#{tp.defined_class}##{tp.method_id} defined in #{tp.defined_box.inspect}" end ``` ### On naming | Candidate | Verdict | Reason | |---|---|---| | `defined_box` | Proposed | Symmetric with `defined_class` | | `box` | Under consideration | Matches `Method#box`, but less specific | ## Possible implementation I'm considering two directions and would appreciate feedback: - Go through `rb_trace_arg_t *` and use `rb_callable_method_entry_without_refinements()` to look up the method definition from the klass and called_id, then read the box off of it. This may add some overhead. - Add an argument carrying the defining-Box information to `rb_exec_event_hook_orig()`. Since this function is used very broadly, this would come with a higher cost of change. ## Open questions 1. For singleton methods, `defined_class` returns the singleton class per spec. Should `defined_box` likewise return the Box that singleton class belongs to? 2. Is similar information also needed for the `:script_compiled` event, etc.? ## Environment ``` $ ./miniruby --version ruby 4.1.0dev (2026-07-04T01:14:12Z master 870c8d6a50) +PRISM [arm64-darwin25] ``` ## Use cases ### Security auditing / debugging When multiple Boxes coexist and an unexpected side effect occurs, there is likely demand for being able to trace "which Box the code that actually ran was defined in." In [vivarium](https://github.com/udzura/vivarium), an auditing tool I'm developing, I'm also considering per-Box auditing, but currently the only options are going through `tp.binding` or re-fetching `Method#box` each time, both of which feel redundant. ### Verifying dependency updates One of the use cases for Box is running an old and a new version of a dependency in parallel, each in its own Box, and comparing the resulting responses. For this, a mechanism to visualize which Box's code path was actually executed is needed. ### Application to multi-tenant systems, etc. TracePoint would make it possible to tally how much code from which Box (i.e., which plugin or tenant) was invoked. For example, an APM/profiling tool could use this to visualize per-Box usage, which may be a real demand. Since this seems like a generally useful attribute to trace with respect to Box in the first place, I expect more ideas for use cases to surface as well. ## Related - [Feature #21311] Namespace on read (revised) -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:125922] [Ruby Bug#18995] IO#set_encoding sometimes set an IO's internal encoding to the default external encoding
by javanthropus (Jeremy Bopp) 03 Jul '26

03 Jul '26
Issue #18995 has been updated by javanthropus (Jeremy Bopp). @nobu, may I ask you to take a look at this? ---------------------------------------- Bug #18995: IO#set_encoding sometimes set an IO's internal encoding to the default external encoding https://bugs.ruby-lang.org/issues/18995#change-117891 * Author: javanthropus (Jeremy Bopp) * Status: Open * ruby -v: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- This script demonstrates the behavior: ```ruby def show(io) printf( "external encoding: %-25p internal encoding: %-25p\n", io.external_encoding, io.internal_encoding ) end Encoding.default_external = 'iso-8859-1' Encoding.default_internal = 'iso-8859-2' File.open('/dev/null') do |f| f.set_encoding('utf-8', nil) show(f) # f.internal_encoding is iso-8859-2, as expected f.set_encoding('utf-8', 'invalid') show(f) # f.internal_encoding is now iso-8859-1! Encoding.default_external = 'iso-8859-3' Encoding.default_internal = 'iso-8859-4' show(f) # f.internal_encoding is now iso-8859-3! end ``` In the 1st case, we see that the IO's internal encoding is set to the current setting of Encoding.default_internal. In the 2nd case, the IO's internal encoding is set to Encoding.default_external instead. The 3rd case is more interesting because it shows that the IO's internal encoding is actually following the current setting of Encoding.default_external. It didn't just copy it when #set_encoding was called. It changes whenever Encoding.default_external changes. What should the correct behavior be? -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:125919] [Ruby Bug#22174] Set operations (&, ^, collect!, flatten, classify, divide) do not preserve compare_by_identity
by gil.desmarais (Gil Desmarais) 03 Jul '26

03 Jul '26
Issue #22174 has been reported by gil.desmarais (Gil Desmarais). ---------------------------------------- Bug #22174: Set operations (&, ^, collect!, flatten, classify, divide) do not preserve compare_by_identity https://bugs.ruby-lang.org/issues/22174 * Author: gil.desmarais (Gil Desmarais) * Status: Open * ruby -v: ruby 4.0.5 (2026-05-20 revision 64336ffd0e) +PRISM [arm64-darwin25] * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- Since `Set` was transitioned to a C-level core class in Ruby 4.0, several operations that allocate new sets or partition subsets (`&`, `^`, `collect!`, `flatten`, `classify`, and `divide`) lost the `compare_by_identity` behavior for the receiver set or its subsets. * For `&`, `collect!`, `flatten`, `classify`, and `divide`, the resulting sets/subsets are allocated without propagating the `compare_by_identity` flag (returning `false` for `#compare_by_identity?`). * For `^` (XOR) with a generic `Enumerable`, the returned set has the flag set (via `dup`), but it allocates a temporary set `tmp` to hold the RHS elements without propagating the `compare_by_identity` flag. This causes the RHS elements to be deduplicated incorrectly using value equality instead of identity equality. A pull request has been opened with the fix and tests: https://github.com/ruby/ruby/pull/17633 ### Reproduction ```ruby require 'set' # 1. Intersection & s1 = Set.new.compare_by_identity s2 = Set.new s1 << "a" s2 << "a" puts "Intersection preserves compare_by_identity: #{(s1 & s2).compare_by_identity?}" # Expected: true # Actual: false # 2. XOR ^ (with duplicate objects by value on RHS) s_xor = Set.new.compare_by_identity x1 = +"x" x2 = +"x" result = s_xor ^ [x1, x2] puts "XOR with Enumerable preserves identity comparison: #{result.size == 2}" # Expected: true (size should be 2, because x1 and x2 are distinct objects) # Actual: false (size is 1) # 3. collect! / map! s_collect = Set.new(["a", "b"]).compare_by_identity s_collect.collect! { |x| x } puts "collect! preserves compare_by_identity: #{s_collect.compare_by_identity?}" # Expected: true # Actual: false # 4. flatten s_flat = Set.new([Set.new([1])]).compare_by_identity puts "flatten preserves compare_by_identity: #{s_flat.flatten.compare_by_identity?}" # Expected: true # Actual: false # 5. classify s_classify = Set.new(["a", "b"]).compare_by_identity classified = s_classify.classify { |x| x } puts "classify subsets preserve compare_by_identity: #{classified.values.all?(&:compare_by_identity?)}" # Expected: true # Actual: false # 6. divide s_divide = Set.new(["a", "b"]).compare_by_identity divided = s_divide.divide { |x| x } puts "divide subsets preserve compare_by_identity: #{divided.all?(&:compare_by_identity?)}" # Expected: true # Actual: false -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:125855] [Ruby Feature#22132] Scala-like for comprehensions
by shugo (Shugo Maeda) 03 Jul '26

03 Jul '26
Issue #22132 has been reported by shugo (Shugo Maeda). ---------------------------------------- Feature #22132: Scala-like for comprehensions https://bugs.ruby-lang.org/issues/22132 * Author: shugo (Shugo Maeda) * Status: Open ---------------------------------------- ## Abstract How about adding an expression form of `for` that desugars into nested `flat_map`/`map` and `filter` calls. Here's an example, which computes all pairs of numbers between `0` and `n-1` whose sum is equal to a given value `v`: ```ruby def foo(n, v) for i in 0...n, j in 0...n when i + j == v then [i, j] end end p foo(10, 10) #=> [[1, 9], [2, 8], [3, 7]...] ``` The above code is desugared as follows: ```ruby def foo(n, v) (0...n).flat_map { |i| (0...n).filter { |j| i + j == v }.map { |j| [i, j] } } end p foo(10, 10) ``` ## Background and Motivation Some other languages have syntactic sugar that flattens nested code. For example, Scala has for comprehensions: ```scala def foo(n: Int, v: Int) = for i <- 0 until n j <- 0 until n if i + j == v yield (i, j) ``` Haskell has do notation: ```haskell foo :: Int -> Int -> [(Int, Int)] foo n v = do i <- [0 .. n-1] j <- [0 .. n-1] guard (i + j == v) pure (i, j) ``` Blocks are often nested deeply in Ruby, so such syntactic sugar is useful. ## Use cases For comprehensions can be used to flatten nested blocks. For example, ```ruby (1..).lazy.flat_map { |z| (1..z).lazy.flat_map { |x| (x..z).lazy.filter { |y| x**2 + y**2 == z**2 }.map { |y| [x, y, z] } } }.take(3).force ``` can be flattened as follows: ```ruby for z in (1..).lazy, x in (1..z).lazy, y in (x..z).lazy when x**2 + y**2 == z**2 then [x, y, z] end.take(3).force ``` For comprehensions can be used not only for Enumerable objects, but also for other objects which have `flat_map` and `map` that satisfy [the Monad laws](https://wiki.haskell.org/index.php?title=Monad_laws). ## Why `then` and `when`? Scala's `yield` conflicts with the existing `yield` keyword in Ruby, so I chose `then`. While a bare `for ... then` (no guard) reads a little unnaturally in English, Ruby already gives `then` a value-producing meaning (e.g., `Kernel#then`), so I consider it acceptable. The guard keyword is not `if` but `when`, because `if` after the source would be ambiguous with the modifier `if`. ## Limitations The right operand of `in` is `arg_value`, not `expr_value`, to avoid conflicts, so unparenthesized method calls (command calls) must be parenthesized. ## Backward compatibility * `for x in xs do ... end` (and the newline form) is unchanged: it still iterates via `each` and returns the collection. * All of the new forms (`for ... then`, `for ... ,`, `for ... when`) were `SyntaxError` before, so no existing program changes meaning. ## Implementation PoC: https://github.com/ruby/ruby/pull/17500 It's currently implemented only in `parse.y`, not in Prism yet, so requires `--parser=parse.y`. ## Open questions * Variable scope: the loop variables currently leak, same as `for ... do`. Should a comprehension instead scope them like a block? -- https://bugs.ruby-lang.org/
4 9
0 0
[ruby-core:125830] [Ruby Feature#22128] C API: Expose RB_OBJ_SET_FROZEN_SHAREABLE
by byroot (Jean Boussier) 02 Jul '26

02 Jul '26
Issue #22128 has been reported by byroot (Jean Boussier). ---------------------------------------- Feature #22128: C API: Expose RB_OBJ_SET_FROZEN_SHAREABLE https://bugs.ruby-lang.org/issues/22128 * Author: byroot (Jean Boussier) * Status: Open ---------------------------------------- ### Context I'm trying to experiment with adapting Active Record for a Ractor architecture. Since database connections can't possibly be Ractor shareable, the idea is to warp each connection inside its own ractor, and then send SQL queries and responses through a port. But for this to perform well, I'd like to directly build the query response as a fully shareable object, so that it can be pushed into the port for free, instead of having Ruby need to recursively walk the potentially large response to mark objects as shareable. Here's an example of how it would work in trilogy: https://github.com/byroot/trilogy/commit/5f58200b398995d2fc0d4673a5a6bbccd0… ### Problem Unfortunately, the necessary API isn't currently exposed in the C API: - `RB_OBJ_SET_FROZEN_SHAREABLE` - `RB_OBJ_SET_SHAREABLE` / `rb_obj_set_shareable` I understand that this API could potentially be misused, but given it's a C API, I believe it's acceptable to require care from the caller. -- https://bugs.ruby-lang.org/
3 4
0 0
[ruby-core:125071] [Ruby Feature#21957] Introduce `Enumerable#close` to free internal resources.
by ioquatix (Samuel Williams) 02 Jul '26

02 Jul '26
Issue #21957 has been reported by ioquatix (Samuel Williams). ---------------------------------------- Feature #21957: Introduce `Enumerable#close` to free internal resources. https://bugs.ruby-lang.org/issues/21957 * Author: ioquatix (Samuel Williams) * Status: Open * Assignee: ioquatix (Samuel Williams) ---------------------------------------- In some cases, `Enumerable` has substantial internal state (e.g. Fiber) related to enumeration. There is currently no way to clear up this state besides garbage collection, which means that we can accumulate considerable garbage before cleaning up, even if we know when the enumerable is no longer needed. I'd like to introduce `Enumerable#close` which invalidates the enumerable, freeing internal resources. After which, most usage would result in `Enumerable::ClosedError`. -- https://bugs.ruby-lang.org/
2 3
0 0
[ruby-core:115879] [Ruby master Bug#20081] Transfered Fiber doesn't return to Fiber that started it
by rmosolgo (Robert Mosolgo) 01 Jul '26

01 Jul '26
Issue #20081 has been reported by rmosolgo (Robert Mosolgo). ---------------------------------------- Bug #20081: Transfered Fiber doesn't return to Fiber that started it https://bugs.ruby-lang.org/issues/20081 * Author: rmosolgo (Robert Mosolgo) * Status: Open * Priority: Normal * ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin22] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Hi! I'm trying to figure out how to make sure that Fibers started with `.transfer` end up _terminated_, not just suspended. (If they're suspended, Rails thinks they're still alive, and they continue to hold onto database connections, see: https://github.com/rmosolgo/graphql-ruby/issues/4739#issuecomment-1866930914.) So, I'm looking for way to make sure that any Fiber I start with `.transfer` will be properly terminated. But what I noticed is that when a transfer-based Fiber terminates, it gives control back to the top-most Fiber, not the Fiber which transfered to it. Is this intended? Here's a script to replicate the issue: ```ruby manager = Fiber.new do parent = Fiber.current worker = Fiber.new do puts "2. Begin Worker" parent.transfer puts "4. End Worker" end puts "1. Transfer 1" worker.transfer puts "3. Transfer 2" worker.transfer puts "5. Finished manager" end manager.transfer puts "6. Finished script" ``` I expect the steps to print in order: ``` 1. Transfer 1 2. Begin Worker 3. Transfer 2 4. End Worker 5. Finished manager 6. Finished script ``` But instead, `5. ...` is skipped: ``` 1. Transfer 1 2. Begin Worker 3. Transfer 2 4. End Worker 6. Finished script ``` I think that's because my `worker` fiber terminates and passes control back to the top-level Fiber. Should it have passed control back to the `manager`? Or is there another way to make sure `worker` is terminated, and `manager` gets control? -- https://bugs.ruby-lang.org/
3 9
0 0
  • ← Newer
  • 1
  • ...
  • 13
  • 14
  • 15
  • 16
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.