ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: jzakiya@gmail.com
To: ruby-core@ruby-lang.org
Subject: [ruby-core:101789] [Ruby master Feature#17474] Interpreting constants at compile time
Date: Mon, 28 Dec 2020 18:30:05 +0000 (UTC)	[thread overview]
Message-ID: <redmine.journal-89617.20201228183004.11075@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-17474.20201226163651.11075@ruby-lang.org

Issue #17474 has been updated by jzakiya (Jabari Zakiya).


Your example:

```
def m(i)
  $("foo#{i}")
end
```

**_would not_** work because it doesn't evaluate at parse-time to a constant value. It requires a runtime parameter ``i``, thus it can't evaluate to a constant value/object it can be substituted with. This example should throw an error.

> Overall, it feels un-Ruby to me. It's a manual low-level optimization hack, just to avoid the need to name a constant.

Matz keeps saying Ruby has to advance to keep relevant. Ruby has made allot of additions to the language recently to do that, some still experimental, some not fully/efficiently implemented yet.

IMHO, this ``feature`` falls in line with recent additions, e.g. ``endless`` methods, ``infinite ranges: (1..).each``, and ``Ractors``.  They were all proposed, and eventually included, to make Ruby easier/better for users. This proposed ``feature/capability`` exists, in some form, in other languages besides Forth, where it originated.


I appreciate others see the potential utility of this feature, and once an implementation has been created, we can then empirically evaluate its impact (on all levels), and see and measure them directly. I'm sure this will allow code to create faster runtimes, which is a major goal for Ruby 3 over its ancestors.

Now users can develop code faster/easier and maintain showing the details of the code developments without performance hits, and can tell the parser which expressions to evaluate at parse-time, and substitute in place to use at runtime. This is much easier/efficient than doing a postcode analysis to see which expressions could be extracted into constant runtime ``values/objects`` (which is rarely done), while maintaining source code brevity and conciseness.



----------------------------------------
Feature #17474: Interpreting constants at compile time
https://bugs.ruby-lang.org/issues/17474#change-89617

* 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/

  parent reply	other threads:[~2020-12-28 18:30 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-26 16:36 [ruby-core:101719] [Ruby master Feature#17474] Interpreting constants at compile time jzakiya
2020-12-26 21:40 ` [ruby-core:101722] " chris
2020-12-27  2:36 ` [ruby-core:101725] " jzakiya
2020-12-27  2:39 ` [ruby-core:101726] " chris
2020-12-27  3:08 ` [ruby-core:101727] " jzakiya
2020-12-27  3:17 ` [ruby-core:101728] " chris
2020-12-27  3:41 ` [ruby-core:101729] " jzakiya
2020-12-27 13:44 ` [ruby-core:101743] " jzakiya
2020-12-27 16:08 ` [ruby-core:101746] " eregontp
2020-12-27 22:28 ` [ruby-core:101759] " marcandre-ruby-core
2020-12-27 22:29 ` [ruby-core:101760] " marcandre-ruby-core
2020-12-28  2:22 ` [ruby-core:101765] " daniel
2020-12-28  4:57 ` [ruby-core:101768] " nobu
2020-12-28 12:32 ` [ruby-core:101776] " eregontp
2020-12-28 16:48 ` [ruby-core:101786] " daniel
2020-12-28 16:52 ` [ruby-core:101787] " chris
2020-12-28 18:30 ` jzakiya [this message]
2021-01-04  2:50 ` [ruby-core:101899] " daniel
2021-01-04 12:37 ` [ruby-core:101910] " eregontp
2021-01-04 13:18 ` [ruby-core:101911] " chris
2021-01-04 16:47 ` [ruby-core:101914] " daniel
2021-01-07 13:36 ` [ruby-core:101974] " eregontp
2021-01-07 16:40 ` [ruby-core:101976] " shevegen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-89617.20201228183004.11075@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).