Well, if you think in terms of how a Char is represented, a Char is jusr an unsigned 16 bit field, with a range from (0 to 2^16 - 1). This can fit without an overflow in an Int (32 bit signed, with a range from -2^31 to 2^31 - 1).
Some of Scala's basic types are, in order of the length of their representation in bits:
Byte (8)
Char (16)
Int (32)
Long (64)
All are signed, except for Char and all are convertible to a type "below" it as they would never over/under-flow (except for Byte to Char, which doesn't exist). See all of those implicit conversions in the Predef.
This is the reason I believe the implicit conversions exist - to allow expressions like the following to exist:
def foo(c: Char) { println(c) }
foo('a' + 2) // prints c
Another explanation is along the lines of the one you have given (a Char is just a number...). For me it does make sense - the set of all Chars is included in the set of all Ints, and therefore, applying my own guidelines for using implicits, the conversion should really be implicit.
I do understand your annoyance as I like compilers to signal errors like the one you have just gave as an example. It would be nice if Scala had a way to turn implicit conversion off (or turn specific implicit conversions off, as turning them all off would probably wreck havoc!)
The only solution I see for your problem is using Map[RichChar, Int] or something similar - RichChar is implicitly converted to an Int, as implicit conversions cannot be chained. EDIT found out that there actually is no implicit conversion from RichChar to Char.
def foo(x: Int) = x + 1
import scala.runtime.RichChar
val ch = 'a'
val rch = new RichChar('a')
foo(ch) // compiles fine
// foo(rch) // does not compile
def bar(ch: Char) = println(ch)
// bar(rch) // oops... does not compile
implicit def rch2char(rch: RichChar): Char = rch.self.asInstanceOf[Char]
bar(rch) // yay!
EDIT: Actually, if you have a good look at the Scala API, Char does have an overloaded + method which takes an Int argument. Same goes for Int. This could have to do with the fact that the underlying JVM does something similar.
Also note that the example I have gave you had nothing to do with allowing adding Ints to Chars! This is already allowed by the API. The more subtle point is that when you add an Int to a Char, you get an Int. The implicit conversion is there to allow using the result of this addition as a Char.
Also note the more theoretical answer I have given - Char is a subset of Int !
-- Flaviu Cipcigan