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-Status: No, score=-3.8 required=3.0 tests=AWL,BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY shortcircuit=no autolearn=ham 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 D89DF1F4B4 for ; Mon, 4 Jan 2021 16:47:41 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 5C0C2120AFE; Tue, 5 Jan 2021 01:46:47 +0900 (JST) Received: from xtrwkhkc.outbound-mail.sendgrid.net (xtrwkhkc.outbound-mail.sendgrid.net [167.89.16.28]) by neon.ruby-lang.org (Postfix) with ESMTPS id A6D87120A8F for ; Tue, 5 Jan 2021 01:46:44 +0900 (JST) Received: by filterdrecv-p3iad2-74bd9fb996-hwg5g with SMTP id filterdrecv-p3iad2-74bd9fb996-hwg5g-19-5FF3469E-45 2021-01-04 16:47:26.751394441 +0000 UTC m=+2137516.211845358 Received: from herokuapp.com (unknown) by ismtpd0044p1mdw1.sendgrid.net (SG) with ESMTP id cvqlz2J7R66ZbB41Now9YA for ; Mon, 04 Jan 2021 16:47:26.641 +0000 (UTC) Date: Mon, 04 Jan 2021 16:47:26 +0000 (UTC) From: daniel@dan42.com Message-ID: References: Mime-Version: 1.0 X-Redmine-MailingListIntegration-Message-Ids: 77821 X-Redmine-Project: ruby-master X-Redmine-Issue-Tracker: Feature X-Redmine-Issue-Id: 17474 X-Redmine-Issue-Author: jzakiya X-Redmine-Sender: Dan0042 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?8sy4RigFvRTdBfCVJrT9zb2J88PC92TMQwdNgaWYaq4f+8vkZ0mo00WcjXucya?= =?us-ascii?Q?6tL5rN+S0+kSU6F1BPb+aEo3VeXNUUg3=2FPhhfjK?= =?us-ascii?Q?uLRdXChsZlDY8B5m7TjK0Ry3cpJqyoacRBDa3vY?= =?us-ascii?Q?jBFvz6Ck6RWsct83rxXHs62RI832OcYKPMfjfqH?= =?us-ascii?Q?vJcrzinFEpeIRYrM8dbi=2Fwbuuu3GjgmGNuCczsC?= =?us-ascii?Q?XFnga6wkPwNzaSS=2Fs=3D?= To: ruby-core@ruby-lang.org X-Entity-ID: b/2+PoftWZ6GuOu3b0IycA== X-ML-Name: ruby-core X-Mail-Count: 101914 Subject: [ruby-core:101914] [Ruby master Feature#17474] Interpreting constants at compile time 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 #17474 has been updated by Dan0042 (Daniel DeLorme). Eregon (Benoit Daloze) wrote in #note-19: > It's not possible to evaluate any Ruby code except literals at parse time, as I already said in https://bugs.ruby-lang.org/issues/17474#note-8. It's completely possible for ruby to just eval that special expression separately from the rest of the file. It would be somewhat equivalent to `TOPLEVEL_BINDING.eval`. It could eval either while parsing, or after the current file has parsed and evaled. And of course, while jzakiya intends for a "parse time" expression, that doesn't exclude the possibility of "first time" which has slightly different but still very close semantics. > Constants are a thousand times clearer, and simpler. Except when they're not... it depends on the code, on the situation. chrisseaton (Chris Seaton) wrote in #note-20: > Another point to consider - does this have an impact on our ability to use optimisations such as lazy parsing and do you know how you would precisely specify the semantics of when the expression is executed in relation to other events? Going with "first time" semantics this would not be an issue, but going with "parse time" semantics I think it would make sense to say that precisely "when" the expression is executed is undefined. So in the case of lazy parsing it would be parsed and evaled when the containing code is parsed, whenever that is. ---------------------------------------- Feature #17474: Interpreting constants at compile time https://bugs.ruby-lang.org/issues/17474#change-89757 * Author: jzakiya (Jabari Zakiya) * Status: Open * Priority: Normal ---------------------------------------- Ruby has borrowed concepts/idioms from allot of languages. I am proposing borrowing a feature from Forth to provide for compile time interpretation of Constants. This should make executed code faster|efficient, while maintaining source code brevity|clarity. Below is actual code used in a large rubygem I have. To develop this method, I had to do allot of test runs to determine the range values. Once found, these values don't change, but I just kept the computed forms of the values, in case I want to upgrade them. In Forth I can interpret those expressions that result in constants, which will be compiled as single values for run time. See wikeipedia article on Forth below starting at **Mixing states of compiling and interpreting**. https://en.wikipedia.org/wiki/Forth_(programming_language) Forth was designed for, and is still used most frequently, in hardware controllers, and with microprocessors. IMHO this feature would also make MRuby more code efficient and faster for this domain too, and IOT devices. Below is an example of real code that would benefit from this. While this example would result in numerical constant, string constants could also be interpreted. ``` def select_pg(endnum, startnum) start_num = end_num end_num = endnum; start_num = startnum range = end_num - start_num pg = 5 if start_num <= Integer.sqrt(end_num) # for one array of primes upto N pg = 7 if end_num > 50 * 10**4 pg = 11 if end_num > 305 * 10**5 else # for split array cases pg = 7 if ((10**6 ... 10**7).include?(range) && start_num < 10**8) || ((10**7 ... 10**8).include?(range) && start_num < 46 * 10**8) || ((10**8 ... 10**9).include?(range) && start_num < 16 * 10**10) || (range >= 10**9 && start_num < 26 * 10**12) pg = 11 if ((10**8 ... 10**9).include?(range) && start_num < 55 * 10**7) || (range >= 10**9 && start_num < 45 * 10**9) end primes = [2, 3, 5, 7, 11, 13].select { |p| p <= pg } {primes, primes.reduce(:*)} # [excluded primes, modpg] for PG end ``` Allowing for compile time interpretation, the code could be rewritten as below. ``` def select_pg(endnum, startnum) start_num = end_num end_num = endnum; start_num = startnum range = end_num - start_num pg = 5 if start_num <= Integer.sqrt(end_num) # for one array of primes upto N pg = 7 if end_num > [50 * 10**4] pg = 11 if end_num > [305 * 10**5] else # for split array cases pg = 7 if (([10**6] ... [10**7]).include?(range) && start_num < [10**8]) || (([10**7] ... [10**8]).include?(range) && start_num < [46 * 10**8]) || (([10**8] ... [10**9]).include?(range) && start_num < [16 * 10**10])|| (range >= [10**9] && start_num < [26 * 10**12]) pg = 11 if (([10**8] ... [10**9]).include?(range) && start_num < [55 * 10**7]) || (range >= [10**9] && start_num < [45 * 10**9]) end primes = [2, 3, 5, 7, 11, 13].select { |p| p <= pg } {primes, primes.reduce(:*)} # [excluded primes, modpg] for PG end ``` This maintains the original form, so if I need/want to change the range limits again I can just change the calculation inline, without having to remember where those values came from. As 3.0 has introduced many new features and idioms, this could be introduced with no breaking change too. Old code would work as before, while new code could take advantage of this feature. Thanks is advance of giving this proposal serious consideration. -- https://bugs.ruby-lang.org/