So you need to carry the safe-invoke thru the expr
f?.in?.readObj
panicdotalFri 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."
brianFri 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.
rfeldmanFri 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]
That's definitely the behavior I would expect...why is it better to have a compiler or runtime error?
jodastephenFri 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.
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.
heliumFri 25 Mar 2011
How would your syntax variation handle this case:
foo.bar?.baz
foo can't be null, but foo.bar can.
jodastephenSat 26 Mar 2011
The syntax variation makes the whole expression "handle null". Thus ?foo.bar.baz would handle your case.
DanielFathSat 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
rfeldmanSat 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 avoidNullErr.
Proposal:
Compiler treats foo?.bar.baz.etc as foo?.bar?.baz?.etc in all cases.
DanielFathSat 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).
tcolarSat 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.
rfeldmanSat 26 Mar 2011
Agreed, I have definitely been surprised by that behavior before.
brianSat 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)
qualidafialSat 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.
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:
So you need to carry the safe-invoke thru the expr
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 thata?.b
could likely be null.rfeldman Fri 25 Mar 2011
Out of curiosity, what is the advantage to having it work this way:
and not:
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:
ie. any expression may be prefixed by
?
, which "handles null".This could be combined with a shortened
?:
operator, although this feels less clear.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
can't be null, butfoo.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 avoidNullErr
.Proposal:
Compiler treats
foo?.bar.baz.etc
asfoo?.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 writefoo.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 thanfoo?+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:
So it makes sense that:
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