scala> val f2: Unit => Int = _ => 5
val f2: Unit => Int = Lambda/0x0000021f62085a28@7819d0e8
and pass () as a value to f2 when call it.
scala> f2(())
val res1: Int = 5
and is understandable, when considering them in typing.
What is () in () => Int and () => 5 in the following expressions?
scala> val f1: () => Int = () => 5
val f1: () => Int = Lambda/0x0000021f62059430@250551af
scala> f1()
val res0: Int = 5
() in () => Int and () => 5 should be a type for typing declaraton, then what is its value? what is the difference between () as type and Nothing? but for Nothing in function signature, it means non-invokable function.
Unfortunately the meaning of () is overloaded; in most other languages it means “empty parameter list” or “no arguments”, but because Scala has that SML heritage, it also means “unit value” (which, most other languages do NOT have) in other contexts, hence the confusion…
Yet another unrelated thing: there is also => Int which is the declaration for a by-name parameter.
Thank you for your quick answer. What you said is also the idiom of other programming languages.
But from type theory, a type is either uninhabited or inhabited by one or more inhabitants. From set thoery, there is an empty set, singlton set, finite or infinite set, so your explanation seems difficult to understand from this perspective.
so if () was a type, it should have one value at least, or we should use Either as the parameter. But when we call f1, we have passed no value. That is confused.
The Unit type has exactly 1 inhabitant, namely the value (). So it’s a singleton
() is not a type as Seth said, yet () => Int is a type, which I think is the source of the confusion. Normally we would think: “type1 => type2” but this way of thinking does not fit this case. It should be Unit => Int, you can think of it that way, if it helps you…
It’s an unfortunate irregularity in Scala, so you just have to accept it. Basically, don’t take it too seriously or try to force it into a conceptual understanding. It’s just the way it is. Many languages have some irregularities here and there, we just accept them. This is how we avoid confusion. It’s irregular, so it doesn’t fit. I hope this makes sense. Sometimes “nonsense” is the way to make sense of things
I think these irregularities that don’t follow a rule inside our minds are the most confusing and difficult to understand, especially for students and newcomers. That’s why I think of programming languages like natural human languages. They can be full of ambiguity or overloading of meaning, just like English, French, etc.
There is the unit type in SML, with only one value (), so that’s where it came from in Scala. Now, SML also has the “empty parameter list” meaning, but it’s written a little differently with a fn keyword, which clarifies things a little:
(this is the SML REPL)
- val f = fn () => 5;
val f = fn : unit -> int
- f();
val it = 5 : int
In Scala, the same thing looks like:
scala> val f = () => 5
val f: () => Int = Lambda/0x0000737c844e5410@7db47323
scala> f()
val res0: Int = 5
Probably it would be better if Scala had the type as Unit => Int but maybe not? Unit indicates a side-effect, not exactly the same meaning as “empty parameters” so maybe Scala’s version is better? As I said, it’s irregular and it’s really a conceptual, almost philosophical difference… these philosophical problems are hard to solve it doesn’t matter, just accept it and move on
Fully agree, we should drop () as only instance of Unit and use unit instead,
imho. It would free up its interpretation as empty Tuple for example, which makes much more sense.
Agreed!
…then there will be issues with code that uses unit as an identifier (lots of libraries probably! especially monadic ones)… so around and around it goes it’s a game of whack-a-mole! (How about sideEffect instead of unit? Nobody would ever use that! )
On some level overloading meaning seems unavoidable, there are too many “empty things” (empty tuples, empty parameter lists, “void” methods, etc.)
I asked this question just to see if there is something I don’t know about Scala’s types. Such questions are also hard to search online.
This and the following explanations are acceptable. Sometimes, some conventions can indeed make programming very convenient. For example, if the call is f2(()), it makes sense in theory, but it is indeed inconvenient in practice.
Thank you and everyone who responded to this question.