[ https://issues.apache.org/jira/browse/GROOVY-11059?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17723831#comment-17723831 ]
Jim Klimov edited comment on GROOVY-11059 at 5/18/23 8:07 AM: -------------------------------------------------------------- Regarding comparisons, I think currently the {{isCase()}} is also loosely useful, given that it would have to be defined in (or hacked into) third-party classes to compare with our custom classes. I mean use-cases like: {code:java} MyClass val = ... // implements equals() and/or compareTo() which do work for strings/numbers/... when called directly switch (val) { case "SomeString": // needs a String.asType() implementation, code in MyClass is not called case 0: // needs a Integer(?).asType() implementation, code in MyClass is not called }{code} One simple case I had in mind was a class to wrap the return value of a "sh" step in Jenkins (calling an external shell program) which may return an exit-code and/or stdout of that program (further code jumps through hoops to collect both). My custom class has fields to store either (or both), and its comparison/equality methods check against one or the other depending on the counterpart data type (numbers to exit-codes, strings to stdout). Original code in the pipelines used {{def res = sh (...)}} so the {{res}} ended up as an {{Integer}} or {{String}} depending on parameters of {{sh()}} and comparisons, switch/case, "in [some, list]" etc. operations were easy. With a wrapper that makes-believe it is a string or integer depending on context it is... not really sure if possible currently? (I mean, direct field comparisons like {{if (newRes.status in [1, 2, 3])}} or {{switch(newRes.getStdout())...}} are surely possible, but would require changes across the board so are not an "easy" fix, and would make the consumer code more intimately tied to the data type used) was (Author: JIRAUSER300415): Regarding comparisons, I think currently the {{isCase()}} is also loosely useful, given that it would have to be defined in (or hacked into) third-party classes to compare with our custom classes. I mean use-cases like: {code:java} MyClass val = ... // implements equals() and/or compareTo() which do work for strings/numbers/... when called directly switch (val) { case "SomeString": // needs a String.asType() implementation, code in MyClass is not called case 0: // needs a Integer(?).asType() implementation, code in MyClass is not called }{code} One simple case I had in mind was a class to wrap the return value of a "sh" step in Jenkins (calling an external shell program) which may return an exit-code and/or stdout of that program (further code jumps through hoops to collect both). My custom class has fields to store either (or both), and its comparison/equality methods check against one or the other depending on the counterpart data type (numbers to exit-codes, strings to stdout). Original code in the pipelines used {{def res = sh (...)}} so the {{res}} ended up as an {{Integer}} or {{String}} depending on parameters of {{sh()}} and comparisons, switch/case, "in [some, list]" etc. operations were easy. With a wrapper that makes-believe it is a string or integer depending on context it is... not really sure if possible currently? (I mean, direct comparisons like {{newRes.status in [1, 2, 3]}} or {{switch(newRes.getStdout())...}} are surely possible, but would require changes across the board so are not an "easy" fix, and would make the consumer code more intimately tied to the data type used) > Want a way to define casting/coercing FROM other classes as part of my class > ---------------------------------------------------------------------------- > > Key: GROOVY-11059 > URL: https://issues.apache.org/jira/browse/GROOVY-11059 > Project: Groovy > Issue Type: Wish > Reporter: Jim Klimov > Priority: Major > > Java has basic casting which relies on one object having a class/interface > which is descendant of another in the equation. Groovy extends this with > coercion which relies on the origin class defining an {{asType()}} method to > state how convert it into an instance of a target class. > For example, if I want to assign my class from a standard {{String}} I'd have > to hack with metaclass of String to extend its {{asType}} to recognize > {{MyClass}} and coerce INTO it, and then I'd be able to say: > {code:java} > MyClass myval = "SomeString" as MyClass{code} > This is clumsy both on implementation side (hacking into other people's code > is not too portable, and has complications with code that runs this hack many > times like a Jenkins Shared Library that would change server JVM's String > over and over for each run), and on coding side (while "as SomeClass" is > explicit, someone has to write it which adds noise in refactorings and goes > against the type simplicity trend of the language). > My proposal is to support a common optional method everywhere, in the > groovyish manner of plastering so many other optional operator overloads like > {{{}asType(){}}}, {{{}isCase(){}}}, {{plus()}} et al, which would be > effectively an inverse {{asType()}} and overload the assignment operator. > By default it could invoke single-parameter constructors (e.g. if I define a > {{MyClass(String)}} one - that can be used to cast the assignment from a > {{{}String{}}}), and it might be extensible if someone has more complex ideas > for their class (e.g. change something in the existing instance instead of > creating a new one, if the override is non-static, or if it generally gets a > parameter with an instance of this class and this parameter is null or not). > Either way, for script writers it would be just a simple assignment symbol > with smarts behind the curtain. > Possibly this might fill in the gap of current {{equals()}} overload that did > not always work well for me (possibly due to ancient groovy in Jenkins core) > to check {{{}if (myClassVal == "somestring") {...{}}}} -- This message was sent by Atlassian Jira (v8.20.10#820010)