From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-2.7 required=3.0 tests=AWL,BAYES_00, DKIM_ADSP_CUSTOM_MED,FORGED_GMAIL_RCVD,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,SPF_HELO_NONE,SPF_PASS shortcircuit=no autolearn=no autolearn_force=no version=3.4.2 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id 739D11F885 for ; Fri, 10 Jan 2020 22:36:42 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 6B403120AB5; Sat, 11 Jan 2020 07:36:27 +0900 (JST) Received: from o1678948x4.outbound-mail.sendgrid.net (o1678948x4.outbound-mail.sendgrid.net [167.89.48.4]) by neon.ruby-lang.org (Postfix) with ESMTPS id E17A6120AAE for ; Sat, 11 Jan 2020 07:36:24 +0900 (JST) Received: by filterdrecv-p3iad2-57f487d66-lm2v9 with SMTP id filterdrecv-p3iad2-57f487d66-lm2v9-17-5E18FC6E-2 2020-01-10 22:36:30.086194348 +0000 UTC m=+2152190.869838973 Received: from herokuapp.com (unknown [54.166.107.205]) by ismtpd0012p1iad1.sendgrid.net (SG) with ESMTP id tjtks_9XR1u3EW1Q5Zh4QA for ; Fri, 10 Jan 2020 22:36:30.011 +0000 (UTC) Date: Fri, 10 Jan 2020 22:36:30 +0000 (UTC) From: eregontp@gmail.com Message-ID: References: Mime-Version: 1.0 X-Redmine-MailingListIntegration-Message-Ids: 72431 X-Redmine-Project: ruby-master X-Redmine-Issue-Id: 16499 X-Redmine-Issue-Author: Eregon X-Redmine-Sender: Eregon X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-SG-EID: =?us-ascii?Q?KippOI8ZHtTweq7XfQzW93937kJ4QNWwSBuHnaMEcr1WYVpQ8fEb4DaenY0HAw?= =?us-ascii?Q?GYhGCK34UqMdWnjWgGI8eaia=2FrpP1wsdsSb944X?= =?us-ascii?Q?TgQ7bpwWhKyW0vCG81AyQBMVFfNWQsDV5f43T4E?= =?us-ascii?Q?l=2F1eBWvOjx4R4vsRrK3frXeWGwRObg9t5OZoYap?= =?us-ascii?Q?eJtcpICnIsKYQMSj4wfmFY=2Fmu1wHjGoK01DhDtf?= =?us-ascii?Q?1Cck6rwUldHDjar5w=3D?= To: ruby-core@ruby-lang.org X-ML-Name: ruby-core X-Mail-Count: 96768 Subject: [ruby-core:96768] [Ruby master Feature#16499] define_method(non_lambda) should not the semantics of the given Proc X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ruby-core-bounces@ruby-lang.org Sender: "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/