Reputation: 4383
The code is:
def mergeTrees(t1: TreeNode, t2: TreeNode): TreeNode = {
if (t1 == null && t2 == null) null
else if (t1 == null) t2
else if (t2 == null) t1
val root = new TreeNode(t1.value + t2.value)
root.left = mergeTrees(t1.left, t2.left)
root.right = mergeTrees(t1.right, t2.right)
root
}
And if I change it to:
def mergeTrees(t1: TreeNode, t2: TreeNode): TreeNode = {
if (t1 == null && t2 == null) null
else if (t1 == null) t2
else if (t2 == null) t1
else {
val root = new TreeNode(t1.value + t2.value)
root.left = mergeTrees(t1.left, t2.left)
root.right = mergeTrees(t1.right, t2.right)
root
}
}
Then it works. What's the reason behind this?
Upvotes: 1
Views: 61
Reputation: 13985
In Scala language specification, the syntax for def
is supported by following gremmar,
Def ::= ‘def’ FunDef
FunDef ::= FunSig [‘:’ Type] ‘=’ Expr
FunSig ::= id [FunTypeParamClause] ParamClauses
So, in your def mergeTrees(t1: TreeNode, t2: TreeNode): TreeNode = {...}
, the RHS is an Expr
and this particular syntax for Expr
is supported by following grammar,
Expr := Expr1
Expr1 := PostfixExpr
PostfixExpr := InfixExpr [id [nl]]
InfixExpr := [‘-’ | ‘+’ | ‘~’ | ‘!’] SimpleExpr
SimpleExpr := BlockExpr
BlockExpr := ‘{’ Block ‘}’
Block ::= BlockStat {semi BlockStat} [ResultExpr]
So... the parser determines your RHS to be a BlockExpr
,
And if you read about blocks
in Scala language specification at - https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#blocks, you will find the following explantion,
A block expression {s1s1; ……; snsn; ee} is constructed from a sequence of block statements s1,…,sns1,…,sn and a final expression e
.
Now, what is a block statement
of BlockStat
?
In we just consider the following case
def abc(i: Int): Int = {
i + 1
i + 5
}
In this case the i + 1
will be ignored (treated as a statement) and i + 5
will be the return value.
Which is similar (but far simpler) to your case, then the RHS BlockExpr is parsed as following,
'{'
i + 1 (BlockStat)
i + 5 (ResultExpr)
'}'
But, that i + 1
looks like an Expr
(or Expression) then why is that treated as statment, that is because of following grammar for BlockStat
,
BlockStat ::= Import
| {Annotation} [‘implicit’ | ‘lazy’] Def
| {Annotation} {LocalModifier} TmplDef
| Expr1
Which means any Expr
of Expr1
grammer can be also be treated as BlockStat
.
So, in this case since the following,
{
i + 1
i + 5
}
best matches to the grammar,
'{'
BlockStat
ResultExpr
'}'
So, this i + 1
which is actually an Expr1
is treated as an statement
and not an expression
. Which means that it will not be the value
of the block expression and the next i + 5
will be tread as value
of the block.
Now, in your case since the following expression
,
if (t1 == null && t2 == null) null
else if (t1 == null) t2
else if (t2 == null) t1
is followed by more statements, these will be treated as a statement
and thus it will not be return value of your def
. And further expression/statements will also be evaluated.
And since your next statement is,
val root = new TreeNode(t1.value + t2.value)
t1.value
or t2.value
will throw NullPointerException on evaluation in case if t1
or t2
is null
.
Upvotes: 1
Reputation: 51271
A chain of if
, else if
, ...
, conditions constitutes a single expression with a single result.
In your 1st example the if else ...
chain results in either null
or t2
or t1
. But the if else
expression is not the only expression in the code block so, because the if else
result is not saved anywhere then it is thrown away and processing moves on to the next expression. Which is not what you intended or want.
The 2nd code example works because there is only one expression in the mergeTrees()
method and that is the if else
expression. So in that case the result of the if else
is the result of the entire method.
Upvotes: 1
Reputation: 4922
In your first example you have an if
statement which calculates a value and then throws that value away. And then it proceeds to calculate the root assuming that neither t1
or t2
is null
.
The second example adds an else clause that is only used when neither t1
or t2
are null
. Now the result of the function is the result of the last statement in that function (which is the whole if
statement). And those values on other branches of the if
statement are useful (they might be the last value of the function and thus the return value).
Upvotes: 1