#1461 safe invoke bug?

panicdotal Fri 25 Mar 2011

Is this a bug? I get a java nullPointer Exception. I thought the safe invoke would short-circuit it.

File? f; obj = f?.in.readObj

I have to do following: File? f; obj = f?.in?.readObj

andy Fri 25 Mar 2011

Every part of that expression can return null if something earlier in the chain returns null:

File? f := null
f?.in.readObj  // f?.in == null --> null.readObj

So you need to carry the safe-invoke thru the expr

f?.in?.readObj 

panicdotal Fri 25 Mar 2011

OK. I misinterpreted the docs' use of the term short-circuit.

"If at any point in a null-safe call chain we detect null, then the whole expression is short circuited and the expression evaluates to null."

brian Fri 25 Mar 2011

I am going to add a check in the compiler to detect that. Essentially something like a?.b.c should really be a compiler error since we know you expect that a?.b could likely be null.

rfeldman Fri 25 Mar 2011

Out of curiosity, what is the advantage to having it work this way:

File? f := null
f?.in.readObj  // f?.in == null --> null.readObj [or compiler error, I guess]

and not:

File? f := null
f?.in.readObj  // f?.in == null --> null

That's definitely the behavior I would expect...why is it better to have a compiler or runtime error?

jodastephen Fri 25 Mar 2011

Interesting how expectations vary. From a compiler perspective, each part is completely separate, so the current Fantom approach makes sense (and a compiler error more so). However, from a usability perspective, perhaps all the developer is trying to say is "yes this might be null, compiler please handle that for me".

To express user, intent. there is an interesting syntax variation:

f?.in?.readObj  // today
?f.in.readObj   // possible change

ie. any expression may be prefixed by ?, which "handles null".

This could be combined with a shortened ?: operator, although this feels less clear.

f?.in?.readObj ?: ""  // today
?f.in.readObj : ""    // possible change

I guess this would affect other operators too, such as + (the online documentation doesn't seem to discuss what happens with null and shortcut operators)

I'm not sure whether I like this syntax variation, particularly as it gives slightly less power. However, it is worth considering.

helium Fri 25 Mar 2011

How would your syntax variation handle this case:

foo.bar?.baz

foo can't be null, but foo.bar can.

jodastephen Sat 26 Mar 2011

The syntax variation makes the whole expression "handle null". Thus ?foo.bar.baz would handle your case.

DanielFath Sat 26 Mar 2011

Yeah, joda's suggestion is one less compiler friendly but more programmer friendly (don't make me think). It would be tricky to implement, but it's probably the best solution overall.

+1 to ?foo.bar.baz

rfeldman Sat 26 Mar 2011

What is the downside to having foo?.bar.baz behave the same way as the proposed ?foo.bar.baz?

Personally I don't think there is any ambiguity in programmer intent if I write foo?.bar.baz - I am quite clearly saying "foo might be null, so compiler, handle this for me."

Is it really reasonable to expect that most developers want a NullErr or a compiler error to be thrown if they write a chain like that? Really? What is the use case for that? The whole point of ? is to circumvent writing boilerplate to avoid NullErr.

Proposal:

Compiler treats foo?.bar.baz.etc as foo?.bar?.baz?.etc in all cases.

DanielFath Sat 26 Mar 2011

Prefix notation (?foo.bar.baz) obviously goes before anything else. A notation like (foo?.bar.baz) does and will allow someone to write foo.bar?.baz. This might be a good thing but I think the simpler (for programmer) solution is best.

PS. As joda said. ?foo+bar would be handled by compiler in a more uniform way than foo?+bar (though the potential to complicate things is there i.e. ?foo+bar*baz).

tcolar Sat 26 Mar 2011

I agree with this (as rfeldman said) My first intuition when using fantom was that the whole rest of the chain would be short circuited if a piece was null

I know I'm not the only one that made that mistake either as its come up somewhat frequently here.

rfeldman Sat 26 Mar 2011

Agreed, I have definitely been surprised by that behavior before.

brian Sat 26 Mar 2011

Boy lots of comments for I thought was sort of an odd boundary condition.

Technically from a language perspective:

a.b.c === (a.b).c

So it makes sense that:

a?.b.c === (a?.b).c

The dot operator binds left to right.

I am uncomfortable changing the meaning of the dot operator because of context. So I think the safest short term solution is to just make it a compile time error if you use a dot operator after a null-safe dot. That keeps thing simple and keeps you from shooting yourself in the foot. Then the code will read clearly with exactly what is happening.

But as the most conservative design choice it doesn't prevent us from enhancing the behavior in the future (like some of these other proposals)

qualidafial Sat 26 Mar 2011

I think I agree with Brian here. I vote to make it a compiler error.

We can always choose to allow it sometime in the future, but if we allow it now and discover a problem with it, we can't take it back out without breaking backward compatibility.

rfeldman Sat 26 Mar 2011

Fair point. I can see the wisdom in that. +1

Login or Signup to reply.