- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Accessing and referencing Nested Classes: Type Mistmatch Error problem
Sat, 2011-07-16, 03:01
I have created an abstract Class called Graph with two nested Case
Classes, partially described as follows
abstract class Graph[N,E]{
//Graph Nodes
case class Node(value:N){
…
}
//Graph Edges
case class Edge(s:Node,t:Node,value:E){
…
}
//NODE METHODS
/** Add a Node to the graph iff the value doesn't exist. If it
does, simply return the existing Node for that value */
def add(sv:N):Node = {…}
/** True iff the two nodes are neighbours of each other. That is,
if there exists an edge connecting
* either s --> t or t --> s. */
def areNeighbours(s:Node,t:Node):Boolean = {(areAdjacent(s,t) ||
(areAdjacent(t,s)))}
/** True iff two nodes are adjacent to each other - that is,
there exists an Edge from s --> t.
* Note: this can be different from being neighbours in the case
of a DirectedGraph. */
def areAdjacent(s:Node,t:Node):Boolean = { (neighbours(s) contains
t) }
…
}
I create a concrete class as follows:
/** Model of a Simple Graph.
* Note: A Simple graph is a graph with undirected edges. */
class SimpleGraph[N,E] extends Graph[N,E]{
…
}
Elsewhere in my ScalaTest / Junit tests, I make the declarations
var G1 = new SimpleGraph[String,String]()
var G2 = new SimpleGraph[String,String]()
//Nodes
var n1_1:SimpleGraph[String,String]#Node = _
var n1_2:SimpleGraph[String,String]#Node = _
initialized as
@Before def initialise(){
n1_1 = G1 add "A"
n1_2 = G1 add "B"
n1_3 = G1 add "C"
…
} //
I then try to make the following test:
@Test def Node_Neighbours_1(){
//confirms that nodes which are neighbours are confirmed as
such
(G1.areNeighbours(n1_1, n1_2)) should be (true)
}
I get the following Type Mismatch error:
type mismatch; found : graph.SimpleGraph[String,String]#Node
required: _113.Node where val _113: graph.SimpleGraph[String,String]
Note my Node declaration:
Var n1_1:SimpleGraph[String,String]#Node = _
I wanted to keep the Node case class internal to Graph because of the
parameterised types which are shared between Graph, Node and Edge. But
I can’t see how to deal with this type mismatch problem…
Any help much appreciated.
Shane
Sat, 2011-07-16, 11:57
#2
Re: Accessing and referencing Nested Classes: Type Mistmatch Err
Thanks Lars,
1) Understand about the bad style. However, this is in a ScalaTest
class and I'm reusing the variables in every test. Setting them to
"val" would prevent the test reuse.
2) Are you saying that when I define n1_1 as
var n1_1:SimpleGraph[String,String]#Node = _
where the type is "SimpleGraph[String,String]#Node" that this isn't
enough (noting the #Node suffix)?
Interestingly, the following test compiles and passes just fine:
@Test def Node_Equality_1(){
// Nodes with the same values are equal
(n1_1 == n2_1) should be (true)
(n1_2 == n2_2) should be (true)
(n1_3 == n2_3) should be (true)
}
Thanks for your thinking...
Shane
On Jul 16, 5:07 pm, Lars Hupel wrote:
> > Elsewhere in my ScalaTest / Junit tests, I make the declarations
>
> > var G1 = new SimpleGraph[String,String]()
> > var G2 = new SimpleGraph[String,String]()
> > //Nodes
> > var n1_1:SimpleGraph[String,String]#Node = _
> > var n1_2:SimpleGraph[String,String]#Node = _
>
> > initialized as
>
> > @Before def initialise(){
> > n1_1 = G1 add "A"
> > n1_2 = G1 add "B"
> > n1_3 = G1 add "C"
> >
> > } //
>
> First of all, that is very bad style. Try to keep everything as 'val's,
> and avoid 'null' values.
>
> > I get the following Type Mismatch error:
>
> > type mismatch; found : graph.SimpleGraph[String,String]#Node
> > required: _113.Node where val _113: graph.SimpleGraph[String,String]
>
> That's a path-dependent type. Because Node is an inner class of the
> Graph class, its instances are bound to a parent instance (or path) of
> Graph. You have to declare 'n1_1' with the type 'G1.Node'. (IIRC this
> only works if 'G1' is a stable identifier, i. e. a 'val'.)
Sat, 2011-07-16, 12:37
#3
Re: Re: Accessing and referencing Nested Classes: Type Mistmatc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 16/07/11 20:53, smagrath wrote:
> Thanks Lars,
>
> 1) Understand about the bad style. However, this is in a ScalaTest
> class and I'm reusing the variables in every test. Setting them to
> "val" would prevent the test reuse.
The contrary is true. Not setting to val prevents reuse.
Although it won't help your type error, the issue of "Accessing and
referencing Nested Classes" was discussed recently on another thread
regarding lenses.
Sat, 2011-07-16, 13:07
#4
Re: Accessing and referencing Nested Classes: Type Mistmatch Err
> The contrary is true. Not setting to val prevents reuse.
I'd like to second that.
> 1) Understand about the bad style. However, this is in a ScalaTest
> class and I'm reusing the variables in every test. Setting them to
> "val" would prevent the test reuse.
Maybe you could put them into an inner class of your test class and
re-instantiate them every time. Or, even better, think about making your
Graph class immutable.
Back to your issue.
> 2) Are you saying that when I define n1_1 as
> var n1_1:SimpleGraph[String,String]#Node = _
>
> where the type is "SimpleGraph[String,String]#Node" that this isn't
> enough (noting the #Node suffix)?
'#' stands for a type projection. That is, it is a super type of every
't1.Node' where 't1' is an instance of 'SimpleGraph', but not vice-versa
(otherwise, they would be equal).
I strongly recommend that you read a bit about path-dependent types and
projections, e. g. in .
> Interestingly, the following test compiles and passes just fine:
>
> @Test def Node_Equality_1(){
> // Nodes with the same values are equal
> (n1_1 == n2_1) should be (true)
> (n1_2 == n2_2) should be (true)
> (n1_3 == n2_3) should be (true)
> }
That's because of two reasons:
* '==' (or 'equals') is not type safe, so the compiler doesn't complain
* default 'equals' for case classes doesn't check the parent reference
(not sure about this one)
Sat, 2011-07-16, 13:17
#5
Re: Accessing and referencing Nested Classes: Type Mistmatch Err
Thanks for the heads up - I'll give it a go tomorrow.
Shane
On Jul 16, 9:06 pm, Lars Hupel wrote:
> > The contrary is true. Not setting to val prevents reuse.
>
> I'd like to second that.
>
> > 1) Understand about the bad style. However, this is in a ScalaTest
> > class and I'm reusing the variables in every test. Setting them to
> > "val" would prevent the test reuse.
>
> Maybe you could put them into an inner class of your test class and
> re-instantiate them every time. Or, even better, think about making your
> Graph class immutable.
>
> Back to your issue.
>
> > 2) Are you saying that when I define n1_1 as
> > var n1_1:SimpleGraph[String,String]#Node = _
>
> > where the type is "SimpleGraph[String,String]#Node" that this isn't
> > enough (noting the #Node suffix)?
>
> '#' stands for a type projection. That is, it is a super type of every
> 't1.Node' where 't1' is an instance of 'SimpleGraph', but not vice-versa
> (otherwise, they would be equal).
>
> I strongly recommend that you read a bit about path-dependent types and
> projections, e. g. in .
>
> > Interestingly, the following test compiles and passes just fine:
>
> > @Test def Node_Equality_1(){
> > // Nodes with the same values are equal
> > (n1_1 == n2_1) should be (true)
> > (n1_2 == n2_2) should be (true)
> > (n1_3 == n2_3) should be (true)
> > }
>
> That's because of two reasons:
>
> * '==' (or 'equals') is not type safe, so the compiler doesn't complain
> * default 'equals' for case classes doesn't check the parent reference
> (not sure about this one)
Sat, 2011-07-16, 13:37
#6
Re: Re: Accessing and referencing Nested Classes: Type Mistmatc
On Sat, Jul 16, 2011 at 03:53:58AM -0700, smagrath wrote:
> where the type is "SimpleGraph[String,String]#Node" that this isn't
> enough (noting the #Node suffix)?
This is not only not enough, this is exactly the bug in your code
the compiler is complaining about. That is the type of a Node in
*any* SimpleGraph[String,String], but the methods of graph G1
are only defined on nodes of graph G1. That is what Lars wrote,
the type of n1_1 must be G1.Node.
> Interestingly, the following test compiles and passes just fine:
>
> @Test def Node_Equality_1(){
> // Nodes with the same values are equal
> (n1_1 == n2_1) should be (true)
Yeah, most popular languages are fundamentally broken wrt. equality, which
is why scala has == and eq and a whole chapter on how to define equals in
in the staircase book (that still didn't prevent the problems discussed in
the recent thread on Proxy and case classes), Common Lisp has =, string=, eq,
eql, equal and equalp, PHP has == and === and so on.
Live with it or use haskell.
- Florian.
Mon, 2011-07-18, 02:07
#7
Re: Re: Accessing and referencing Nested Classes: Type Mistmatc
On Sat, Jul 16, 2011 at 08:27, Florian Hars wrote:
>
> Yeah, most popular languages are fundamentally broken wrt. equality, which
> is why scala has == and eq and a whole chapter on how to define equals in
> in the staircase book (that still didn't prevent the problems discussed in
> the recent thread on Proxy and case classes), Common Lisp has =, string=, eq,
> eql, equal and equalp, PHP has == and === and so on.
> Live with it or use haskell.
Mind you, Proxy is broken by design, even if it is true that it got
_more_ broken.
> Elsewhere in my ScalaTest / Junit tests, I make the declarations
>
> var G1 = new SimpleGraph[String,String]()
> var G2 = new SimpleGraph[String,String]()
> //Nodes
> var n1_1:SimpleGraph[String,String]#Node = _
> var n1_2:SimpleGraph[String,String]#Node = _
>
> initialized as
>
> @Before def initialise(){
> n1_1 = G1 add "A"
> n1_2 = G1 add "B"
> n1_3 = G1 add "C"
> …
> } //
First of all, that is very bad style. Try to keep everything as 'val's,
and avoid 'null' values.
> I get the following Type Mismatch error:
>
> type mismatch; found : graph.SimpleGraph[String,String]#Node
> required: _113.Node where val _113: graph.SimpleGraph[String,String]
That's a path-dependent type. Because Node is an inner class of the
Graph class, its instances are bound to a parent instance (or path) of
Graph. You have to declare 'n1_1' with the type 'G1.Node'. (IIRC this
only works if 'G1' is a stable identifier, i. e. a 'val'.)