What does '()' mean in '() => Int' and '() => 5'?

() is the single value of Unit type. So we write

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.

Thanks.

When used in combination with =>, () means “no arguments”.

() => Int is a type, the type of a function value that takes no arguments and returns an Int.

() => 5 is an expression, a function literal that takes no arguments and always returns 5.

In both cases, () doesn’t have any independent meaning — it only means something when uses in combination with =>.

There is no direct relationship between that meaning of () and the meaning of () as a value of type Unit.

what is the difference between () as type and Nothing ?

By itself, () is not a legal type. There is no relation between the two things in your question.

Hope this helps!

2 Likes

Just like what Seth said.

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.

1 Like

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.

@spamegg1, I just see your answer. I will read the material you point out. Could you give a more specific link to SML about my topic?

Thank you very much.

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 :smiley:

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 :smiley: it doesn’t matter, just accept it and move on :smiley:

1 Like

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.

And not only for them, for me it still is the hardest part of Scala, even after all those years being member of this community. But hé, in school I always got A’s in math and F’s in languages. :grin:

1 Like

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 :laughing: it’s a game of whack-a-mole! (How about sideEffect instead of unit? Nobody would ever use that! :smiley: )

On some level overloading meaning seems unavoidable, there are too many “empty things” (empty tuples, empty parameter lists, “void” methods, etc.)

1 Like

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.

1 Like
scala> val x: Function0[Int] = () => 42
val x: () => Int = Lambda$1453/0x00007b84144ec410@dae5e0

scala> x.getClass.getInterfaces
val res0: Array[Class[?]] = Array(interface scala.Function0, interface java.io.Serializable)
1 Like