#2068 SafeInvoke with XElem and ParseErr

bedla Fri 14 Dec 2012

Hi, maybe I dont understand safeinvoke operator correctly but following code throws exception.

Code>

using xml
class SafeInvokeTest
{
  static Void main()
  {
      element := XElem("test")
      echo("$element element.text = $element.text")
      test := element.text?.val.toInt
      echo("$test")
  }
}

Console output>

<test> element.text = null
sys::ParseErr: Invalid Int: 'null'
  fan.sys.FanInt.fromStr (FanInt.java:40)
  fan.sys.FanStr.toInt (FanStr.java:841)
  fantomtest::SafeInvokeTest.main (SafeInvokeTest.fan:10)
  java.lang.reflect.Method.invoke (Method.java:601)
  fan.sys.Method.invoke (Method.java:559)
  fan.sys.Method$MethodFunc.callList (Method.java:198)
  fan.sys.Method.callList (Method.java:138)
  fanx.tools.Fan.callMain (Fan.java:173)
  fanx.tools.Fan.executeType (Fan.java:140)
  fanx.tools.Fan.execute (Fan.java:41)
  fanx.tools.Fan.run (Fan.java:298)
  fanx.tools.Fan.main (Fan.java:336)

When I change element.text?.val.toInt to element.text?.val?.toInt variable test is null as expected. This is I dont understand, because XElem.text signature is XText? and XText.val signature is Str, and I think that when I dont have nullable val slot I can use normall call.

Is it bug or I just dont understand it well :]

Thx

Ivos

Yuri Strot Fri 14 Dec 2012

This is actually by design, see this discussion: #1461.

And I believe since v1.0.61 there should be compile check for such chaining calls:

fansh> "".index("a")?.toStr.toInt
ERROR(26): Non-null safe call chained after null safe call

bedla Fri 14 Dec 2012

Currently I am using fantom-1.0.63 and when I compile there is no error. What I do not understand is that, why call did not ended at first null value and insted of it compiler passes Str with value "null" and try to convert it to Int with exception.

brian Fri 14 Dec 2012

If you look at your code, it is really looks like this:

temp := element.text?.val
test := temp.toInt

Since temp is null, the non-safe call to toInt fails with NPE. What you need is:

test := element.text?.val?.toInt

As ystrot said, we need to fix the compiler to report that as an error

katox Fri 14 Dec 2012

@bedla Safe invoke is not really a global operation (working within a statement) but a normal operator.

This is the same situation as in Groovy (originating safe-invoke operator as well as elvis operator, I guess). See for example http://www.nearinfinity.com/blogs/jeff_kunkle/groovys_safe_navigation_operat.html

bedla Sat 15 Dec 2012

Ok, no problem for me. But I think, that docs should be updated to capture this "corner case" (Groovy's explanation, URL you provided, makes more sance for me than Fantom docs).

Login or Signup to reply.