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
  • ----- 2025 -----
  • 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

  • 5 participants
  • 3280 discussions
[ruby-core:111168] [Ruby master Feature#18980] Re-reconsider numbered parameters: `it` as a default block parameter
by ufuk (Ufuk Kayserilioglu) 02 Dec '22

02 Dec '22
Issue #18980 has been updated by ufuk (Ufuk Kayserilioglu). @maedi `_$`, and especially `$`, have the same problems as `@` in which it is super easy to confuse and hard to differentiate `$.size` vs `$size`, as mentioned here https://bugs.ruby-lang.org/issues/18980#note-28 ---------------------------------------- Feature #18980: Re-reconsider numbered parameters: `it` as a default block parameter https://bugs.ruby-lang.org/issues/18980#change-100453 * Author: k0kubun (Takashi Kokubun) * Status: Open * Priority: Normal ---------------------------------------- ## Problem Numbered parameters (`_1`, `_2`, ...) look like unused local variables and I don't feel motivated to use them, even though I need this feature very often and always come up with `_1`. ```rb [1, 2, 3].each { puts _1 } ``` I have barely used it in the last 2~3 years because it looks like a compromised syntax. I even hesitate to use it on IRB. ### Why I don't use `_1` I'm not clever enough to remember the order of parameters. Therefore, when a block has multiple parameters, I'd always want to name those parameters because which is `_1` or `_2` is not immediately obvious. Thus I would use this feature only when a block takes a single argument, which is actually pretty common. If I use `_1`, it feels like there might be a second argument, and you might waste time to think about `_2`, even if `_2` doesn't exist, which is a cognitive overhead. If you use `it`, it kinda implies there's only a single argument, so you don't need to spend time remembering whether `_2` exists or not. It is important for me that there's no number in `it`. ## Proposal Hoping to introduce `it` as an alternative to `_1` later, experiment with warning `#it` method calls without any arguments or blocks. If nobody sees serious problems after some warning period, we'll implement `it` as follows: ### Specification ```rb [1, 2, 3].each { puts it } ``` `it`s behavior should be as close to `_1` as possible. `it` should treat array arguments in the same way as `_1`. `it` doesn't work in a block when an ordinary parameter is defined. `it` is implemented as a special case of `getlocal` insn, not a method. `it` without an argument is considered `_1` or a normal local variable if defined. `it` is considered a method call only when it has any positional/keyword/block arguments. ## Past discussions * [Feature #4475] default variable name for parameter: Proposed `it`, and merged as `@1`. * 2019/03/13: [DevelopersMeeting20190311Japan](https://docs.google.com/document/d/e/2PACX-… * 2019/04/17: [DevelopersMeeting20190417Japan](https://docs.google.com/document/d/1hw6Xca8… * 2019/04/20: [Ruby Committers vs the World](https://youtu.be/5eAXAUTtNYU?t=3118) * [Feature #15723] Reconsider numbered parameters: Renamed `@1` to `_1`. * 2019/08/29: [DevelopersMeeting20190829Japan](https://docs.google.com/document/d/1XypDO1c… * [Feature #15897] `it` as a default block parameter: Proposed `it`, and got closed because `_1` was merged. ### Compatibility `it` has not necessarily been rejected by Matz; he just said [it's difficult to keep compatibility](https://bugs.ruby-lang.org/issues/4475#note-6) and [`it` or `this` _could_ break existing code](https://bugs.ruby-lang.org/issues/15723#note-2). It feels like everybody thinks `it` is the most beautiful option but is not sure if `it` breaks compatibility. But, in reality, does `it`? The following cases have been discussed: * `it` method, most famously in RSpec: You almost always pass a positional and/or block argument to RSpec's `it`, so the conflict is avoided with my proposal. You virtually never use a completely naked `it` ([comment](https://bugs.ruby-lang.org/issues/15897#note-29)) * `it` local variable: With the specification in my proposal, the existing code can continue to work if we consider `it` as a local variable when defined. With the specification in my proposal, existing code seems to break if and only if you call a method `#it` without an argument. But it seems pretty rare (reminder: a block given to an RSpec test case is also an argument). It almost feels like people are too afraid of compatibility problems that barely exist or have not really thought about options to address them. Also, you could always experiment with just showing warnings, which doesn't break any compatibility. Even if it takes 2~3 years of a warning period, I'd be happy to use that in 3 years. ### Confusion We should separately discuss incompatible cases and "works but confusing" cases. Potential confusion points: * RSpec's `it "tests something" do ... end` vs `it` inside the `do ... end` * `it` could be a local variable or `_1`, depending on the situation My two cents: You'd rarely need to write `it` directly under RSpec's `it` block, and you would just name a block argument for that case. In a nested block under a test case, I don't think you'd feel `it` is RSpec's. When you use a local variable `it = 1`, you'd use the local variable in a very small scope or few lines because otherwise, it'd be very hard to figure out what the local variable has anyway. So you'd likely see the assignment `it = 1` near the use of the local variable and you could easily notice `it` is not `_1`. If not, such code would be confusing and fragile even without this feature. The same applies when `it` is a method/block argument. I believe it wouldn't be as confusing as some people think, and you can always choose to not use `it` in places where `it` is confusing. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111155] [Ruby master Bug#19173] syntax_suggest segfaults on syntax error when refinement activated
by tomstuart (Tom Stuart) 02 Dec '22

02 Dec '22
Issue #19173 has been reported by tomstuart (Tom Stuart). ---------------------------------------- Bug #19173: syntax_suggest segfaults on syntax error when refinement activated https://bugs.ruby-lang.org/issues/19173 * Author: tomstuart (Tom Stuart) * Status: Open * Priority: Normal * ruby -v: ruby 3.2.0dev (2022-12-02T10:47:18Z master 11871e49c4) [arm64-darwin21] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- While reporting certain syntax errors (e.g. “Invalid yield”, “Invalid redo”), `syntax_suggest` segfaults when a refinement is activated: ``` % echo 'yield' > test.rb; ruby test.rb test.rb:1: Invalid yield test.rb: compile error (SyntaxError) % echo 'using Module.new; yield' > test.rb; ruby test.rb test.rb:1: Invalid yield /Users/tom/.rubies/ruby-master/lib/ruby/3.2.0+3/fileutils.rb:2646: [BUG] Segmentation fault at 0x0000000000000008 […] -- Ruby level backtrace information ---------------------------------------- /Users/tom/.rubies/ruby-master/lib/ruby/3.2.0+3/syntax_suggest/core_ext.rb:25:in `detailed_message' ``` There’s no problem if `syntax_suggest` is disabled: ``` % echo 'using Module.new; yield' > test.rb; ruby --disable-syntax_suggest test.rb test.rb:1: Invalid yield test.rb: compile error (SyntaxError) ``` This bug exists on both `3.2.0-preview3` and `master`, and I’ve verified it on x86_64 as well as my arm64 machine. A crash report log is attached. ---Files-------------------------------- ruby-2022-12-02-122013.ips (16.4 KB) -- https://bugs.ruby-lang.org/
3 2
0 0
[ruby-core:111166] [Ruby master Feature#18980] Re-reconsider numbered parameters: `it` as a default block parameter
by maedi (Maedi Prichard) 02 Dec '22

02 Dec '22
Issue #18980 has been updated by maedi (Maedi Prichard). Or `_$`: ```Ruby [1, 2, 3].map { puts _$ } ``` ``` [1, 2, 3].map { puts _$ } ``` Or even just `$` by itself: ```Ruby [1, 2, 3].map { puts $ } ``` ``` [1, 2, 3].map { puts $ } ``` In my opinion $ is under utilised in Ruby compared to other languages. In writing day to day code you don’t often use global variables, so $ could provide an entirely unique local “this” variable without mentally switching to the global context. ---------------------------------------- Feature #18980: Re-reconsider numbered parameters: `it` as a default block parameter https://bugs.ruby-lang.org/issues/18980#change-100451 * Author: k0kubun (Takashi Kokubun) * Status: Open * Priority: Normal ---------------------------------------- ## Problem Numbered parameters (`_1`, `_2`, ...) look like unused local variables and I don't feel motivated to use them, even though I need this feature very often and always come up with `_1`. ```rb [1, 2, 3].each { puts _1 } ``` I have barely used it in the last 2~3 years because it looks like a compromised syntax. I even hesitate to use it on IRB. ### Why I don't use `_1` I'm not clever enough to remember the order of parameters. Therefore, when a block has multiple parameters, I'd always want to name those parameters because which is `_1` or `_2` is not immediately obvious. Thus I would use this feature only when a block takes a single argument, which is actually pretty common. If I use `_1`, it feels like there might be a second argument, and you might waste time to think about `_2`, even if `_2` doesn't exist, which is a cognitive overhead. If you use `it`, it kinda implies there's only a single argument, so you don't need to spend time remembering whether `_2` exists or not. It is important for me that there's no number in `it`. ## Proposal Hoping to introduce `it` as an alternative to `_1` later, experiment with warning `#it` method calls without any arguments or blocks. If nobody sees serious problems after some warning period, we'll implement `it` as follows: ### Specification ```rb [1, 2, 3].each { puts it } ``` `it`s behavior should be as close to `_1` as possible. `it` should treat array arguments in the same way as `_1`. `it` doesn't work in a block when an ordinary parameter is defined. `it` is implemented as a special case of `getlocal` insn, not a method. `it` without an argument is considered `_1` or a normal local variable if defined. `it` is considered a method call only when it has any positional/keyword/block arguments. ## Past discussions * [Feature #4475] default variable name for parameter: Proposed `it`, and merged as `@1`. * 2019/03/13: [DevelopersMeeting20190311Japan](https://docs.google.com/document/d/e/2PACX-… * 2019/04/17: [DevelopersMeeting20190417Japan](https://docs.google.com/document/d/1hw6Xca8… * 2019/04/20: [Ruby Committers vs the World](https://youtu.be/5eAXAUTtNYU?t=3118) * [Feature #15723] Reconsider numbered parameters: Renamed `@1` to `_1`. * 2019/08/29: [DevelopersMeeting20190829Japan](https://docs.google.com/document/d/1XypDO1c… * [Feature #15897] `it` as a default block parameter: Proposed `it`, and got closed because `_1` was merged. ### Compatibility `it` has not necessarily been rejected by Matz; he just said [it's difficult to keep compatibility](https://bugs.ruby-lang.org/issues/4475#note-6) and [`it` or `this` _could_ break existing code](https://bugs.ruby-lang.org/issues/15723#note-2). It feels like everybody thinks `it` is the most beautiful option but is not sure if `it` breaks compatibility. But, in reality, does `it`? The following cases have been discussed: * `it` method, most famously in RSpec: You almost always pass a positional and/or block argument to RSpec's `it`, so the conflict is avoided with my proposal. You virtually never use a completely naked `it` ([comment](https://bugs.ruby-lang.org/issues/15897#note-29)) * `it` local variable: With the specification in my proposal, the existing code can continue to work if we consider `it` as a local variable when defined. With the specification in my proposal, existing code seems to break if and only if you call a method `#it` without an argument. But it seems pretty rare (reminder: a block given to an RSpec test case is also an argument). It almost feels like people are too afraid of compatibility problems that barely exist or have not really thought about options to address them. Also, you could always experiment with just showing warnings, which doesn't break any compatibility. Even if it takes 2~3 years of a warning period, I'd be happy to use that in 3 years. ### Confusion We should separately discuss incompatible cases and "works but confusing" cases. Potential confusion points: * RSpec's `it "tests something" do ... end` vs `it` inside the `do ... end` * `it` could be a local variable or `_1`, depending on the situation My two cents: You'd rarely need to write `it` directly under RSpec's `it` block, and you would just name a block argument for that case. In a nested block under a test case, I don't think you'd feel `it` is RSpec's. When you use a local variable `it = 1`, you'd use the local variable in a very small scope or few lines because otherwise, it'd be very hard to figure out what the local variable has anyway. So you'd likely see the assignment `it = 1` near the use of the local variable and you could easily notice `it` is not `_1`. If not, such code would be confusing and fragile even without this feature. The same applies when `it` is a method/block argument. I believe it wouldn't be as confusing as some people think, and you can always choose to not use `it` in places where `it` is confusing. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111164] [Ruby master Feature#17325] Adds Fiber#cancel, which forces a Fiber to break/return
by ioquatix (Samuel Williams) 02 Dec '22

02 Dec '22
Issue #17325 has been updated by ioquatix (Samuel Williams). I'm not against this feature, but I'm not sure if it has a valid use case. I like the idea of using break as a semantic for making a fiber exit in a similar way to a method call, etc. `Fiber#raise` is currently used for cancellation like semantics, but it uses an exception. Maybe `break` is better, but efficiently is not a strong argument here, at least, in the case where terminating a fiber is a rare occurrence. But using a `Stop` exception is probably not as good as a clean semantic for termination as a break mechanic. ---------------------------------------- Feature #17325: Adds Fiber#cancel, which forces a Fiber to break/return https://bugs.ruby-lang.org/issues/17325#change-100449 * Author: nevans (Nicholas Evans) * Status: Open * Priority: Normal ---------------------------------------- Calling `Fiber#cancel` will force a fiber to return, skipping rescue and catch blocks but running all ensure blocks. It behaves as if a `break` or `return` were used to jump from the last suspension point to the top frame of the fiber. Control will be transferred to the canceled fiber so it can run its ensure blocks. ## Propagation from resuming to resumed fibers Any non-root living fiber can be canceled and cancellation will propagate to child (resumed) fibers. In this way, a suspended task can be canceled even if it is e.g. resuming into an enumerator, and the enumerator will be canceled as well. Transfer of control should match #17221's *(much improved)* transfer/resume semantics. After the cancellation propagates all the way to the bottom of the fiber resume stack, the last fiber in the chain will then be resumed. Resuming fibers will not run until they are yielded back into. ## Suspension of canceled fibers Canceled fibers can still transfer control with `resume`, `yield`, and `transfer`, which may be necessary in order to release resources from `ensure` blocks. For simplicity, subsequent cancels will behave similarly to calling `break` or `return` inside an `ensure` block, and the last cancellation reason will overwrite earlier reasons. ## Alternatives `Fiber#raise` could be used, but: * Can only raise on resumable fibers. * Cannot propagate cancellation down to resumed fibers. * Exceptions are bigger and slower than `break`. * `#raise` can't (and shouldn't) be sent to resuming fibers. (It can't propagate.) * Exceptions can be caught. This might be desirable, but that should be at the discretion of the calling fiber. Catch/Throw could be used (with an anonymous `Object.new`), but: * We would need to add `Fiber#throw` (or wrap/intercept `Fiber.yield`). * A hypothetical `Fiber#throw` should probably have similar semantics to `#resume` and thus only be allowed on resumable fibers. * In that case, it wouldn't propagate down to resumed fibers. * `catch` adds an extra stack frame. We could use go-style "Context" objects that contain a "done?" queue/future. * These would need to be explicitly passed around. * Although their usage could be enforced via linters like rubocop, I think that placing it off to the side will give developers the impression that it is optional Some sort of cancel propagation mechanism is not optional for structured concurrency. * It should built into any task-scheduler library, which would allow application code to use it explicitly. * But this suffers the same problem as current Fiber wrappers: it works fine if your code uses the wrapper, but code that uses fibers without the wrapper can be incompatible and introduce bugs (e.g. fibers that are released without running their `ensure` blocks). * This make sense for a language like go which doesn't have exceptions but does have a convention of returning an "error" value. It feels out of place in ruby, IMO. Letting the fiber-task-scheduler mitigates that... for code that uses the fiber-task-scheduler. We could add a keyword option to `Fiber#raise` that gives it similar propagation semantics to this. * IMO, the simplicity of `Fiber#raise` simply being a specialized version of `Fiber#resume` is worth preserving. * The propagation changes alone are enough of a semantic difference to warrant a new method. We could implement `Fiber#cancel` by using `fiber.raise(FiberCancellationError)` on the bottom fiber and catching that exception during termination of the canceled fiber. * This would have the "benefit" that the exception could be rescued. * I might be wrong, but I think that doing this would mostly duplicate my PR, but with some added complexity around exception construction and catching. * It might be a good keyword option? e.g. `Fiber#cancel(with_exception: [true,#exception,#to_str])` Just let the task-fiber-scheduler library handle this. * That's what I'm already doing now. It's mostly fine. It works in my code. * Putting it into ruby core should lead to a small performance boost on very commonly repeated code. * There's probably a better way to store the `cancel_reason` that doesn't require the overhead of adding another `VALUE` to `rb_fiber_struct`. Maybe it can be placed directly into `errinfo`? * Although the common cases can be handled via a trampoline fiber or #17221, there can still be situations where your application's fiber-scheduler library might not know about fibers created by other libraries. This adds interoperability to a common scenario. * Coroutine cancellation is IMO a core feature. It's important to have something like this for all applications and libraries to use as a baseline for interoperability. Implementation: https://github.com/ruby/ruby/pull/3766 -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111163] [Ruby master Feature#17325] Adds Fiber#cancel, which forces a Fiber to break/return
by nevans (Nicholas Evans) 02 Dec '22

02 Dec '22
Issue #17325 has been updated by nevans (Nicholas Evans). This should be closed, in favor of a (TBD) configurable structured concurrency system, built on `Fiber.current.storage` (#19078). :) ---------------------------------------- Feature #17325: Adds Fiber#cancel, which forces a Fiber to break/return https://bugs.ruby-lang.org/issues/17325#change-100448 * Author: nevans (Nicholas Evans) * Status: Open * Priority: Normal ---------------------------------------- Calling `Fiber#cancel` will force a fiber to return, skipping rescue and catch blocks but running all ensure blocks. It behaves as if a `break` or `return` were used to jump from the last suspension point to the top frame of the fiber. Control will be transferred to the canceled fiber so it can run its ensure blocks. ## Propagation from resuming to resumed fibers Any non-root living fiber can be canceled and cancellation will propagate to child (resumed) fibers. In this way, a suspended task can be canceled even if it is e.g. resuming into an enumerator, and the enumerator will be canceled as well. Transfer of control should match #17221's *(much improved)* transfer/resume semantics. After the cancellation propagates all the way to the bottom of the fiber resume stack, the last fiber in the chain will then be resumed. Resuming fibers will not run until they are yielded back into. ## Suspension of canceled fibers Canceled fibers can still transfer control with `resume`, `yield`, and `transfer`, which may be necessary in order to release resources from `ensure` blocks. For simplicity, subsequent cancels will behave similarly to calling `break` or `return` inside an `ensure` block, and the last cancellation reason will overwrite earlier reasons. ## Alternatives `Fiber#raise` could be used, but: * Can only raise on resumable fibers. * Cannot propagate cancellation down to resumed fibers. * Exceptions are bigger and slower than `break`. * `#raise` can't (and shouldn't) be sent to resuming fibers. (It can't propagate.) * Exceptions can be caught. This might be desirable, but that should be at the discretion of the calling fiber. Catch/Throw could be used (with an anonymous `Object.new`), but: * We would need to add `Fiber#throw` (or wrap/intercept `Fiber.yield`). * A hypothetical `Fiber#throw` should probably have similar semantics to `#resume` and thus only be allowed on resumable fibers. * In that case, it wouldn't propagate down to resumed fibers. * `catch` adds an extra stack frame. We could use go-style "Context" objects that contain a "done?" queue/future. * These would need to be explicitly passed around. * Although their usage could be enforced via linters like rubocop, I think that placing it off to the side will give developers the impression that it is optional Some sort of cancel propagation mechanism is not optional for structured concurrency. * It should built into any task-scheduler library, which would allow application code to use it explicitly. * But this suffers the same problem as current Fiber wrappers: it works fine if your code uses the wrapper, but code that uses fibers without the wrapper can be incompatible and introduce bugs (e.g. fibers that are released without running their `ensure` blocks). * This make sense for a language like go which doesn't have exceptions but does have a convention of returning an "error" value. It feels out of place in ruby, IMO. Letting the fiber-task-scheduler mitigates that... for code that uses the fiber-task-scheduler. We could add a keyword option to `Fiber#raise` that gives it similar propagation semantics to this. * IMO, the simplicity of `Fiber#raise` simply being a specialized version of `Fiber#resume` is worth preserving. * The propagation changes alone are enough of a semantic difference to warrant a new method. We could implement `Fiber#cancel` by using `fiber.raise(FiberCancellationError)` on the bottom fiber and catching that exception during termination of the canceled fiber. * This would have the "benefit" that the exception could be rescued. * I might be wrong, but I think that doing this would mostly duplicate my PR, but with some added complexity around exception construction and catching. * It might be a good keyword option? e.g. `Fiber#cancel(with_exception: [true,#exception,#to_str])` Just let the task-fiber-scheduler library handle this. * That's what I'm already doing now. It's mostly fine. It works in my code. * Putting it into ruby core should lead to a small performance boost on very commonly repeated code. * There's probably a better way to store the `cancel_reason` that doesn't require the overhead of adding another `VALUE` to `rb_fiber_struct`. Maybe it can be placed directly into `errinfo`? * Although the common cases can be handled via a trampoline fiber or #17221, there can still be situations where your application's fiber-scheduler library might not know about fibers created by other libraries. This adds interoperability to a common scenario. * Coroutine cancellation is IMO a core feature. It's important to have something like this for all applications and libraries to use as a baseline for interoperability. Implementation: https://github.com/ruby/ruby/pull/3766 -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111162] [Ruby master Feature#19000] Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object]
by ufuk (Ufuk Kayserilioglu) 02 Dec '22

02 Dec '22
Issue #19000 has been updated by ufuk (Ufuk Kayserilioglu). Thanks for the discussion and the name suggestion. I updated the PR https://github.com/ruby/ruby/pull/6766 to use `Data#with`. I would be grateful if it could get a review. However, that raises a question: How should `Data#with` behave if it is passed no arguments? Semantically, that should mean "create a copy of the current data object with no fields changed", but then that ends up being identical to what `Kernel#dup` does. Also, `with` with no arguments does not read that well. @matz and @mame Should it be an error? Example: ```ruby Point = Data.define(:x, :y) origin = Point.new(x: 0, y: 0) new_origin = origin.with # should this be an error? ``` ---------------------------------------- Feature #19000: Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object] https://bugs.ruby-lang.org/issues/19000#change-100445 * Author: RubyBugs (A Nonymous) * Status: Open * Priority: Normal ---------------------------------------- *As requested: extracted a follow-up to #16122 Data: simple immutable value object from [this comment](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/109815)* # Proposal: Add a "Copy with changes" method to Data Assume the proposed `Data.define` exists. Seeing examples from the [[Values gem]](https://github.com/ms-ati/Values): ```ruby require "values" # A new class Point = Value.new(:x, :y) # An immutable instance Origin = Point.with(x: 0, y: 0) # Q: How do we make copies that change 1 or more values? right = Origin.with(x: 1.0) up = Origin.with(y: 1.0) up_and_right = right.with(y: up.y) # In loops movements = [ [ :x, +0.5 ], [ :x, +0.5 ], [ :y, -1.0 ], [ :x, +0.5 ], ] # position = Point(x: 1.5, y: -1.0) position = movements.inject(Origin) do |p, (field, delta)| p.with(field => p.send(field) + delta) end ``` ## Proposed detail: Call this method: `#with` ```ruby Money = Data.define(:amount, :currency) account = Money.new(amount: 100, currency: 'USD') transactions = [+10, -5, +15] account = transactions.inject(account) { |a, t| a.with(amount: a.amount + t) } #=> Money(amount: 120, currency: "USD") ``` ## Why add this "Copy with changes" method to the Data simple immutable value class? Called on an instance, it returns a new instance with only the provided parameters changed. This API affordance is now **widely adopted across many languages** for its usefulness. Why is it so useful? Because copying immutable value object instances, with 1 or more discrete changes to specific fields, is the proper and ubiquitous pattern that takes the place of mutation when working with immutable value objects. **Other languages** C# Records: “immutable record structs — Non-destructive mutation” — is called `with { ... }` https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-t… Scala Case Classes — is called `#copy` https://docs.scala-lang.org/tour/case-classes.html Java 14+ Records — Brian Goetz at Oracle is working on adding a with copy constructor inspired by C# above as we speak, likely to be called `#with` https://mail.openjdk.org/pipermail/amber-spec-experts/2022-June/003461.html Rust “Struct Update Syntax” via `..` syntax in constructor https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-insta… ## Alternatives Without a copy-with-changes method, one must construct entirely new instances using the constructor. This can either be (a) fully spelled out as boilerplate code, or (b) use a symmetrical `#to_h` to feed the keyword-args constructor. **(a) Boilerplate using constructor** ```ruby Point = Data.define(:x, :y, :z) Origin = Point.new(x: 0.0, y: 0.0, z: 0.0) change = { z: -1.5 } # Have to use full constructor -- does this even work? point = Point.new(x: Origin.x, y: Origin.y, **change) ``` **(b) Using a separately proposed `#to_h` method and constructor symmetry** ```ruby Point = Data.define(:x, :y, :z) Origin = Point.new(x: 0.0, y: 0.0, z: 0.0) change = { z: -1.5 } # Have to use full constructor -- does this even work? point = Point.new(**(Origin.to_h.merge(change))) ``` Notice that the above are not ergonomic -- leading so many of our peer language communities to adopt the `#with` method to copy an instance with discrete changes. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111161] [Ruby master Bug#19175] Ripper does not recognize some pattern matching defining local variable
by tompng (tomoya ishida) 02 Dec '22

02 Dec '22
Issue #19175 has been reported by tompng (tomoya ishida). ---------------------------------------- Bug #19175: Ripper does not recognize some pattern matching defining local variable https://bugs.ruby-lang.org/issues/19175 * Author: tompng (tomoya ishida) * Status: Open * Priority: Normal * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- Ripepr does not recognize hshptn and aryptn splat defining local variables. ~~~ruby Ripper.sexp('a in [*x]; x') # => [:program, [[:case, [:vcall, [:@ident, "a", [1, 0]]], [:in, [:aryptn, nil, nil, [:var_field, [:@ident, "x", [1, 7]]], nil], nil, nil]], [:vcall, [:@ident, "x", [1, 11]]]]] Ripper.sexp('a in {x:}; x') # => [:program, [[:case, [:vcall, [:@ident, "a", [1, 0]]], [:in, [:hshptn, nil, [[[:@label, "x:", [1, 6]], nil]], nil], nil, nil]], [:vcall, [:@ident, "x", [1, 11]]]]] ~~~ RubyVM::AbstractSyntaxTree returns `(LVAR@1:11-1:12 :x)` I think `[:vcall, [:@ident, "x", [1, 11]]]` should be `[:var_ref, [:@ident, "x", [1, 11]]]` Other pattern seems to be OK. ~~~ruby Ripper.sexp('a in [x, y => z]; x; y; z') # => [:program, [[:case, [:vcall, [:@ident, "a", [1, 0]]], [:in, [:aryptn, nil, [[:var_field, [:@ident, "x", [1, 6]]], [:binary, [:var_field, [:@ident, "y", [1, 9]]], :"=>", [:var_field, [:@ident, "z", [1, 14]]]]], nil, nil], nil, nil]], [:var_ref, [:@ident, "x", [1, 18]]], [:var_ref, [:@ident, "y", [1, 21]]], [:var_ref, [:@ident, "z", [1, 24]]]]] ~~~ -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111157] [Ruby master Bug#19174] YJIT configure "checking whether rustc works for YJIT... no" in rustc 1.65.0 on x86_64
by jaruga (Jun Aruga) 02 Dec '22

02 Dec '22
Issue #19174 has been reported by jaruga (Jun Aruga). ---------------------------------------- Bug #19174: YJIT configure "checking whether rustc works for YJIT... no" in rustc 1.65.0 on x86_64 https://bugs.ruby-lang.org/issues/19174 * Author: jaruga (Jun Aruga) * Status: Open * Priority: Normal * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- On the latest master branch `11871e49c4fe493d6b958046969bc863f7fb6627` on Fedora 36, ``` $ uname -m x86_64 $ which rustc /bin/rustc $ rustc --version rustc 1.65.0 (Fedora 1.65.0-1.fc37) ``` I am seeing the "checking whether rustc works for YJIT... no". ``` $ ./autogen.sh $ ./configure --enable-yjit 2>&1 | tee configure.log ... checking for rustc... rustc checking whether rustc works for YJIT... no ... * YJIT support: yes ... ``` Seeing the code <https://github.com/ruby/ruby/blob/11871e49c4fe493d6b958046969bc863f7fb6627/…>, it is to check if the rustc is >= 1.58.0. And the used rustc is 1.65.0. ``` dnl check if rustc is recent enough to build YJIT (rustc >= 1.58.0) ``` I suspect that the checking logic might be something wrong. I checked why the checking logic fails with the modification below. ``` $ git diff diff --git a/configure.ac b/configure.ac index 79167a9c67..33a1b9540d 100644 --- a/configure.ac +++ b/configure.ac @@ -3753,7 +3753,7 @@ AS_IF([test "$RUSTC" != "no"], dnl Fails in case rustc target doesn't match ruby target. dnl Can happen on Rosetta, for example. AS_IF([echo "#[cfg(target_arch = \"$YJIT_TARGET_ARCH\")]\n fn main() { let x = 1; format!(\"{x}\"); }" | - $RUSTC - --emit asm=/dev/null 2>/dev/null], + $RUSTC - --emit asm=/dev/null], [YJIT_RUSTC_OK=yes] ) AC_MSG_RESULT($YJIT_RUSTC_OK) ``` ``` $ ./autogen.sh $ ./configure --enable-yjit 2>&1 | tee configure_debug.log ... checking for rustc... rustc checking whether rustc works for YJIT... error: unknown start of token: \ --> <anon>:1:31 | 1 | #[cfg(target_arch = "x86_64")]\n fn main() { let x = 1; format!("{x}"); } | ^ error: expected one of `!` or `::`, found keyword `fn` --> <anon>:1:34 | 1 | #[cfg(target_arch = "x86_64")]\n fn main() { let x = 1; format!("{x}"); } | ^^ expected one of `!` or `::` error: aborting due to 2 previous errors no ... * YJIT support: yes ... ``` Is it intended behavior? Actually after running the `configure`, the `make` works. -- https://bugs.ruby-lang.org/
2 1
0 0
[ruby-core:111159] [Ruby master Feature#19078] Introduce `Fiber#storage` for inheritable fiber-scoped variables.
by nevans (Nicholas Evans) 02 Dec '22

02 Dec '22
Issue #19078 has been updated by nevans (Nicholas Evans). @Dan0042 (Daniel DeLorme) wrote in #note-21: > What about when we want per-ractor storage... a fourth type? FWIW, `Ractor#[]` has existed since 3.0: https://docs.ruby-lang.org/en/3.0/Ractor.html#method-i-5B-5D :) > Per-ractor inheritable storage... a fifth type? In my opinion, absolutely not. The following is just a hypothetical--if and when I have an actual proposal, I'll post it in another ticket. :) This feature is brand-new so it has some "rough edges", but I think should be updated to automatically share all ractor-sharable values. Of course, the big question is: what to do for non-ractor-sharable values? Hypothetically: 1) By default, simple raise an exception from Ractor.new, just like it does any other time you accidentally attempt to send non-sharable state into a new Ractor. 2) Add a kwarg to Ractor.new, and a method to the fiber storage, both of which will simply drop all non-ractor sharable storage. Either way: non-inheritance should always be an explicit opt-out. 3) Add an API for more fine-grained control at certain points, so that library authors can designate different behaviors via callback. Because often the desired behavior is more complicated than simply dropping or inheriting a variable: e.g. rather than inherit the current task id, a new fiber/thread/ractor might automatically create a brand new task which is a child of the current task. For inspiration here, we might look to Kotlin, which delegates a great deal of functionality to the current `coroutineContext[CoroutineDispatcher]` (this would be handled entirely by library code, and invisible to most users), to `coroutineContext[Job]` (which combines with `CoroutineScope` and a few others to handle almost everything related to structured concurrency), and any [ThreadContextElement] that's been added to the context. That last one is mostly used for backward compatibility with libraries that expect thread-locals. Similarly, go contexts delegate internally to `context.Value(cancelContextKey)`, where `cancelContextKey` is a private package var which is used purely for comparison-by-identity. This is essentially the `@key = Object.new` trick demonstrated by @ioquatix in #note-10, and it's the recommended usage pattern for context keys in go. [ThreadContextElement]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotli… Anyway: my goal here isn't to propose any particular approach, but to show this feature might be used as a foundation for other future features. IMO, fine-grained inheritance control might be out-of-scope for 3.2 (at least, any API we put together now would need to be marked "experimental"). I simply wanted to show how other languages build on a similar foundation to handle the problems you mentioned. ---------------------------------------- Feature #19078: Introduce `Fiber#storage` for inheritable fiber-scoped variables. https://bugs.ruby-lang.org/issues/19078#change-100443 * Author: ioquatix (Samuel Williams) * Status: Closed * Priority: Normal * Assignee: ioquatix (Samuel Williams) ---------------------------------------- Pull Request: https://github.com/ruby/ruby/pull/6612 This is an evolution of the previous ideas: - https://bugs.ruby-lang.org/issues/19058 - https://bugs.ruby-lang.org/issues/19062 This PR introduces fiber scoped variables, and is a solution for problems like <https://github.com/ioquatix/ioquatix/discussions/17>. The main interface is: ```ruby Fiber[key] = value Fiber[key] # => value ``` The variables are scoped (local to) a fiber and inherited into child fibers and threads. ```ruby Fiber[:request_id] = SecureRandom.hex(16) Fiber.new do p Fiber[:request_id] # prints the above request id end ``` The fiber scoped variables are stored and can be accessed: ```ruby Fiber.current.storage # => returns a Hash (copy) of the internal storage. Fiber.current.storage= # => assigns a Hash (copy) to the internal storage. ``` Fiber itself has one new keyword argument: ``` Fiber.new(..., storage: hash, false, undef, nil) ``` This can control how the fiber variables are setup in a child context. To minimise the performance overhead of some of the implementation choices, we are also simultaneously implementing <https://bugs.ruby-lang.org/issues/19077>. ## Examples ### Request loop ```ruby Thread.new do while request = queue.pop Fiber.new(storage: {id: SecureRandom.hex(16)}) do handle_request.call(request) end end end ``` OR ```ruby Thread.new do while request = queue.pop Fiber.current.storage = {id: SecureRandom.hex(16)} handle_request.call(request) end end ``` -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111158] [Ruby master Feature#19078] Introduce `Fiber#storage` for inheritable fiber-scoped variables.
by nevans (Nicholas Evans) 02 Dec '22

02 Dec '22
Issue #19078 has been updated by nevans (Nicholas Evans). I'm also a bit late to this. While I do have some nitpicks, I'll leave them for another ticket (if I ever get around to it). But, to answer a couple of @Dan0042's questions (and maybe others): As mentioned by @eregon above, one of the most important use-cases for this is structured concurrency. If you try to implement structured concurrency, you will eventually wind up needing and implementing some version of this feature. If you look at the documentation and API for go's and kotlin's versions of this feature, it's overwhelmingly about structured concurrency. @eregon included a good link describing structured concurrency, above. If I remember correctly, this page is also a good introduction to the idea: https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-con… ---- Here's a short list of the same basic feature, as implemented in several other languages (I copied a couple of these links from the other tickets linked in the description): * [go's context package](https://pkg.go.dev/context#pkg-overview) * Maybe the simplest implementation of the idea? * [Kotlin's Coroutine Contexts](https://kotlinlang.org/docs/coroutine-context-and-dispatchers.htm… * [python's contextvars](https://docs.python.org/3/library/contextvars.html) (integrated with `asyncio`, etc) * See [PEP 567](https://peps.python.org/pep-0567/) (and PEP-550 which preceded it) for more info on design details, etc. * [JEP 429: Extent-Local Variables](https://openjdk.org/jeps/429) This ticket is implemented a little bit differently than these, but is basically in the same category and has many of the same motivations, etc. ---------------------------------------- Feature #19078: Introduce `Fiber#storage` for inheritable fiber-scoped variables. https://bugs.ruby-lang.org/issues/19078#change-100441 * Author: ioquatix (Samuel Williams) * Status: Closed * Priority: Normal * Assignee: ioquatix (Samuel Williams) ---------------------------------------- Pull Request: https://github.com/ruby/ruby/pull/6612 This is an evolution of the previous ideas: - https://bugs.ruby-lang.org/issues/19058 - https://bugs.ruby-lang.org/issues/19062 This PR introduces fiber scoped variables, and is a solution for problems like <https://github.com/ioquatix/ioquatix/discussions/17>. The main interface is: ```ruby Fiber[key] = value Fiber[key] # => value ``` The variables are scoped (local to) a fiber and inherited into child fibers and threads. ```ruby Fiber[:request_id] = SecureRandom.hex(16) Fiber.new do p Fiber[:request_id] # prints the above request id end ``` The fiber scoped variables are stored and can be accessed: ```ruby Fiber.current.storage # => returns a Hash (copy) of the internal storage. Fiber.current.storage= # => assigns a Hash (copy) to the internal storage. ``` Fiber itself has one new keyword argument: ``` Fiber.new(..., storage: hash, false, undef, nil) ``` This can control how the fiber variables are setup in a child context. To minimise the performance overhead of some of the implementation choices, we are also simultaneously implementing <https://bugs.ruby-lang.org/issues/19077>. ## Examples ### Request loop ```ruby Thread.new do while request = queue.pop Fiber.new(storage: {id: SecureRandom.hex(16)}) do handle_request.call(request) end end end ``` OR ```ruby Thread.new do while request = queue.pop Fiber.current.storage = {id: SecureRandom.hex(16)} handle_request.call(request) end end ``` -- https://bugs.ruby-lang.org/
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • ...
  • 328
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.