The word ‘unit’ is used very widely in the real world.
For example, A Quantity class consists of ‘amount’ and ‘unit’.
data class Unit(
val code: String,
val name: String,
val symbol: String
)
data class Quantity(
val number: Number,
val unit: Unit
)
val METER: Unit = Unit("m", "meter", "M")
val GRAM: Unit = Unit("g", "gram", "M")
val heightOfBuilding = Quantity(500, METER)
val weightOfBeef = Quantity(500, GRAM)
I can’t use Unit because Kotlin occupied it.
There is no suitable word for ‘a standard amount of a physical quantity’ except Unit.
That is unfortunate. You could potentially use instead:
Dimension
MeasurementUnit
Magnitude
I definitely wouldn’t recommend it, but if you are dead-set on the Unit naming, you could import kotlin.Unit as KUnit to avoid the namespace collision.
Using full names instead of initialisms makes them more readable, and your IDE’s code completion makes them pretty easy to type. I would suggest you use UnitOfMeasure as your class name.
I have to agree. And there is this disregard for units of measure across almost all other languages and standard libraries. It’s almost like software engineers have a prejudice against actual science. I have never quite understood.
“Unit” is a term from type and category theory, it is the representation of all types with exactly one element, and there is always a unique mapping from any type to unit. In a sense, “Nothing” (or “bottom”) is kind of its opposite, because you can uniquely map Nothing to every type.
There will be always some words you would like to use (e.g. I’m often annoyed that “is” and “as” are off limits for my DSLs). I agree that the overlap in meaning with physical and mathematical units is unfortunate, but in my opinion “Unit” expresses much better what is going on than the “void” inherited from C. Making it a “real” type was a huge improvement over the special handling that “void” needed, so I’m all for naming it appropriately, even if it is a minor inconvenience in cases like yours.
What I find odd about the name ‘Unit’ is that Kotlin has generally prioritised being clear and easy to read, even when that means not following existing usage in mathematics, computer science, and/or previous languages. (For example, fun instead of ‘def’, Nothing instead of ‘bottom’ or ‘void’, Any instead of ‘top’ or ‘Object’…)
But Unit seems very much a term from mathematics. In general usage it makes only the vaguest sense, isn’t very intuitive, and doesn’t read well. (As shown by the confusion it seems to generate, and all the questions about it on sites like this.)
Maybe JetBrains just couldn’t think of anything better? (I’m not saying that I can… But if they had, then code would read better and the word would be free for the scientific meaning!)
The Unit type ist a well known term in functional programming, e.g. Scala uses it. I think it was sensible by JetBrains to keep it, instead of reinventing the wheel.
For me personally, one of the main selling points of Kotlin was to be “Scala, but for humans”. “Unit” is a great example of things that stopped me from getting into Scala and Kotlin is free of most of such stuff.
But I agree that maybe there wasn’t a better word. Type system is by nature an abstract thing and speaking about it is going into the academic territory already. We can’t avoid this easily.
As somebody who has avoided Scala like the plague, this is only for a small set of users better. For example in your case. However, ‘Unit’ for me does not ring a bell at all other than a Unit of Measurement.
According to Kotlin:
In Kotlin, Unit is a type that represents a function that does not return any meaningful value. It is similar to void in Java and other languages but has some differences and specific uses in Kotlin. Let’s explore Unit in detail:
So basically They are returning a unit of something that is nothing?? I find that confusing, Scala is also confusing
No, they return a very concrete “something”, but this something is usually ignored, because there is only one value for this type, and this value holds no data. So, you can think of it as: “This method returns something, but the result is so boring that you can safely ignore it.”
So why bother? I can see at least two reasons:
“Something” is not “nothing”. If you had a method in Java that would never return (infinite loop or throwing always an exception), you would give this method the same return type void like a “normal” method. In Kotlin you can do better, and distinguish it from normal methods by using Nothing instead of Unit. E.g. you have probably come across the TODO() function, and it only works because of this distinction.
Returning a rather boring, but regular value helps a lot when using generics. In Java you had all these special cases handling “no return value”, like the interface Consumer - in Kotlin it’s just a normal function returning Unit. Kotlin does more interesting stuff with generics, like more functional programming and extension methods, that makes it more important to avoid this quirk (similar as it is avoiding the problems Java has with primitive types as generic parameters)
Don’t think Unit is the same as void, it really isn’t. It is a very normal type with a single value (also named Unit) that helps to make the type system more regular. You can assign it to variables, it can be an argument, there is nothing special about it, except that you don’t have to return it explicitly in a function, and that it is exceptionally boring.
I understand and respect the language designer’s intention. Unit is scientific and rational, but not practical nor user-friendly.
In my project, I have written down about 100K lines, but used Unit less than 10 times. In addition, the word ‘unit’ is widely used not only in the computer science world, but also in the real world. I tried to find alternative words of unit but failed.
I love Kotlin’s sense of humor. Whenever I type ‘fun’, I have fun. Unit makes Kotlin scientific, but hard to use in science.
So what I understand is that a ‘something’ not interesting and (on my side of usage of Kotlin) never considered, must be expressed to me in order I remember there is a ‘something’ having the appearance of ‘nothing’.
I’m a bit ironic, it’s true. But when I discovered Kotlin I thought it was a bit weird this ‘Unit’ that is always used as a ‘void’ or ‘Void’ (when specified) in other languages.
As UX specialist and developer, I do like relevant semantics, and to my opinion there are too much hidden considerations behind this key word, which are not useful for the users, that would justify not to use it and keep the general semantic ‘void’ (even little not completely relevant) in order to preserve the accessibility.
But that’s the thing. The “something” does not have the appearance of “nothing”. Example:
// the `: Unit` return type can be implicit
fun doSomething(): Unit
and
fun throwAnError(): Nothing
The Kotlin compiler and you the programmer are able to distinguish these functions. The compiler (and you) know the first function is expected to return, while the second will never return, and that all subsequent code is unreachable.
If both of these functions returned void (or whatever the Kotlin equivalent would have been e.g. Void), the Kotlin compiler could do no better than Java can with the corresponding declarations.
Why not add Nothing in the type system, and use the more familiar Void for just the first case? That would have been exceedingly confusing for developers already familiar with the concept of Void in other languages, and it would complicate interop with Java.
Ok Raman… I can understand your point but on the site of usage :
You don’t wait for anything from → Unit, no more form → Nothing
So take Swift, you have Void. Does Kotlin has different concerns than Swift? No the same.
The gut of mech that needed to have that “type” having a unique value… even justified by the design, should not rise at the surface of language. Its semantic is not accurate, no more its relationship with the usefulness.
And the fact is not “common” in the universe of language, should have been enough to decide to use a common term.
I can say the same for coroutine that choose to tag function that should run ‘async’ with the tag ‘suspend’ just because in the gut of mech there is suspension.
It’s for me the same error that name a function after the technique involved in it rather than what it produces.
As I understand it the Swift Void type is equivalent to the void type in every other language, including Java. It does not differentiate between a function that never returns and a function that returns with no value. So yes, Kotlin does something different and (IMO) better.
Different topic… but good analogy because I think you are making a similar mistake. A suspending function is not an asynchronous function in the common use of the term “asynchronous”. So using async would be confusing. In most other languages that use async in the function signature the return value is some kind of promise or task indicating the code runs asynchronously (i.e. in parallel) with respect to the caller. In Kotlin, a call to a suspending function is synchronous – the caller suspends at that line of code until the call is complete.
Swift is the notable exception here, and IMO did confusingly use the async keyword for functions that suspend and do not have some kind of Promise return type. The developer has to deal with this at the call-site by doing either let foo = await asyncFunction() to mark the suspension, or async let foo = asyncFunction() to indicate that foo is a future/deferred/promise type (and confusingly, this use of the async keyword actually indicates parallelism, as opposed to an async function which does not). Their documentation is similarly confusing, asserting contrary to the common use of the term that asynchronous means suspending, not parallel:
Asynchronous code can be suspended and resumed later, although only one piece of the program executes at a time.
The Kotlin reasoning for use of the suspend key word is that suspension is the fundamental concept of concern. Furthermore, synchronous suspending calls are much more common than asynchronous calls, and thus require the least amount of ceremony.
void blah1() // says: there is nothing to collect from it
int blah2() // says: you should collect the result
so
int a = blah2()
with
func blash1() // same as void C' or Java' ones
func blash2() -> Int // "
if you:
blash2() // swift precompiler warn you don't collect
// the result
so you can:
_ = blash2()
or
@discardResult front to the func
if you:
var a = blash1() // swift precompiler warn there is nothing to collect
but with
fun blash1() // say what: in the commun developper head = Void
// so nothing to collect
the very stangeness (always on the usage side)
if you write
var a = blash1() // no precompiler complaint at all
println(a) // >> kotlin.Unit
you can even write
if (a == Unit) {...} // what is useless and a bit non sense
// (always on the usage side)
// because you didn't waited for something
// while your intention was 'Void'
2- on suspend
(precision: thread means kind of parallelism whatever been the way to do it)
An heavy function/operation can “block” the execution “thread” in a way you were waiting to be still responsive on an another part… let’s say mainly, on UI.
So the handling is to relocate the load on an other thread.
But there are tone of other reasons we want to relocate operations or delegate them to other threads. Not only UI.
In swift you declare the function to be async that force you to execute it in a Task {}.
It doesn’t mean this function is “blocking” so you delocate it? No you just say it must be relocated on an other thread than the main one.
You exposed await as blocking. It’s only the case if you execute more than 1 async func in a row.
func blash1() async { print(1) ; Thead.sleep(for: .second(2)) }
func blash1() async { print(2) }
Task {
await blash1() // print "1" then block the thread for 2 sec and passes hand to blash2
await blash2()
}
With coroutines, you’re faced (always on the usage side) with for instance: runBlocking { }
Let’s think a bit. The first time I see that I wandered, “what is blocking? what is inside the block? or it will run the block since I’ll stop current thread?..”
With suspend. I felt completely confused before reading the doc. Is it really “blocking” or I must translate it by async.
In fact, using it, you simply discover it’s exactly the same as async/await but whiteout the await
Two suspend functions in a runBlocking bloc (or whatever coroutines block) are strictly synchrone. So you have the same behavior but nothing to alert / signal you the fact.
suspend fun blash1() { println("1") ; Thread.sleep(2000L) }
suspend fun blash2() { println("2") }
runBlocking {
blash1() // print "1" then block the thread for 2 sec and passes hand to blash2
blash2()
}
finaly:
So I repeat again Raman, you could be right on the side of what stand under the hood, or in the reality of …
But on the side on usage… I maintain, it’s not user-friendly.
I must say there are probably to 2 things I found out of that case in this language.
It was explained before – Kotlin uses Unit so that functions are regular.
Lambdas that don’t return a value don’t need special handling versus lambdas that do. Since all functions return something (except the ones that don’t return at all i.e. Nothing :-)). Therefore we don’t need workarounds like the Java Consumer and the Java Function. In Kotlin, functions are not either Consumers or Functions – they are just Functions.
I agree the naming is not necessarily obvious, but other languages that support functional programming operate the same way. For example, Scala uses Unit as well.
As I was writing this, I thought – wait a second, it can’t be the case that Swift functions are not regular – and indeed, I was wrong earlier. Swift functions with no return value DO actually return something: the empty tuple (), which Swift simply aliases to Void:
func f1() {
print("f1")
}
// a compiler warning, not an error!
let f = f1()
// prints `()`
print(f)
So that Swift code prints () which is not so different than your example code which prints kotlin.Unit.
So if you think the Swift behavior is ideal, now you know Swift operates almost exactly like Kotlin. All we would have left to haggle over is naming and compiler warning behavior. The Kotlin compiler could probably be modified to emit a warning in that situation just like Swift does. So this isn’t a fundamental language concern.
If you didn’t know this about Swift Void, then its a good example of why using a different name is a good idea – it forces you to learn and understand as opposed to proceeding unchecked with an incorrect assumption, as I believe we were both doing with Swift.
You said:
Blocking is not about heavy operations. It is a Thread that can’t do anything else because it is waiting for something. For example, the JVM Thread.sleep method blocks a Thread. In fact, a Thread that is doing heavy operations is not actually blocked, it is in a Runnablestate.
Blocking simply means the thread is blocked and cannot move forward. This is standard terminology for Java threads. runBlocking is meant solely as a bridge from the world of threads to the world of coroutines. It is therefore doing exactly what it says – it is blocking the current thread while waiting for the coroutine to finish i.e. that thread is blocked and cannot do any other work.
Its natural to be a bit confused when encountering new language constructs, but once understood I don’t see how this isn’t reasonably developer-friendly?
Yep. I explained earlier why I think suspend was a better choice than async/await so I won’t rehash that. Its a valid point there is nothing in the code to indicate a suspension point (though IDEA shows it very clearly in the gutter). I haven’t found this to be a problem in practice.
You come from a Swift background? I come from a Java/Kotlin background and this is exactly what I think every time I use something new in Swift. Then after a while I learn how it works and think “yeah, that’s not too bad”. So mostly this is about language familiarity. But, I maintain that Kotlin by and large makes dev-friendly choices more often than not.