Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make compiler check that 2 method arguments have the same type?

Tags:

scala

Probably I am missing something fundamental here, but I was refactoring certain things in my code and on the halfway I noticed that my code compiles, where I would expect it would not. So here is the method signature:

def checkUiFieldValue[T](fieldName:String, uiValue:T, expectedValue:T):Unit ={...}

Here is a place where it is used:

checkUiFieldValue("State", stateInListView(ar.name), ar.state)

The return type of the stateInListView is ARState class, while the type of the ar.state is String. So question is why does it compile and does not tell me that types do not match? I caught myself with a thought that I expect that compiler would check that uiValue and expectedValue are of the same type T but probably my assumption is incorrect.

Or type parameter T in the method definition actually means that both arguments will be casted to Any in my case? If so then how should I properly restrict both args to have the same type at compile time?

like image 679
Alexander Arendar Avatar asked Mar 09 '23 00:03

Alexander Arendar


2 Answers

One possible approach is to infer the types of the two arguments separately then use =:= to prove they're the same:

def test2[S, T](a: String, b: S, c: T)(implicit ev: S =:= T): T = ???
val x = test2("", new A, new A) // compiles
val y = test2("", new A, new B) // doesn't compile; can't prove A =:= B

This might be a bit strict for you though in the presence of subtyping:

class C extends B
val z = test2("", new B, new C) // doesn't compile; can't prove B =:= C
val w = test2[B, B]("", new B, new C) // does compile
like image 120
Hugh Avatar answered Mar 11 '23 04:03

Hugh


As you mention, the reason why that compiles is that T is the first common type between stateInListView(ar.name) and ar.state.

You can verify this by executing these lines:

class A()
class B()

def test[T](a : String, b : T, c : T) : T = ???   

val x : Any = test("ciao", new A(), new B()) // Compiles OK
val y : A = test[A]("ciao", new A(), new B()) // Does not compile: B does not work
val z : B = test[B]("ciao", new A(), new B()) // Does not compile: A does not work

Besides specifying T manually (e.g. test[A](...)), I can't really think of a way to avoid this behaviour....

like image 22
mdm Avatar answered Mar 11 '23 06:03

mdm