I am wondering why the two type parameters (named \"A\") with the same name (\"A\") is allowed as per the example below. I know this is a POOR naming of type parameters, do
Its not just related to scala. In most languages you can do that. Because as you said the variables are in different scope.
In c#
class test
{
int i;
void method(int i)
{
this.i = i;
}
}
this represents the self type. I am not sure about the this functionality in scala. But the reason for your question is scope level.
I'm not expert of Scala, but your code behave exactly what I would expected.
First, you need to know that the type parameter of method is not need bound to class.
For example, the following is valid Scala.
class Test1 {
def test[A] (x: A) = println(x)
}
And the following is also a valid Scala code, the only different is that this one does not use the type A at all.
class Test2[A] {
def test (x: Int) = println(x)
}
So I think it is clear now, first you created a instance of MyTest[Int], which is fine.
scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest@308ff65f
Then you called checkString[A, Int] without provide type parameter A, since it is a generic function, the compiler must inference what type is A.
scala> test.checkString("String",1)
Value is a String
x is not a String
res7: java.lang.String = String
Note:
In this time point, Scala already knows that x must be a Int and its type is fixed, since you provide it by MyTest[Int]. So the following code will yield compile error.
scala> val t = new MyTest[Int]
t: MyTest[Int] = MyTest@cb800f
scala> t.checkString ("A", "B")
<console>:8: error: type mismatch;
found : java.lang.String("B")
required: t.MyType
t.checkString ("A", "B")
Now the complier looks at the arguments you provided, and found its is
checkString ("String", 1)
which is corresponding to
checkString (value: A, x: Int)
So now compiler knows type A in checkString[A, Int] must be a string, and if you do all of this by hand, your code will look like this.
scala> val test = new MyTest[Int]
test: MyTest[Int] = MyTest@5bda13
scala> test.checkString[String]("String", 1)
Value is a String
x is not a String
res1: String = String
scala> test.checkString[Int] (3, 4)
Value is not a String
x is not a String
res4: Int = 3
scala> test.checkString[Int] ("String", 4)
<console>:8: error: type mismatch;
found : java.lang.String("String")
required: Int
test.checkString[Int] ("String", 4)
^
Well I belive at scala we use same rule as in Java basically we are looking for smallest available scope in Java:
class Foo<T>{
T instance;
void <T> T getInstance(){
return instance
}
}
Will produce a compilation error since type T declared in generic method getInstance is not the same as parameter type of class Foo. In case of Scala I believe then you write
def checkString[A]
You telling compiler that function behavior will vary upon provided type but it has no connection with parameter class of outer class. Unfortunately I cannot find correct place is Scala spec right now.
Nested scopes in Scala are free to shadow each others' symbol tables. Types are not the only things you can do this with. For example:
class X[A](a: A) {
def X[A](a: A) {
if (a==this.a) {
val X = Some(this.a)
X match {
case Some(a) => "Confused much yet?"
case _ => "Just because you can do this doesn't mean you should."
}
}
}
}
The principle is that a scope has control over its namespace. This has dangers, if you use it foolishly (e.g. I have used X
and a
for each of three different things, and A
for two--in fact, you could replace every identifier with X
except for the one in the Some
which has to be lower case). But it also has benefits when writing functional code--you don't have to worry about having to rename some iterating variable or type or whatever just because you happen to place it in a different context.
def example = {
val a = Array(1,2,3,4,5)
val sumsq = a.map(i => i*i).sum
a.map(i => {
val a = Array.range(1,i)
val sumsq = a.map(i => i*i).sum // Cut and paste from above, and works!
sumsq + i
}).sum
}
So be aware that you have the power to confuse yourself, and wisely choose to use that power non-confusingly.