ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
@ 2025-05-22  8:39 ioquatix (Samuel Williams) via ruby-core
  2025-05-22 10:15 ` [ruby-core:122231] " Eregon (Benoit Daloze) via ruby-core
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: ioquatix (Samuel Williams) via ruby-core @ 2025-05-22  8:39 UTC (permalink / raw)
  To: ruby-core; +Cc: ioquatix (Samuel Williams)

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

----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359

* Author: ioquatix (Samuel Williams)
* Status: Open
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:122231] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
  2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
@ 2025-05-22 10:15 ` Eregon (Benoit Daloze) via ruby-core
  2025-05-22 12:12 ` [ruby-core:122233] " ioquatix (Samuel Williams) via ruby-core
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Eregon (Benoit Daloze) via ruby-core @ 2025-05-22 10:15 UTC (permalink / raw)
  To: ruby-core; +Cc: Eregon (Benoit Daloze)

Issue #21359 has been updated by Eregon (Benoit Daloze).


Do you have real-world examples where you would use this, e.g. in gems?

----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359#change-113379

* Author: ioquatix (Samuel Williams)
* Status: Open
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:122233] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
  2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
  2025-05-22 10:15 ` [ruby-core:122231] " Eregon (Benoit Daloze) via ruby-core
@ 2025-05-22 12:12 ` ioquatix (Samuel Williams) via ruby-core
  2025-05-22 20:00 ` [ruby-core:122237] " Eregon (Benoit Daloze) via ruby-core
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: ioquatix (Samuel Williams) via ruby-core @ 2025-05-22 12:12 UTC (permalink / raw)
  To: ruby-core; +Cc: ioquatix (Samuel Williams)

Issue #21359 has been updated by ioquatix (Samuel Williams).


Yes, in Async, I want to set the cause of an exception before raising it later on a fiber.

Additionally, serialisation and deserialisation of exceptions is almost impossible without being able to set the cause, e.g. any kind of Ruby RPC.

----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359#change-113381

* Author: ioquatix (Samuel Williams)
* Status: Open
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:122237] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
  2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
  2025-05-22 10:15 ` [ruby-core:122231] " Eregon (Benoit Daloze) via ruby-core
  2025-05-22 12:12 ` [ruby-core:122233] " ioquatix (Samuel Williams) via ruby-core
@ 2025-05-22 20:00 ` Eregon (Benoit Daloze) via ruby-core
  2025-05-22 23:44 ` [ruby-core:122243] " ioquatix (Samuel Williams) via ruby-core
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Eregon (Benoit Daloze) via ruby-core @ 2025-05-22 20:00 UTC (permalink / raw)
  To: ruby-core; +Cc: Eregon (Benoit Daloze)

Issue #21359 has been updated by Eregon (Benoit Daloze).


ioquatix (Samuel Williams) wrote in #note-2:
> Yes, in Async, I want to set the cause of an exception before raising it later on a fiber.

#21360 would be enough for that, although you'd need to wrap the exception + cause-to-be in some extra object.

> Additionally, serialisation and deserialisation of exceptions is almost impossible without being able to set the cause, e.g. any kind of Ruby RPC.

WDYM by almost impossible?
Causes can't be cyclic so that's not an issue (which BTW means we would need to check that in this assignment method).
`Marshal` can do it I guess.
And if not `raise self, cause: value` + `rescue` but I agree that's hacky and inefficient.

Serializing exceptions properly without Marshal is probably quite hard yes, not only about the cause but also the internal backtrace representation, the `backtrace_locations` objects, other internal state for core exceptions that can't always be set in constructor, etc.
But is there a need for that?

----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359#change-113387

* Author: ioquatix (Samuel Williams)
* Status: Open
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:122243] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
  2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
                   ` (2 preceding siblings ...)
  2025-05-22 20:00 ` [ruby-core:122237] " Eregon (Benoit Daloze) via ruby-core
@ 2025-05-22 23:44 ` ioquatix (Samuel Williams) via ruby-core
  2025-05-23 14:08 ` [ruby-core:122251] " Eregon (Benoit Daloze) via ruby-core
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: ioquatix (Samuel Williams) via ruby-core @ 2025-05-22 23:44 UTC (permalink / raw)
  To: ruby-core; +Cc: ioquatix (Samuel Williams)

Issue #21359 has been updated by ioquatix (Samuel Williams).


> Serializing exceptions properly without Marshal is probably quite hard yes, not only about the cause but also the internal backtrace representation, the backtrace_locations objects, other internal state for core exceptions that can't always be set in constructor, etc. But is there a need for that?

Yes, serialisation with msgpack is painful and impossible to do correctly in some situations, if you have custom serialisation rules for certain object types (using a msgpack factory), you can't use `Marshal.dump` as part of msgpack's serialisation because it won't correctly serialise the internal objects of the exception.

----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359#change-113389

* Author: ioquatix (Samuel Williams)
* Status: Open
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:122251] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
  2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
                   ` (3 preceding siblings ...)
  2025-05-22 23:44 ` [ruby-core:122243] " ioquatix (Samuel Williams) via ruby-core
@ 2025-05-23 14:08 ` Eregon (Benoit Daloze) via ruby-core
  2025-05-27 13:39 ` [ruby-core:122310] " zzak (zzak _) via ruby-core
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Eregon (Benoit Daloze) via ruby-core @ 2025-05-23 14:08 UTC (permalink / raw)
  To: ruby-core; +Cc: Eregon (Benoit Daloze)

Issue #21359 has been updated by Eregon (Benoit Daloze).


`msgpack` doesn't seem to handle recursive data structures:
```
irb(main):003> a=[]
=> []
irb(main):004> a<<a
=> [[...]]
irb(main):005> a
=> [[...]]
irb(main):006> a.to_msgpack
msgpack-1.8.0/lib/msgpack.rb:41:in `write': stack level too deep (SystemStackError)
```
So I think it's unrealistic to try to serialize/deserialize exceptions or complex objects with msgpack, it seems really meant for non-recursive simple data.

----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359#change-113397

* Author: ioquatix (Samuel Williams)
* Status: Open
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:122310] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
  2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
                   ` (4 preceding siblings ...)
  2025-05-23 14:08 ` [ruby-core:122251] " Eregon (Benoit Daloze) via ruby-core
@ 2025-05-27 13:39 ` zzak (zzak _) via ruby-core
  2025-06-05  9:07 ` [ruby-core:122440] " matz (Yukihiro Matsumoto) via ruby-core
  2025-06-05  9:25 ` [ruby-core:122445] " Eregon (Benoit Daloze) via ruby-core
  7 siblings, 0 replies; 9+ messages in thread
From: zzak (zzak _) via ruby-core @ 2025-05-27 13:39 UTC (permalink / raw)
  To: ruby-core; +Cc: zzak (zzak _)

Issue #21359 has been updated by zzak (zzak _).


Another thing to consider is we don't have `Exception#backtrace=` but instead `Exception#set_backtrace`.

So an alternative is `Exception#set_cause` or `Exception#set_backtrace(cause:)`. I guess.

----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359#change-113452

* Author: ioquatix (Samuel Williams)
* Status: Open
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:122440] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
  2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
                   ` (5 preceding siblings ...)
  2025-05-27 13:39 ` [ruby-core:122310] " zzak (zzak _) via ruby-core
@ 2025-06-05  9:07 ` matz (Yukihiro Matsumoto) via ruby-core
  2025-06-05  9:25 ` [ruby-core:122445] " Eregon (Benoit Daloze) via ruby-core
  7 siblings, 0 replies; 9+ messages in thread
From: matz (Yukihiro Matsumoto) via ruby-core @ 2025-06-05  9:07 UTC (permalink / raw)
  To: ruby-core; +Cc: matz (Yukihiro Matsumoto)

Issue #21359 has been updated by matz (Yukihiro Matsumoto).


I am basically against `cause=` (or `set_cause` that is). It makes exceptions more complex. Is it impossible to defer exception creation til it is absolutely needed?

Matz.


----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359#change-113621

* Author: ioquatix (Samuel Williams)
* Status: Assigned
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [ruby-core:122445] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment
  2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
                   ` (6 preceding siblings ...)
  2025-06-05  9:07 ` [ruby-core:122440] " matz (Yukihiro Matsumoto) via ruby-core
@ 2025-06-05  9:25 ` Eregon (Benoit Daloze) via ruby-core
  7 siblings, 0 replies; 9+ messages in thread
From: Eregon (Benoit Daloze) via ruby-core @ 2025-06-05  9:25 UTC (permalink / raw)
  To: ruby-core; +Cc: Eregon (Benoit Daloze)

Issue #21359 has been updated by Eregon (Benoit Daloze).


Maybe `Exception.new("message", cause: cause)` should be supported, but I suppose that might be quite hard to support for all subclasses of `Exception`.
That's probably the reason it's on `raise` and not in exception constructor.
BTW it's also `raise` that sets the (initial) backtrace of an exception, not the exception constructor (unlike in Java).

Maybe `Exception#exception` could accept a `cause:` kwarg?

----------------------------------------
Feature #21359: Introduce `Exception#cause=` for Post-Initialization Assignment
https://bugs.ruby-lang.org/issues/21359#change-113626

* Author: ioquatix (Samuel Williams)
* Status: Assigned
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
Ruby currently allows an exception’s `cause` to be explicitly set **only at the time of raising** using `raise ..., cause: ...`. However, there are valid use cases where it would be convenient to set the cause when creating an exception.

## The Problem

Ruby supports exception chaining via the `cause:` keyword during a `raise`, like so:

```ruby
raise StandardError.new("failure"), cause: original_exception
```

## Proposed Solution

Introduce `Exception#cause=` as a public setter method on `Exception`, allowing post-initialization assignment of the cause:

```ruby
cause = RuntimeError.new("low-level error")
error = StandardError.new("higher-level error")
error.cause = cause
```

It would be semantically equivalent to the following implementation:

```ruby
error = StandardError.new("error")
cause = RuntimeError.new("cause")

class Exception
  def cause= value
    backtrace = self.backtrace_locations

    raise self, cause: value
  rescue Exception
    self.set_backtrace(backtrace)
  end
end

p error.cause # nil
error.cause = cause
p error.cause # => #<RuntimeError: cause>
```

### Benefits

* Simplifies creation of rich exception objects in frameworks, tools, and tests.
* Enables structured error chaining in asynchronous and deferred execution environments.
* Avoids misuse of `raise`/`rescue` for control flow and metadata setting.




-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-06-05  9:26 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-22  8:39 [ruby-core:122228] [Ruby Feature#21359] Introduce `Exception#cause=` for Post-Initialization Assignment ioquatix (Samuel Williams) via ruby-core
2025-05-22 10:15 ` [ruby-core:122231] " Eregon (Benoit Daloze) via ruby-core
2025-05-22 12:12 ` [ruby-core:122233] " ioquatix (Samuel Williams) via ruby-core
2025-05-22 20:00 ` [ruby-core:122237] " Eregon (Benoit Daloze) via ruby-core
2025-05-22 23:44 ` [ruby-core:122243] " ioquatix (Samuel Williams) via ruby-core
2025-05-23 14:08 ` [ruby-core:122251] " Eregon (Benoit Daloze) via ruby-core
2025-05-27 13:39 ` [ruby-core:122310] " zzak (zzak _) via ruby-core
2025-06-05  9:07 ` [ruby-core:122440] " matz (Yukihiro Matsumoto) via ruby-core
2025-06-05  9:25 ` [ruby-core:122445] " Eregon (Benoit Daloze) via ruby-core

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).