[#109844] [Ruby master Feature#18996] Proposal: Introduce new APIs to reline for changing dialog UI colours — "st0012 (Stan Lo)" <noreply@...>

Issue #18996 has been reported by st0012 (Stan Lo).

14 messages 2022/09/07

[#109850] [Ruby master Feature#19000] Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object] — "RubyBugs (A Nonymous)" <noreply@...>

Issue #19000 has been reported by RubyBugs (A Nonymous).

42 messages 2022/09/08

[#109905] [Ruby master Bug#19005] Ruby interpreter compiled XCode 14 cannot build some native gems on macOS — "stanhu (Stan Hu)" <noreply@...>

Issue #19005 has been reported by stanhu (Stan Hu).

28 messages 2022/09/15

[#109930] [Ruby master Bug#19007] Unicode tables differences from Unicode.org 14.0 data and removed properties since 13.0 — "nobu (Nobuyoshi Nakada)" <noreply@...>

Issue #19007 has been reported by nobu (Nobuyoshi Nakada).

8 messages 2022/09/17

[#109937] [Ruby master Feature#19008] Introduce coverage support for `eval`. — "ioquatix (Samuel Williams)" <noreply@...>

Issue #19008 has been reported by ioquatix (Samuel Williams).

23 messages 2022/09/17

[#109961] [Ruby master Bug#19012] BasicSocket#recv* methods return an empty packet instead of nil on closed connections — "byroot (Jean Boussier)" <noreply@...>

Issue #19012 has been reported by byroot (Jean Boussier).

8 messages 2022/09/20

[#109985] [Ruby master Feature#19015] Language extension by a heredoc — "ko1 (Koichi Sasada)" <noreply@...>

Issue #19015 has been reported by ko1 (Koichi Sasada).

14 messages 2022/09/22

[#109995] [Ruby master Bug#19016] syntax_suggest is not working with Ruby 3.2.0-preview2 — "hsbt (Hiroshi SHIBATA)" <noreply@...>

Issue #19016 has been reported by hsbt (Hiroshi SHIBATA).

9 messages 2022/09/22

[#110097] [Ruby master Feature#19024] Proposal: Import Modules — "shioyama (Chris Salzberg)" <noreply@...>

SXNzdWUgIzE5MDI0IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHNoaW95YW1hIChDaHJpcyBTYWx6YmVy

27 messages 2022/09/27

[#110119] [Ruby master Bug#19026] Add `Coverage.supported?(x)` to detect support for `eval` coverage flag. — "ioquatix (Samuel Williams)" <noreply@...>

SXNzdWUgIzE5MDI2IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGlvcXVhdGl4IChTYW11ZWwgV2lsbGlh

10 messages 2022/09/28

[#110133] [Ruby master Bug#19028] GCC12 Introduces new warn flags `-Wuse-after-free` — "eightbitraptor (Matthew Valentine-House)" <noreply@...>

SXNzdWUgIzE5MDI4IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGVpZ2h0Yml0cmFwdG9yIChNYXR0aGV3

8 messages 2022/09/28

[#110145] [Ruby master Misc#19030] [ANN] Migrate lists.ruby-lang.org to Google Groups — "hsbt (Hiroshi SHIBATA)" <noreply@...>

SXNzdWUgIzE5MDMwIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGhzYnQgKEhpcm9zaGkgU0hJQkFUQSku

12 messages 2022/09/29

[#110154] [Ruby master Bug#19033] One-liner pattern match as Boolean arg syntax error — "baweaver (Brandon Weaver)" <noreply@...>

SXNzdWUgIzE5MDMzIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGJhd2VhdmVyIChCcmFuZG9uIFdlYXZl

7 messages 2022/09/30

[ruby-core:109856] [Ruby master Feature#19000] Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object]

From: "bkuhlmann (Brooke Kuhlmann)" <noreply@...>
Date: 2022-09-08 19:47:49 UTC
List: ruby-core #109856
Issue #19000 has been updated by bkuhlmann (Brooke Kuhlmann).


 In case it's of interest, I've partially solved this problem in the [Refinements](https://www.alchemists.io/projects/refinements) gem several years back by adding the `#merge` and `#merge!` methods to `Struct` as a refinement. Here's the [source code](https://github.com/bkuhlmann/refinements/blob/main/lib/refinements/structs.rb#L18-L23). I'm mostly posting this here in case it helps provide more example solutions to the problem mentioned in Alternative B above:

``` ruby
point = Point.new(**(Origin.to_h.merge(change)))
```

I've found that using keyword arguments, regardless of whether the struct was constructed using positionals or keywords, has been very effective in practice.

----------------------------------------
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-99093

* 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
# A new class
Point = Data.def(: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) { |p, move| p.with(**move) }
```

## 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: 窶彿mmutable record structs 窶Non-destructive mutation” — is called `with { ... }`
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record#nondestructive-mutation

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-instances-from-other-instances-with-struct-update-syntax

## 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/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread