From: zverok.offline@... Date: 2019-12-19T09:24:00+00:00 Subject: [ruby-core:96328] [Ruby master Misc#16260] Symbol#to_proc behaves like lambda, but doesn't aknowledge it Issue #16260 has been updated by zverok (Victor Shepelev). > As a symbol proc cannot know the method to be invoked, so now I think it cannot be lambda. > In the case `:+`, it looks like a lambda, but it is **not always true.** @nobu, I am not sure I get it right. Can you please show when it is not true?.. For as far as I can understand, there are two distinctions of lambda: 1. Its `return` returns from lambda itself, not enclosing scope 2. It treats parameters strictly, without implicit unpacking/optionality Now, `:+.to_proc` behaves this way: ```ruby PLUS = :+.to_proc PLUS.call(1, 2) # => 3 PLUS.call([1, 2]) # ArgumentError (wrong number of arguments (given 0, expected 1)) # Tried to call [1, 2].+(), not 1.+(2), so no unpacking ``` Whilst lambda would behave this way: ```ruby PLUS_L = lambda { |obj, *rest| obj.send(:+, *rest) } PLUS_L.call(1, 2) # => 3 PLUS_L.call([1, 2]) # ArgumentError (wrong number of arguments (given 0, expected 1)) # Explicit return: lambda { |obj, *rest| return obj.send(:+, *rest) }.call(1, 2) # => 3 ``` ....and proc will behave this way: ```ruby PLUS_P = lambda { |obj, *rest| obj.send(:+, *rest) } PLUS_P.call(1, 2) # => 3 PLUS_P.call([1, 2]) # => 3 # Implicit unpacking # Explicit return: proc { |obj, *rest| return obj.send(:+, *rest) }.call(1, 2) # --- returns from the enclosing scope ``` So, `:.to_proc` behaves *exactly* like lambda, and *nothing* like proc. The only thing that differs from the equivalent lambda is... ```ruby PLUS.parameters # => [[:rest]] PLUS_L.parameters # => [[:req, :obj], [:rest, :rest]] ``` (which is ideally to be fixed too, as in fact the first parameter is indeed mandatory.) Can you please show me the case when `:.to_proc` does NOT behave like lambda?.. > Just curious: How do you want to use the result of `lambda?`? @mame For explanatory and educational purposes, at least. For example, in [this article](https://zverok.github.io/blog/2019-10-18-each_with_object.html), I am showing some funny examples, and to explain why this works: ```ruby [1, 2, 3].zip([4, 4, 4]).map { |a, b| a + b } ``` ...and this not: ```ruby [1, 2, 3].zip([4, 4, 4]).map(&:+) ``` ...I'd like to just say "because `:+.to_proc` is a lambda, as you can see", but what I really need to say is "becuase `:+.to_proc` doesn't unpacks arguments, behaving like lambda... though it doesn't aknowledge it is"". So, yep, debugging, explaining, teaching, this kind of things. ---------------------------------------- Misc #16260: Symbol#to_proc behaves like lambda, but doesn't aknowledge it https://bugs.ruby-lang.org/issues/16260#change-83240 * Author: zverok (Victor Shepelev) * Status: Rejected * Priority: Normal * Assignee: ---------------------------------------- Seems that `Symbol#to_proc` returns `Proc` that has lambda semantics: ```ruby proc = :+.to_proc proc.call(1, 2) # => 3 proc.call([1, 2]) # ArgumentError (wrong number of arguments (given 0, expected 1)) ``` But if you ask... ```ruby proc.lambda? # => false ``` That seems to be an inconsistency, which I'd like to clarify. There are obviously two ways to fix it: 1. Make it respond `true` to `lambda?` (and mention the semantics in docs) 2. Make it behave like non-lambda. The second one seems to produce some useful behavior: ```ruby # Currently: [1, 2].zip([3, 4]).map(&:+) # ArgumentError (wrong number of arguments (given 0, expected 1)) # With non-lambda: class Symbol def to_proc proc { |o, *a| o.send(self, *a) } end end [1, 2].zip([3, 4]).map(&:+) # => [4, 6] ``` Probably all of it was discussed when `Symbol#to_proc` was introduced, but as old NEWS-files doesn't link to tickets/discussions, I can't find the reasoning for current behavior. -- https://bugs.ruby-lang.org/ Unsubscribe: