ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:96768] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc
       [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
@ 2020-01-10 22:36 ` eregontp
  2020-01-11 22:44 ` [ruby-core:96793] " ruby-core
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: eregontp @ 2020-01-10 22:36 UTC (permalink / raw)
  To: ruby-core

Issue #16499 has been reported by Eregon (Benoit Daloze).

----------------------------------------
Feature #16499: define_method(non_lambda) should not the semantics of the given Proc
https://bugs.ruby-lang.org/issues/16499

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38

But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different).

This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent.
It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change.

We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically,
just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`.
But it would also preserve `arity`, `parameters`, etc.
Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently.

My point is we shall never change the semantics of `return`/`break` somewhere in the code.
It should always mean exactly one thing.
`define_method(name) { literal block }` is fine with that rule, it always behave as a lambda.
But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly.

I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not.

OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons.
We should look at those reasons and provide better alternatives.

I think sometimes people want to know how many arguments a non-lambda Proc takes.
For example, `proc { |a,b=1| }`.
`proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments.
They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value.
`lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

Maybe we should return the same as for a lambda for `non_lambda.parameters`?
`Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them.

cc @zverok



-- 
https://bugs.ruby-lang.org/

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

* [ruby-core:96793] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc
       [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
  2020-01-10 22:36 ` [ruby-core:96768] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc eregontp
@ 2020-01-11 22:44 ` ruby-core
  2020-01-12 14:20 ` [ruby-core:96802] " zverok.offline
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: ruby-core @ 2020-01-11 22:44 UTC (permalink / raw)
  To: ruby-core

Issue #16499 has been updated by marcandre (Marc-Andre Lafortune).


> I believe exactly 0 people want foo { return 42 } to change its meaning based on whether foo calls define_method or not.

This is wrong, there is at least me 😅

I believe that many API use `define_method` for metaprogramming and allow `return` within their blocks.

One example is RSpec's `let`:

```
  RSpec.describe Something do
    let(:foo) { return 42 }
  end
```

It is 100% clear what is meant and there are gazillions `let` blocks in the wild. This is just one example.

This would be a compatibility nightmare, for a gain I can not see (here simply raising an error).

I am strongly against this.

----------------------------------------
Feature #16499: define_method(non_lambda) should not the semantics of the given Proc
https://bugs.ruby-lang.org/issues/16499#change-83787

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38

But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different).

This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent.
It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change.

We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically,
just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`.
But it would also preserve `arity`, `parameters`, etc.
Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently.

My point is we shall never change the semantics of `return`/`break` somewhere in the code.
It should always mean exactly one thing.
`define_method(name) { literal block }` is fine with that rule, it always behave as a lambda.
But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly.

I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not.

OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons.
We should look at those reasons and provide better alternatives.

I think sometimes people want to know how many arguments a non-lambda Proc takes.
For example, `proc { |a,b=1| }`.
`proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments.
They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value.
`lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

Maybe we should return the same as for a lambda for `non_lambda.parameters`?
`Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them.

cc @zverok



-- 
https://bugs.ruby-lang.org/

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

* [ruby-core:96802] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc
       [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
  2020-01-10 22:36 ` [ruby-core:96768] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc eregontp
  2020-01-11 22:44 ` [ruby-core:96793] " ruby-core
@ 2020-01-12 14:20 ` zverok.offline
  2020-01-12 16:19 ` [ruby-core:96803] " eregontp
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: zverok.offline @ 2020-01-12 14:20 UTC (permalink / raw)
  To: ruby-core

Issue #16499 has been updated by zverok (Victor Shepelev).


@eregon what is the exact proposal of this ticket? I am not sure neither from title nor from description :(

As a side note, in regards to the last part:

> They might also look at proc.parameters which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate a and b even though only b has a proper default value.
> `lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

> Maybe we should return the same as for a lambda for non_lambda.parameters?

I believe curent behavior is pretty consistent, as it describes what it would realy accept. `req` means it will raise "Wrong number of arguments" if the argument is not provided, `opt` means it will accept argument's absence and will provide the default value. So, `proc { |a, b=1|` "real" signature (considering how it will process its args), is in fact `proc { |a=nil, b=1, *|`. **If** some complicated code accepts "any callable" and somehow validates "what args it requires", `opt` is more true for non-lambda's arg than `req`.

----------------------------------------
Feature #16499: define_method(non_lambda) should not the semantics of the given Proc
https://bugs.ruby-lang.org/issues/16499#change-83797

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38

But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different).

This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent.
It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change.

We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically,
just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`.
But it would also preserve `arity`, `parameters`, etc.
Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently.

My point is we shall never change the semantics of `return`/`break` somewhere in the code.
It should always mean exactly one thing.
`define_method(name) { literal block }` is fine with that rule, it always behave as a lambda.
But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly.

I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not.

OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons.
We should look at those reasons and provide better alternatives.

I think sometimes people want to know how many arguments a non-lambda Proc takes.
For example, `proc { |a,b=1| }`.
`proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments.
They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value.
`lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

Maybe we should return the same as for a lambda for `non_lambda.parameters`?
`Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them.

cc @zverok



-- 
https://bugs.ruby-lang.org/

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

* [ruby-core:96803] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc
       [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2020-01-12 14:20 ` [ruby-core:96802] " zverok.offline
@ 2020-01-12 16:19 ` eregontp
  2020-01-12 16:24 ` [ruby-core:96804] " eregontp
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: eregontp @ 2020-01-12 16:19 UTC (permalink / raw)
  To: ruby-core

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


marcandre (Marc-Andre Lafortune) wrote:
> One example is RSpec's `let`:

I guess we'll have to disagree on that one, I think the code below should return from the surrounding method/file.

> ```
>   RSpec.describe Something do
>     let(:foo) { return 42 }
>   end
> ```

> It is 100% clear what is meant and there are gazillions `let` blocks in the wild. This is just one example.

I would think very few `let` use `return` though, do you have a real world example?

> This would be a compatibility nightmare, for a gain I can not see (here simply raising an error).

If we do the approach where we just wrap the non-lambda Proc in a lambda automatically it would be compatible for that case.

----------------------------------------
Feature #16499: define_method(non_lambda) should not the semantics of the given Proc
https://bugs.ruby-lang.org/issues/16499#change-83798

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38

But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different).

This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent.
It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change.

We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically,
just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`.
But it would also preserve `arity`, `parameters`, etc.
Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently.

My point is we shall never change the semantics of `return`/`break` somewhere in the code.
It should always mean exactly one thing.
`define_method(name) { literal block }` is fine with that rule, it always behave as a lambda.
But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly.

I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not.

OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons.
We should look at those reasons and provide better alternatives.

I think sometimes people want to know how many arguments a non-lambda Proc takes.
For example, `proc { |a,b=1| }`.
`proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments.
They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value.
`lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

Maybe we should return the same as for a lambda for `non_lambda.parameters`?
`Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them.

cc @zverok



-- 
https://bugs.ruby-lang.org/

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

* [ruby-core:96804] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc
       [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2020-01-12 16:19 ` [ruby-core:96803] " eregontp
@ 2020-01-12 16:24 ` eregontp
  2020-01-12 16:27 ` [ruby-core:96805] " eregontp
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: eregontp @ 2020-01-12 16:24 UTC (permalink / raw)
  To: ruby-core

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


zverok (Victor Shepelev) wrote:
> I believe curent behavior is pretty consistent, as it describes what it would realy accept.

Yes, in that regard it's inconsistent.
It might be impractical though, depending on whether you want something that reflects what the user writes (i.e., I'd argue always unexpected for the user to be called with 0 arguments) or how many arguments the method accepts.

But anyway `Proc#arity` is clearly inconsistent with `parameters`:
```ruby
> proc { |a,b=1| }.arity
=> 1 # => should be -1, accepts any amount of arguments
> lambda { |a,b=1| }.arity
=> -2

In contrast to:
> proc { |*rest| }.arity
=> -1 # OK
> lambda { |*rest| }.arity
=> -1 # OK
```

And I'd argue `Proc#arity` is what should be used to know how many arguments are required and allowed, not `Proc#parameters`.

----------------------------------------
Feature #16499: define_method(non_lambda) should not the semantics of the given Proc
https://bugs.ruby-lang.org/issues/16499#change-83799

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38

But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different).

This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent.
It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change.

We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically,
just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`.
But it would also preserve `arity`, `parameters`, etc.
Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently.

My point is we shall never change the semantics of `return`/`break` somewhere in the code.
It should always mean exactly one thing.
`define_method(name) { literal block }` is fine with that rule, it always behave as a lambda.
But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly.

I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not.

OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons.
We should look at those reasons and provide better alternatives.

I think sometimes people want to know how many arguments a non-lambda Proc takes.
For example, `proc { |a,b=1| }`.
`proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments.
They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value.
`lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

Maybe we should return the same as for a lambda for `non_lambda.parameters`?
`Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them.

cc @zverok



-- 
https://bugs.ruby-lang.org/

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

* [ruby-core:96805] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc
       [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2020-01-12 16:24 ` [ruby-core:96804] " eregontp
@ 2020-01-12 16:27 ` eregontp
  2020-01-16  8:18 ` [ruby-core:96901] [Ruby master Feature#16499] define_method(non_lambda) should not change " matz
  2020-01-16  9:57 ` [ruby-core:96908] " larskanis
  7 siblings, 0 replies; 8+ messages in thread
From: eregontp @ 2020-01-12 16:27 UTC (permalink / raw)
  To: ruby-core

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


Eregon (Benoit Daloze) wrote:
> If we do the approach where we just wrap the non-lambda Proc in a lambda automatically it would be compatible for that case.

I'm tired, that's wrong, it would actually return from the file, just like any other non-lambda block.
That would be consistent, but yet it would be compatible for those cases with `return` inside a `block` given to `define_method` later on.
I think those cases are very rare though.


----------------------------------------
Feature #16499: define_method(non_lambda) should not the semantics of the given Proc
https://bugs.ruby-lang.org/issues/16499#change-83800

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38

But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different).

This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent.
It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change.

We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically,
just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`.
But it would also preserve `arity`, `parameters`, etc.
Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently.

My point is we shall never change the semantics of `return`/`break` somewhere in the code.
It should always mean exactly one thing.
`define_method(name) { literal block }` is fine with that rule, it always behave as a lambda.
But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly.

I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not.

OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons.
We should look at those reasons and provide better alternatives.

I think sometimes people want to know how many arguments a non-lambda Proc takes.
For example, `proc { |a,b=1| }`.
`proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments.
They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value.
`lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

Maybe we should return the same as for a lambda for `non_lambda.parameters`?
`Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them.

cc @zverok



-- 
https://bugs.ruby-lang.org/

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

* [ruby-core:96901] [Ruby master Feature#16499] define_method(non_lambda) should not change the semantics of the given Proc
       [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2020-01-12 16:27 ` [ruby-core:96805] " eregontp
@ 2020-01-16  8:18 ` matz
  2020-01-16  9:57 ` [ruby-core:96908] " larskanis
  7 siblings, 0 replies; 8+ messages in thread
From: matz @ 2020-01-16  8:18 UTC (permalink / raw)
  To: ruby-core

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

Status changed from Open to Rejected

There could be enormous code breakages by the proposed change. The compatibility is more important than slightly better consistency.

Matz.


----------------------------------------
Feature #16499: define_method(non_lambda) should not change the semantics of the given Proc
https://bugs.ruby-lang.org/issues/16499#change-83918

* Author: Eregon (Benoit Daloze)
* Status: Rejected
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38

But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different).

This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent.
It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change.

We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically,
just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`.
But it would also preserve `arity`, `parameters`, etc.
Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently.

My point is we shall never change the semantics of `return`/`break` somewhere in the code.
It should always mean exactly one thing.
`define_method(name) { literal block }` is fine with that rule, it always behave as a lambda.
But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly.

I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not.

OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons.
We should look at those reasons and provide better alternatives.

I think sometimes people want to know how many arguments a non-lambda Proc takes.
For example, `proc { |a,b=1| }`.
`proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments.
They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value.
`lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

Maybe we should return the same as for a lambda for `non_lambda.parameters`?
`Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them.

cc @zverok



-- 
https://bugs.ruby-lang.org/

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

* [ruby-core:96908] [Ruby master Feature#16499] define_method(non_lambda) should not change the semantics of the given Proc
       [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
                   ` (6 preceding siblings ...)
  2020-01-16  8:18 ` [ruby-core:96901] [Ruby master Feature#16499] define_method(non_lambda) should not change " matz
@ 2020-01-16  9:57 ` larskanis
  7 siblings, 0 replies; 8+ messages in thread
From: larskanis @ 2020-01-16  9:57 UTC (permalink / raw)
  To: ruby-core

Issue #16499 has been updated by larskanis (Lars Kanis).


Unfortunately `define_method` is currently the only way to retrieve `Proc#parameters` without information loss. See #15357 and [here](https://github.com/larskanis/eventbox/blob/3bcbc30096c6003e96d41c6496c781dfc90ac36a/lib/eventbox/argument_wrapper.rb#L10-L17) for the workaround per `default_method`. Therefore fixing `default_method` would also require fixing `Proc#parameters`.

----------------------------------------
Feature #16499: define_method(non_lambda) should not change the semantics of the given Proc
https://bugs.ruby-lang.org/issues/16499#change-83926

* Author: Eregon (Benoit Daloze)
* Status: Rejected
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
From https://bugs.ruby-lang.org/issues/15973?next_issue_id=15948&prev_issue_id=15975#note-38

But I think we should change `define_method(&non_lambda)` because that currently confusingly treats the same block body differently (e.g., the same `return` in the code means something different).

This is the only construct in Ruby that can change a non-lambda to a lambda, and it's very inconsistent.
It also forces implementations to have a way to convert a proc to a lambda, which is a non-trivial change.

We could maybe make `define_method(name, non_lambda)` just wrap the Proc in a lambda, automatically,
just like we can do manually with: `define_method(name, -> *args { non_lambda.call(*args) })`.
But it would also preserve `arity`, `parameters`, etc.
Then it wouldn't be any more verbose, but it would avoid the problem of treating the same `return`/`break` in the code differently.

My point is we shall never change the semantics of `return`/`break` somewhere in the code.
It should always mean exactly one thing.
`define_method(name) { literal block }` is fine with that rule, it always behave as a lambda.
But `define_method(&non_lambda)` is problematic as `non_lambda` can be passed to other methods or called directly.

I believe exactly 0 people want `foo { return 42 }` to change its meaning based on whether `foo` calls `define_method` or not.

OTOH, it seems people have repeatedly wanted to convert a proc to a lambda, but for other reasons.
We should look at those reasons and provide better alternatives.

I think sometimes people want to know how many arguments a non-lambda Proc takes.
For example, `proc { |a,b=1| }`.
`proc.arity` gives `1` here which might be helpful but also surprising as that Proc accepts any number of arguments.
They might also look at `proc.parameters` which gives `[[:opt, :a], [:opt, :b]]` which does not differentiate `a` and `b` even though only `b` has a proper default value.
`lambda { |a,b=1| }.parameters` returns the more useful `[[:req, :a], [:opt, :b]]`.

Maybe we should return the same as for a lambda for `non_lambda.parameters`?
`Proc#lambda?` would still tell whether it's strict about arguments and whether it deconstructs them.

cc @zverok



-- 
https://bugs.ruby-lang.org/

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

end of thread, other threads:[~2020-01-16  9:57 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <redmine.issue-16499.20200110223629@ruby-lang.org>
2020-01-10 22:36 ` [ruby-core:96768] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc eregontp
2020-01-11 22:44 ` [ruby-core:96793] " ruby-core
2020-01-12 14:20 ` [ruby-core:96802] " zverok.offline
2020-01-12 16:19 ` [ruby-core:96803] " eregontp
2020-01-12 16:24 ` [ruby-core:96804] " eregontp
2020-01-12 16:27 ` [ruby-core:96805] " eregontp
2020-01-16  8:18 ` [ruby-core:96901] [Ruby master Feature#16499] define_method(non_lambda) should not change " matz
2020-01-16  9:57 ` [ruby-core:96908] " larskanis

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 read-only IMAP folder(s) and NNTP newsgroup(s).