I think parameterized types fit nicely in your setting. Abstract types are bound to a particular instance, hence the error you are getting. I confess I didn't try to refactor your example to make abstract types work, but the following snippet doesn't try to mix abstract and parameterized types, and scalac has no problems with it trait INodeTKey, TValue { type Node = INodeTKey, TValue def get(key : TKey) : TValue def set(key : TKey, v : TValue) : Node def combine(other : Node, key : TKey): Node } class ANodeTKey,TValue( val akey : TKey, val aval : TValue ) extends INodeTKey, TValue { def get(key : TKey) : TValue = aval def set(key : TKey, v : TValue) : Node = new ANode(key,v) def combine(other : Node, key : TKey) : Node = other.
Set(key, aval) }.
I think parameterized types fit nicely in your setting. Abstract types are bound to a particular instance, hence the error you are getting. I confess I didn't try to refactor your example to make abstract types work, but the following snippet doesn't try to mix abstract and parameterized types, and scalac has no problems with it.
Trait INodeTKey, TValue { type Node = INodeTKey, TValue def get(key : TKey) : TValue def set(key : TKey, v : TValue) : Node def combine(other : Node, key : TKey): Node } class ANodeTKey,TValue( val akey : TKey, val aval : TValue ) extends INodeTKey, TValue { def get(key : TKey) : TValue = aval def set(key : TKey, v : TValue) : Node = new ANode(key,v) def combine(other : Node, key : TKey) : Node = other. Set(key, aval) }.
1 See the scala style guide for type parameter style guide davetron5000.github. Com/scala-style/naming_conventions/… – oluies Jul 26 '10 at 13:24.
First of all I would like to point out that the combine method does not use the other parameter at all, you could just as well write: def combine(key : TKey) : Node = set(key, aval) .. but I guess it is just the principle we are after here. If you have a very small set of allowed TKey and TValue combinations (say 2), you can use the abstract type tactics and cut parameterized types out of the code all together: trait INode { type TKey type TValue def get(key : TKey) : TValue def set(key : TKey, v : TValue) : INode def combine(other : INode, key : TKey): INode } case class StringNode( val m_key : String, val m_val : String ) extends INode { type TKey = String type TValue = String override def get(key : TKey) : TValue = { m_val } override def set(key : TKey, v : TValue) : INode = new StringNode(key,v) override def combine(other : INode, key :TValue): INode = { other match { case node: StringNode => node. Set(key, m_val) case _ => throw new IllegalArgumentException("Not OK bla bla") } } } In my example you will get some code duplication in the methods of StringNode and, say, IntNode , but at least the principle of abstract types is illustrated.
Since other is a different INode, it has it's own TKey and TValue types. There is no guarantee that TKey and TValue of this ANode match those of other. You need to constrain the types with either equality or lower bound (which I used).
I didn't try to run it, but the following compiles against Scala 2.8.0 trait AbsTypes { type TKey type TValue } trait INode extends AbsTypes { def get(key : TKey) : TValue def set(key : TKey, v : TValue) : INode //def combine(other : INode, key : TKey): INode type TNode = INode { type TKey >: INode.this. TKey type TValue >: INode.this. TValue } def combine(other : TNode, key : TKey) : INode } class ANodeT1,T2(val akey : T1, val aval : T2) extends INode { type TKey = T1 type TValue = T2 type Node = ANodeT1,T2 def get(key : TKey) : TValue = { aval } def set(key : TKey, v : TValue) : INode = { new ANode(key,v) } def combine(other : TNode, key : TKey) : INode = { other.
Set(key, aval) } }.
Thanks for your answers, they're most helpful & have really helped my understanding. One alternative solution I've found is below. The AbsType doesn't need to be the base class, you can use it to wrap up the parameterized type definitions.
Class ANodeT Combine(n2,2) // compile error }.
I think parameterized types fit nicely in your setting. Abstract types are bound to a particular instance, hence the error you are getting. I confess I didn't try to refactor your example to make abstract types work, but the following snippet doesn't try to mix abstract and parameterized types, and scalac has no problems with it.
First of all I would like to point out that the combine method does not use the other parameter at all, you could just as well write.
Generic parameters don't automatically override abstract types, even if they have the same names. Try renaming the generic parameters (to avoid name conflicts), and then declaring the types TKey and TValue in the method body class ANodeA,B( val akey : A, val aval : B ) extends INode { type TKey=A type TValue=B def get(key : TKey) : TValue = aval def set(key : TKey, v : TValue) : INode = new ANode(key,v) } I suppose it would be nice if the compiler emitted an error on the line where you specified the names of the generic types, instead of waiting until you started using those types.
Generic parameters don't automatically override abstract types, even if they have the same names. Try renaming the generic parameters (to avoid name conflicts), and then declaring the types TKey and TValue in the method body. Class ANodeA,B( val akey : A, val aval : B ) extends INode { type TKey=A type TValue=B def get(key : TKey) : TValue = aval def set(key : TKey, v : TValue) : INode = new ANode(key,v) } I suppose it would be nice if the compiler emitted an error on the line where you specified the names of the generic types, instead of waiting until you started using those types.
Thanks, that solved this part, but I have a follow up question I'll post separately – NYCBrit Jul 26 '10 at 4:29 1 Could be worth adding here stackoverflow. Com/questions/1332574/… – oluies Jul 26 '10 at 7:58 @Brent, is that a common error? – Ken Bloom Jul 26 '10 at 13:36.
I don't have time unfortunately to test what I'm about to write but my understanding of your code is that each INode is going to get it's own TValue type. So the get operation really returns INode.this. TValue which is not compatible with another TValue type on another node.
The way to avoid this might be to write: trait Nodes { type TKey type TValue trait INode { def get(key : TKey) : TValue } class ANode( val akey : TKey, val aval : TValue ) extends INode }.
He's still going to have the same problem with your code, because akey and aval are of the types named by the generics, not the abstract types. (Furthermore, if you compile only this code, you're not going to notice any compiler errors because you didn't try to use the conflicting types. ) – Ken Bloom Jul 26 '10 at 1:04 Oh, yes, that's a copy and paste error.My intention was to use the types from the Nodes trait.
– Eric Jul 26 '10 at 1:09 I have edited your answer to reflect that intention, and removed my downvote. – Ken Bloom Jul 26 '10 at 2:17 Thanks, this would work, but it adds an unwanted reference to the outer type in my node instance. I'm trying to make the node as small/efficient as possible – NYCBrit Jul 26 '10 at 4:12.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.