Details
-
New Feature
-
Status: Open
-
Minor
-
Resolution: Unresolved
-
None
-
None
-
None
Description
I have been poking around with the many ways to extend a class/object's functionality within groovy. To add a new method that can be called like any other instance method, there are a few possibilities:
1. modify the MetaClass
String.metaClass.ext = { -> print delegate } "works".ext()
2. use a category class
@Category(String) class Cat { void ext() { println this } } use (Cat) { "works".ext() }
3. apply a mixin
first create class similar to Cat in (2)
def str = "works"; str.metaClass.mixin(Cat) str.ext()
4. apply a trait
trait Ext { void ext() { println this.toLowerCase() } // see GROOVY-11142 } "works".withTraits(Ext).ext()
5. create an extension moodule
- create class similar to Cat in (2)
- create META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule file
- build and deploy separately from current script / project
What I'm after is something that works as easily in a script or source file as static imports but lets me call like an extension method. And does not modify state outside of the current script (like MetaClass) or introduce a thread barrier (like use). And works with static type checking.
Scala has an "extension" mechanism that is similar to static import but there is a keyword on the category class that lets compiler know the method is used like any other instance method. Scala used to provide "implicit" methods – I've lost my familiarity with those.
I've seen "import static extension foo.Bar.baz;" for some language. (citation required)
And lastly, Kotlin provides a local extension like this:
fun foo.Bar.baz() { x ->
// ...
}
For any new users or just to add something quickly that can be used in a file, I think I'm looking for an enhancement to "import static ..." that will get substituted in the source unit, like StaticImportVisitor does today for static method calls. For example:
import static foo.Bar.baz import static /*something*/ foo.Bar.baz baz("") // supported by first import "".baz() // supported by second import
I have been considering whether "extension", "default", some annotation or something else should be used for /*something*/ in the script above.
Similar to Kotlin, this could let someone declare an extension in a single script with no dynamic runtime impact:
import static /*something*/ ThisScript.* static ext(String self) { print self } "works".ext()
Has anyone looked at something like this in Groovy or other languages and has some feedback?
Attachments
Issue Links
- is related to
-
GROOVY-2521 keyword 'use' like 'import (static)' to use categories in a complete compilation unit
- Open
-
GROOVY-8417 Add @UseCategory annotation for classes/methods instead of use() everywhere
- Open
-
GROOVY-3387 Add @Use Annotation
- Closed
- relates to
-
GROOVY-11161 Support extension methods inside the same compilation unit
- Open