ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
@ 2023-12-27  3:27 tagomoris (Satoshi Tagomori) via ruby-core
  2023-12-27  3:43 ` [ruby-core:115920] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: tagomoris (Satoshi Tagomori) via ruby-core @ 2023-12-27  3:27 UTC (permalink / raw
  To: ruby-core; +Cc: tagomoris (Satoshi Tagomori)

Issue #20093 has been reported by tagomoris (Satoshi Tagomori).

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115920] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
@ 2023-12-27  3:43 ` kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  2023-12-27  3:44 ` [ruby-core:115921] " Dan0042 (Daniel DeLorme) via ruby-core
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core @ 2023-12-27  3:43 UTC (permalink / raw
  To: ruby-core; +Cc: kjtsanaktsidis (KJ Tsanaktsidis)

Issue #20093 has been updated by kjtsanaktsidis (KJ Tsanaktsidis).


Would `class extension` just be syntax sugar for this:

```
String.class_eval do
    def exclude?(string) = !include?(string)
end
```

or would it behave differently in some way?

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105876

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115921] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
  2023-12-27  3:43 ` [ruby-core:115920] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
@ 2023-12-27  3:44 ` Dan0042 (Daniel DeLorme) via ruby-core
  2023-12-27  4:00 ` [ruby-core:115922] " rubyFeedback (robert heiler) via ruby-core
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Dan0042 (Daniel DeLorme) via ruby-core @ 2023-12-27  3:44 UTC (permalink / raw
  To: ruby-core; +Cc: Dan0042 (Daniel DeLorme)

Issue #20093 has been updated by Dan0042 (Daniel DeLorme).


I think what you're looking for is class_eval / module_eval

```ruby
String.class_eval do
  def exclude?(string)
    !include?(string)
  end
end
```

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105877

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115922] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
  2023-12-27  3:43 ` [ruby-core:115920] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  2023-12-27  3:44 ` [ruby-core:115921] " Dan0042 (Daniel DeLorme) via ruby-core
@ 2023-12-27  4:00 ` rubyFeedback (robert heiler) via ruby-core
  2023-12-27  6:11 ` [ruby-core:115926] " tagomoris (Satoshi Tagomori) via ruby-core
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: rubyFeedback (robert heiler) via ruby-core @ 2023-12-27  4:00 UTC (permalink / raw
  To: ruby-core; +Cc: rubyFeedback (robert heiler)

Issue #20093 has been updated by rubyFeedback (robert heiler).


Dan0042 wrote:

> I think what you're looking for is class_eval / module_eval

I am not entirely certain tagomoris meant to use **.class_eval** here.

See his alternative suggestion of "reopen".

Of course I may be wrong, but if I understood it correctly his issue
request may be more related towards being able to extend something in
ruby no matter if it is a class or a module or already-defined versus
yet-to-be-defined; a bit like a "promise" of functionality, not unlike
refinements make isolated modifications to existing classes/code.

E. g.:

    class extension String
    class reopen String
    reopen String # just as an example to drop the class/module name altogether and may be shorter

In particular in the last case, I have had use cases to want to **avoid** having to type either "class" or "module" altogether. I also agree with the use case of refinements, by the way, but
I always felt the syntax awkward. This is also one slight problem I have here, in that I think
"class foobar String" is too verbose - and it may also be a bit confusing for ruby users. But I
think tagomoris has a point as well - the intention should be for a ruby developer to "modify behaviour xyz". As stated, I may be mistaken, so perhaps tagomoris can refer to the .class_eval example. We should ideally come up with a useful syntax, though - being an elegant language is
one of ruby's strong points, even if what is elegant differs between individuals naturally.

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105878

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115926] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
                   ` (2 preceding siblings ...)
  2023-12-27  4:00 ` [ruby-core:115922] " rubyFeedback (robert heiler) via ruby-core
@ 2023-12-27  6:11 ` tagomoris (Satoshi Tagomori) via ruby-core
  2023-12-27 12:59 ` [ruby-core:115934] " Edwing123 (Edwin Garcia) via ruby-core
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: tagomoris (Satoshi Tagomori) via ruby-core @ 2023-12-27  6:11 UTC (permalink / raw
  To: ruby-core; +Cc: tagomoris (Satoshi Tagomori)

Issue #20093 has been updated by tagomoris (Satoshi Tagomori).


Thank you for your feedback. Yes, `class_eval` / `module_eval` can do the same things functionally. `class extension String` could be a syntax sugar of `String.class_eval do ... end`.
I think it's reasonable to have such a syntax sugar because we're using `class Foo; ...; end` instead of `(Foo = Class.new).class_eval do ... end`.
I never want to recommend someone to use `class_eval` for monkey patching.

As pointed out above, I want to have the more simple keyword `reopen` or `extend`(oops, it's not good) for both class and module (e.g., `reopen String`). But adding top-level keywords is unrealistic. That's the reason I proposed a bit of verbose syntax.

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105879

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115934] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
                   ` (3 preceding siblings ...)
  2023-12-27  6:11 ` [ruby-core:115926] " tagomoris (Satoshi Tagomori) via ruby-core
@ 2023-12-27 12:59 ` Edwing123 (Edwin Garcia) via ruby-core
  2023-12-27 14:51 ` [ruby-core:115935] " zverok (Victor Shepelev) via ruby-core
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Edwing123 (Edwin Garcia) via ruby-core @ 2023-12-27 12:59 UTC (permalink / raw
  To: ruby-core; +Cc: Edwing123 (Edwin Garcia)

Issue #20093 has been updated by Edwing123 (Edwin Garcia).


If this feature has the purpose of making class/module extension explicit (meaning you can clearly see that a class/module is being open again to be extended), then I agree with it.

By the way, I think the keyword `open` is more suitable:

```ruby
class Foo
end

# Yay! Explicitly opening
# a class for extension.
open class Foo
 def bar()
 end
end
```

I like that we're being explicit, so with this when reading code, we can answer that the class/module is being open for extension and that its "canonical" definition is somewhere else.

Regarding backward compatibility:

- Should the `open` keyword be optional in order for existing code to keep working?

If that's the case, then existing  code that doesn't use `open` won't benefit from this:

> Raise errors if the specified class/module is not defined.

So, only code using `open` will opt into checking if the class/module being open is already defined.

I believe this is fine, and this proposal opens the door to adding a feature that will make reading Ruby code more clearly. Eventually gems and applications can adopt the new keyword!

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105885

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115935] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
                   ` (4 preceding siblings ...)
  2023-12-27 12:59 ` [ruby-core:115934] " Edwing123 (Edwin Garcia) via ruby-core
@ 2023-12-27 14:51 ` zverok (Victor Shepelev) via ruby-core
  2023-12-27 14:53 ` [ruby-core:115936] " Eregon (Benoit Daloze) via ruby-core
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: zverok (Victor Shepelev) via ruby-core @ 2023-12-27 14:51 UTC (permalink / raw
  To: ruby-core; +Cc: zverok (Victor Shepelev)

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


Just a side note: we actually have a term for "reopen existing class," and it is "refine."

So a bit of "turning the head around," this proposal might be rephrased as "default refinements" (ones that are always activated when some file is required), we might phrase it as just
```ruby
# written at the top-level
refine String do
  def exclude?(string)
    !include?(string)
  end
end
```

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105886

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115936] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
                   ` (5 preceding siblings ...)
  2023-12-27 14:51 ` [ruby-core:115935] " zverok (Victor Shepelev) via ruby-core
@ 2023-12-27 14:53 ` Eregon (Benoit Daloze) via ruby-core
  2023-12-29  1:11 ` [ruby-core:115972] " matheusrich (Matheus Richard) via ruby-core
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Eregon (Benoit Daloze) via ruby-core @ 2023-12-27 14:53 UTC (permalink / raw
  To: ruby-core; +Cc: Eregon (Benoit Daloze)

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


tagomoris (Satoshi Tagomori) wrote in #note-4:
> I never want to recommend someone to use `class_eval` for monkey patching.

Why not?
For clarity, I mean `class_eval` with a block so there are no syntax highlighting hurdles and no extra runtime parsing.
It is the existing way to be explicit this is reopening an existing class, and it fails clearly if the class was not defined before.
The only downside I see is that doesn't make it easy to define and access constants defined under that class/module.
A possibility in that case is to use `class_eval(String)`.

I guess the motivation for this proposal is #19744?

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105887

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115972] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
                   ` (6 preceding siblings ...)
  2023-12-27 14:53 ` [ruby-core:115936] " Eregon (Benoit Daloze) via ruby-core
@ 2023-12-29  1:11 ` matheusrich (Matheus Richard) via ruby-core
  2023-12-29  5:28 ` [ruby-core:115973] " tagomoris (Satoshi Tagomori) via ruby-core
  2023-12-29  5:50 ` [ruby-core:115974] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  9 siblings, 0 replies; 11+ messages in thread
From: matheusrich (Matheus Richard) via ruby-core @ 2023-12-29  1:11 UTC (permalink / raw
  To: ruby-core; +Cc: matheusrich (Matheus Richard)

Issue #20093 has been updated by matheusrich (Matheus Richard).


Why a new keyword? If it behaves like a `class_eval`, could it be an alias?

```rb
String.reopen do
  def stuff = here
end
```

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105935

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115973] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
                   ` (7 preceding siblings ...)
  2023-12-29  1:11 ` [ruby-core:115972] " matheusrich (Matheus Richard) via ruby-core
@ 2023-12-29  5:28 ` tagomoris (Satoshi Tagomori) via ruby-core
  2023-12-29  5:50 ` [ruby-core:115974] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  9 siblings, 0 replies; 11+ messages in thread
From: tagomoris (Satoshi Tagomori) via ruby-core @ 2023-12-29  5:28 UTC (permalink / raw
  To: ruby-core; +Cc: tagomoris (Satoshi Tagomori)

Issue #20093 has been updated by tagomoris (Satoshi Tagomori).


I commented that "class_eval / module_eval can do the same things functionally.". However, as @Eregon pointed out, there is a different rule about constants around `class_eval` / `module_eval`.
The method definition in `class_eval`/`module_eval` cannot refer to the class/module constants, and the block of `class_eval`/`module_eval` block cannot add/update the class/module constants. So, guiding people to use `class_eval` / `module_eval` instead of `class`/`module` for monkey patching should cause trouble and confusion.
For the same reason, @matheusrich 's idea (`Module#reopen` method) is not ideal in my opinion. Adding methods instead of a new keyword should be much easier, but it's not what I want.

The idea of top-level keywords, @Edwing123 's `open class` and @zverok 's `refine` look very hard to implement properly to me. `open class` conflicts with the existing `Kernel#open`. If `refine` is a method to take a block argument, it has the same problem with `class_eval`. If `refine` is a new top-level keyword (without following `do`), it will conflict with the `Module#refine` (Ruby core team members may be able to find any solution to avoid the conflict, though).

So, My idea is still to have a new keyword between `class`/`module` and the name of class/module: `class extension String`.

@Eregon It's true that this ticket's idea came up in an offline discussion about namespaces, but I thought this idea has its own value to be proposed as an independent feature, and I think it's (partially, at least) true because some people are making comments to agree with the intention.

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105936

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

* [ruby-core:115974] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
  2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
                   ` (8 preceding siblings ...)
  2023-12-29  5:28 ` [ruby-core:115973] " tagomoris (Satoshi Tagomori) via ruby-core
@ 2023-12-29  5:50 ` kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  9 siblings, 0 replies; 11+ messages in thread
From: kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core @ 2023-12-29  5:50 UTC (permalink / raw
  To: ruby-core; +Cc: kjtsanaktsidis (KJ Tsanaktsidis)

Issue #20093 has been updated by kjtsanaktsidis (KJ Tsanaktsidis).


> The only downside I see is that doesn't make it easy to define and access constants defined under that class/module.
> A possibility in that case is to use class_eval(String)

I actually found this quite surprising:

```
irb(main):008> String.class_eval { Module.nesting }
=> []
irb(main):009> String.class_eval "Module.nesting"
=> [String]
```

I get why the first one is empty (we're not inside a `class String ... end` block), but I find it surprising that the string form returns `String`.

----------------------------------------
Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules
https://bugs.ruby-lang.org/issues/20093#change-105937

* Author: tagomoris (Satoshi Tagomori)
* Status: Open
* Priority: Normal
----------------------------------------
`class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B.
But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called.

For example:

```ruby
# string_exclude.rb
class String
  def exclude?(string)
    !include?(string)
  end
end
```

This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below:

```ruby
load('string_exclude.rb', true)
```

This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user.

So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined.

```ruby
class extension String
  def exclude?(string)
    !include?(string)
  end
end # adds #exclude? to String class

class extension Stroooong
  def exclude?(string)
    !include?(string)
  end
end # will raise NameError (or something else)
```

Some additional things:

* `class extension String` (and `module extension String`)  causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name.
* I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`.




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

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

end of thread, other threads:[~2023-12-29  5:51 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-27  3:27 [ruby-core:115919] [Ruby master Feature#20093] Syntax or keyword to reopen existing classs/modules, never to define new classs/modules tagomoris (Satoshi Tagomori) via ruby-core
2023-12-27  3:43 ` [ruby-core:115920] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
2023-12-27  3:44 ` [ruby-core:115921] " Dan0042 (Daniel DeLorme) via ruby-core
2023-12-27  4:00 ` [ruby-core:115922] " rubyFeedback (robert heiler) via ruby-core
2023-12-27  6:11 ` [ruby-core:115926] " tagomoris (Satoshi Tagomori) via ruby-core
2023-12-27 12:59 ` [ruby-core:115934] " Edwing123 (Edwin Garcia) via ruby-core
2023-12-27 14:51 ` [ruby-core:115935] " zverok (Victor Shepelev) via ruby-core
2023-12-27 14:53 ` [ruby-core:115936] " Eregon (Benoit Daloze) via ruby-core
2023-12-29  1:11 ` [ruby-core:115972] " matheusrich (Matheus Richard) via ruby-core
2023-12-29  5:28 ` [ruby-core:115973] " tagomoris (Satoshi Tagomori) via ruby-core
2023-12-29  5:50 ` [ruby-core:115974] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core

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).