[ 
https://issues.apache.org/jira/browse/GROOVY-7563?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14727716#comment-14727716
 ] 

Thibault Kruse commented on GROOVY-7563:
----------------------------------------

Okay, there are 4 distinct changes that I suggest to make. We can discuss for 
each whether they need to be provided with a new API, or can replace existing 
behavior without unduly breaking existing code.

h2. 1. toString(Range x)

The current state is this:
{code}
InvokerHelper.format(1..4, false) == 1..4
InvokerHelper.format([1..4], false) == [1..4]
InvokerHelper.toString(1..4) == [1, 2, 3, 4] // surprise
InvokerHelper.toString([1..4]) == [1..4]
{code}
So ranges get expanded to lists in printing, unless they are contained in any 
other Structure (Collection, array, Map).
That is because ranges get special treatment in format, but not in toString(), 
and toString uses format for recursions.

Possible alternatives for groovy-2.5+: 
- Always print ranges in List-form in toString()
- Always print ranges in range-form in toString.
- Keep current inconsistent behavior.

Any change here can impact users of Groovy who rely on the current inconsistent 
behavior, so I don't know how to handle this.

h2. Provide safe printing for maps and arrays as well
The current state is this:
{code}
class ExceptionOnToString {String toString(){ throw new 
UnsupportedOperationException()}}
def eInst = new ExceptionOnToString()
InvokerHelper.toListString([eInst], -1, true) == 
'[<ExceptionOnToString@a1b2c3d4>]'
InvokerHelper.toListString([[eInst]], -1, true) == '[<ArrayList@a1b2c3d4>]' // 
unclear exactly what Object threw exception
InvokerHelper.toListString([[[[[eInst, 1, 2, 3]]]]], -1, true) == 
'[<ArrayList@a1b2c3d4>]' // same as preceding line
InvokerHelper.toListString([[x: eInst]] -1, true) == 
'[<LinkedHashMap@a1b2c3d4>]'
InvokerHelper.toListString([[x: [y: [z: eInst, a: 1, b: 2]]]] -1, true) == 
'[<LinkedHashMap@a1b2c3d4>]' // same as preceding line

// no similar api with 'safe' argument for arrays or maps
{code}

So toListString has an argument safe that makes the method catch exceptions 
(though not for nested structures), but that feature does not exist for the 
other data structures. As a result, the provided information is poor in some 
cases, and there just is not the same useful feature for printing other things 
than lists.

Possible alternatives for groovy-2.5+: 
- Keep current inconsistent behavior.
- remove (/ deprecate+later remove) method with safe flag
- Provide Safe variant non-recursive methods for other collections
- Provide recursively safe method for nested structures

I believe no client code can justifiedly rely on the fact that passing safe 
will *NOT* be safe unless for arguments directly (not nested) contained in a 
collection. So I would say providing safe alternatives that are recursively 
safe would be okay for Groovy2.5+

One problem is whether to make that change to the format method, thus changing 
the output of power-asserts in cases when toString() throws Exceptions, or 
whether to provide an alternative safe format method that does not impact 
powerasserts in any way. Note though that in GROOVY-7569 I suggest changing the 
output of powerasserts in a much more drastic way anyway, so if that were to be 
accepted, it would seem strange to refuse changes in this case.

h2. Map: key-self detection

The current state is this:
{code}
Map m = [:]
m.put('x', m)
InvokerHelper.toMapString(m) == '[x: (this Map)]'
Map m2 = [:]
m2.put(m2, 'x')
InvokerHelper.toMapString(m2) // StackOverflowError
{code}

Again I would argue that no client code can justifiedly rely on a 
StackOverFlowError being thrown, so changing this to not throw it cannot impact 
users in an unjustified way.

h2. Provide safe printing for Ranges as well

When the objects defining the range borders throw an exception in toString(), 
the question is whether to handle that like for Collections. This is such a 
rare and exotic case that I would think it does not matter either way. Since 
implementing safety here is simple (if a safe format method exists), I would 
suggest to allow it being safe.


I changed the PR to have 4 commits to closely match the 4 suggested features 
above.

> InvokerHelper formatting methods have inconsistent API
> ------------------------------------------------------
>
>                 Key: GROOVY-7563
>                 URL: https://issues.apache.org/jira/browse/GROOVY-7563
>             Project: Groovy
>          Issue Type: Improvement
>          Components: groovy-jdk
>            Reporter: Thibault Kruse
>            Assignee: Guillaume Laforge
>            Priority: Minor
>
> in class org.codehaus.groovy.runtime.InvokerHelper, there are methods used to 
> print out Objects. The methods sometimes have a maxsize, verbose or safe 
> argument, but they do not have them consistently. I suggest changing the 
> private API so that methods for all Collection/Map types have the same API 
> and same functionality.
> See https://github.com/apache/incubator-groovy/pull/96



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to