What are the rules of semicolon inference? - kotlin

Kotlin provides “semicolon inference”: syntactically, subsentences (e.g., statements, declarations etc) are separated by the pseudo-token SEMI, which stands for “semicolon or newline”. In most cases, there’s no need for semicolons in Kotlin code.
This is what the grammar page says. This seems to imply that there is a need to specify semicolons in some cases, but it doesn't specify them, and the grammar tree below doesn't exactly make this obvious. Also I have suspicions that there are some cases where this feature may not work correctly and cause problems.
So the question is when should one insert a semicolon and what are the corner cases one needs to be aware of to avoid writing erroneous code?

You only need to specify semicolons in cases where it is ambiguous to the compiler what you are trying to do, and the absence of a semicolon would result in an obvious compiler error.
The rule is: Don't worry about this and don't use semicolons at all (other than the two cases below). The compiler will tell you when you get it wrong, guaranteed. Even if you accidentally add an extra semicolon the syntax highlighting will show you it is unnecessary with a warning of "redundant semicolon".
The two common cases for semi-colons:
An enum class that has a list of enums and also properties or functions in the enum requires a ; after the enum list, for example:
enum class Things {
ONE, TWO;
fun isOne(): Boolean = this == ONE
}
And in this case the compiler will tell you directly if you fail to do it correctly:
Error:(y, x) Kotlin: Expecting ';' after the last enum entry or '}' to close enum class body
Otherwise the only other common case is when you are doing two statements on the same line, maybe for brevity sake:
myThingMap.forEach { val (key, value) = it; println("mapped $key to $value") }
Absence of a semicolon in this last example will give you a more mysterious error at the point where it is confused what you are doing. It is really hard to make some code that would both be valid as two statements separated by a semicolon that are also valid when the semicolon is removed and they become one.
In the past there were other cases like an initialization block of a class which was more "anonymous" { ... } before Kotlin 1.0 and later became init { ... } which no longer needed the semicolon because it is much clearer. These cases no longer remain in the language.
Confidence in this feature:
Also I have suspicions that there are some cases where this feature may not work correctly and cause problems.
The feature works well, there is no evidence anywhere that there are problems with this feature and years of Kotlin experience have not turned up any known cases where this feature backfires. If there is a problem with a missing ; the compiler will report an error.
Searching all of my open-source Kotlin, and our internal rather large Kotlin projects, I find no semi-colons other than the cases above -- and very very few in total. Supporting the notion of "don't use semicolons in Kotlin" as the rule.
However, it is possible that you can intentionally contrive a case where the compiler doesn't report an error because you created code that is valid and has different meaning with and without a semicolon. This would look like the following (a modified version of the answer by #Ruckus):
fun whatever(msg: String, optionalFun: ()->Unit = {}): () -> Unit = ...
val doStuff: () -> Unit = when(x) {
is String -> {
{ doStuff(x) }
}
else -> {
whatever("message") // absence or presence of semicolon changes behavior
{ doNothing() }
}
}
In this case doStuff is being assigned the result of the call to whatever("message") { doNothing() } which is a function of type ()->Unit; and if you add a semicolon it is being assigned the function { doNothing() } which is also of type ()->Unit. So the code is valid both ways. But I have not seen something like this occur naturally since everything has to line up perfectly. The feature suggested emit keyword or ^ hat operator would have made this case impossible, and it was considered but dropped before 1.0 due to strongly opposed opinions and time constraints.

I addition to Jayson Minard's answer, I've run into one other weird edge case where a semicolon is needed. If you are in a statement block that returns a function without using the return statement, you need a semicolon. For example:
val doStuff: () -> Unit = when(x) {
is String -> {
{ doStuff(x) }
}
else -> {
println("This is the alternate"); // Semicolon needed here
{ doNothing() }
}
}
Without the semicolon, Kotlin thinks the { doNothing() } statement is a second argument to println() and the compiler reports an error.

Kotlin seems to mostly infer semicolons eagerly. There seem to be exceptions (as shown in Jayson Minard's enum example).
Generally, the type system will catch badly inferred semicolons, but here are some cases where the compiler fails.
If an invocation's arguments are in the next line (including the parenthesis), Kotlin will assume that arguments are simply a new parenthesised expression statement:
fun returnFun() : (x: Int) -> Unit {
println("foo")
return { x -> println(x) }
}
fun main(args: Array<String>) {
println("Hello, world!")
returnFun()
(1 + 2) // The returned function is not called.
}
A more common case could be the following, where we have a return with the expression in the next line. Most of the time the type system would complain that there is no return value, but if the return type is Unit, then all bets are off:
fun voidFun() : Unit {
println("void")
}
fun foo() : Unit {
if (1 == 1) return
voidFun() // Not called.
}
fun bar() : Unit {
if (1 == 1)
return
voidFun() // Not called.
}
The bar function could potentially happen, if the return voidFun() wouldn't fit on one line. That said, must developers would simply write the call to the function on a separate line.

Related

How do I specify an ActionListener in Kotlin?

I want to add an ActionListener to a JButton in Kotlin. In Java, I would just write this:
JPanel makeButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
JButton dirButton = new JButton("Change directory");
dirButton.addActionListener(e -> chooseDirectory());
panel.add(dirButton)
return panel;
}
But it's not so simple in Kotlin. I first tried this:
private fun makeButtonPanel() : JPanel {
val panel = JPanel(FlowLayout())
val dirButton = JButton("Choose")
dirButton.addActionListener(e -> chooseDirectory()) // error message here
// ...
}
private fun chooseDirectory() { ... }
But I'm getting this error message:
Type Mismatch
Required: ((ActionEvent!) -> Unit)!
Found: KFunction1<ActionEvent, Unit>
I understand that the ! means that this is a java method with uncertain nullability, but that doesn't help me understand how to write it. All I want it to do is call the chooseDirectory() method. There must be a clean, simple way to do this, but I don't see it.
As you've discovered, you need to use braces ({ }).
This is because braces are a necessary part of defining a lambda in Kotlin.  (That differs from languages like Java and Scala, where the necessary part is the -> or => arrow.  That's because in Kotlin the arrow is optional if there are one or no parameters; if one, the it keyword is used.)
Without the braces, the code would call your chooseDirectory() function, and try to pass its result to addActionListener() — which obviously wouldn't work.
Braces are also sufficient: they're taken as defining a lambda unless you're giving the body of a function or method or an if/when branch.  (Again, this differs from most C/Java-like languages.  In Kotlin, if you just want a block scope, you have to use a construct such as run.)
As for the parentheses, they're optional here.  You could include them if you wanted:
dirButton.addActionListener({ chooseDirectory() })
But Kotlin has a convention that if a function's last parameter is a function, you can pass it after the parens:
dirButton.addActionListener(){ chooseDirectory() }
And if that would make the parens empty, then you can omit them entirely:
dirButton.addActionListener{ chooseDirectory() }
That's to allow functions that look like new language syntax.  For example, you may have met the with function:
with(someObject) {
itsProperty = someValue
}
That's just a perfectly ordinary function, defined in the standard library, and taking a function as its last parameter.  Similarly, repeat:
repeat(10) {
// Some code to be run 10 times…
}
There's one further thing worth mentioning here.  In Kotlin, lambdas are one way to define functions, which are first-class types and can be defined, passed around, and used just like other types.  This differs from Java, which has traditionally used interfaces for those purposes — often interfaces with a Single Abstract Method (‘SAM interfaces’) — and in which lambdas are little more than syntactic sugar for defining an anonymous implementation of such an interface.
As a special case, for interoperability, Kotlin allows a lambda to define an implementation of a Java SAM interface (or, since Kotlin 1.4, of a Kotlin fun interface), instead of a function.
ActionListener is a Java SAM interface, which is why you can use a lambda here.
Okay, I figured it out, and it was pretty simple. I just have to dispense with the parentheses and say
dirButton.addActionListener { chooseDirectory() }
I'm still not clear on when I should use braces instead of parentheses.

What is the difference between require and assert?

With Kotlin 1.3 came a new feature, contracts, and with them the function require(), but it seems pretty similar to assert(). Here is what their KDoc says:
require(value: Boolean): Throws an IllegalArgumentException if the value is false.
assert(value: Boolean): Throws an AssertionError if the value is false and runtime assertions have been enabled on the JVM using the -ea JVM option.
So when should I use require() and when should I use assert()?
require and assert work differently. For this, you need to dive into the code.
assert(condition) calls a different method internally, which is where you see the actual code:
#kotlin.internal.InlineOnly
public inline fun assert(value: Boolean, lazyMessage: () -> Any) {
if (_Assertions.ENABLED) {
if (!value) {
val message = lazyMessage()
throw AssertionError(message)
}
}
}
AFAIK, this ties to the -ea flag; if -ea isn't present (or disabled), assert will not throw an exception.
As a result, this will not compile:
fun something(string: String?){
assert (string != null)
nonNull(string) // Type mismatch
}
fun nonNull(str: String){}
This is where require comes in. require(condition) also calls a different method under the hood. If you replace assert with require, you'll see that smart cast will successfully cast it as non-null, because require is guaranteed to throw an exception if the condition fails.
#kotlin.internal.InlineOnly
public inline fun require(value: Boolean, lazyMessage: () -> Any): Unit {
contract {
returns() implies value
}
if (!value) {
val message = lazyMessage()
throw IllegalArgumentException(message.toString())
}
}
The boolean-only function does the contract too, then calls that method if the contract fails.
Contracts are new, and I am not entirely sure how they work, but this is how I understand it:
The implies keyword is an infix fun; what this does is that it tells the compiler the condition is true if it returns from the method. This helps with auto-casting, like in the example I mentioned earlier. It doesn't actually cause the method to return (or at least that's what my current testing points to), but it's for the compiler.
It's also readable: returning implies condition is true
That's the contact part: the exception here is always thrown, as you can see by the condition. require uses if(!value), where as assert checks if(_Assertions.ENABLED && !value).
This isn't the only use for require though. It can also be used for validation of arguments. I.e. if you have this:
operator fun get(index: Int) : T {
if (index < 0 || index >= size)
throw IllegalArgumentException("Index out of range")
// return here
}
You could replace it with:
operator fun get(index: Int) : T {
require (index >= 0 && index < size) { "Index out of range" }
// return here
}
There are a lot different uses for this, but these are just some examples.
What this means:
assert is like in Java; it is only triggered if assertions are enabled. Using it does not guarantee the condition is met.
require always works, regardless of VM flags
Which means require can be used to help the compiler with i.e. smart cast, and it's better to use than assert for making sure arguments are valid. And since it also works regardless of VM flags, it can be used outside debugging cases, as forpas mentioned. If you're making a library written in Kotlin, you can replace argument checking with manual throwing with require, and it will still work. Obviously, this assumes Kotlin 1.3.0, but that's beside the point.
And it can be used internally to ensure smart cast works as expected, but throw an exception if the condition isn't met.
To answer your question though:
Use require when you want to to argument checking, even if it's in production.
Use assert if you're doing local debugging, and have the -ea flag enabled.
Let's say you want a function to calculate n! (factorial) like this:
fun factorial(n: Long): Long {
require(n >= 0) { "Number must not be negative" }
// code
}
In this case require() checks the validity of the argument passed to the function and throws an IllegalArgumentException if the argument is not what it's supposed to be and for debugging you also have the explanatory message.
On the other hand assert() can be used anywhere in your code to make your own specialized checks if runtime assertions have been enabled.
There is also
check(Boolean) throws IllegalStateException when its argument is false,
which is used to check object state.
So each of the above has its own place in your code and you can use it if you find it useful.

Can you concatenate statements at run-time in Kotlin?

I am trying to interface with TeamCity using Kotlin-DSL
In this section of the TC Kotlin guide there is a rather odd looking part where it seems like it causes statements to become concatenated on the fly.
It first defines these:
val linux = Requirements() {
contains("os.name", "linux")
}
val oracle = Requirements() {
equals("db.name", "oracle")
}
val java6 = Requirements() {
contains("env.JAVA_HOME", "1.6")
}
Then does this with those definitions:
buildType {
...
requirements(linux + oracle + java6)
...
}
I know that the above section of code is equivalent to
buildType {
...
requirements {
contains("os.name", "linux")
equals("db.name", "oracle")
contains("env.JAVA_HOME", "1.6")
}
...
}
So I suppose what my question boils down to is what is the return type of the 'Requirements' function that can just be concatenated together? My guess is it is some sort of statement/ function wrapper and Kotlin lets you concatenate these as you go, and the function signature looks like this:
fun Requirements(init: (a: String, b: String) -> UnknownTypeA) : UnknownTypeB
EDIT:
For anyone who is confused when reading this in the future, the calls to Requirements are actually an object initialisation via the Requirements constructor. I do inevitably feel embarrassed for not picking up on this (The casing of the name should have been hint enough!) but I'm making this edit to make it clear to people that it is not a function. Thank you to Hotkey for pointing that out.
First, note that Requirements accepts a function into its constructor. Without knowing what is the type of that function, let's assume it's Context.() -> Unit (a function with receiver of Context, accepting no arguments and returning Unit).
Now, we can naturally overload the plus operator for the Requirements type, so that it returns another Requirements instance that has a function that applies both functions from the operands.
You could do that in your own code in the following way:
class Requirements(val check: Context.() -> Unit)
operator fun Requirements.plus(other: Requirements) =
Requirements { check(); other.check() }

returning the last expression in a block

I am learning the new and very beautiful language Kotlin and everything seems to be very logical and consistent. I only found one thing which seems like an arbitrary exception to the rule than a solid rule. But maybe I lack enough understanding some deeper reasons behind the rule.
I know that in if-else and when statements there are blocks of code, then the last expression is returned. In the next example 1 or 2 are returned depending on the condition - in our case it returns 1.
val x = if (1 < 2) {println("something"); 1} else {println("something else"); 2}
On the other hand this does not hold for any code block. The next line assigns y not to 1 but to the whole block of code as a lambda.
val y = {println("something"); 1}
Similarly in function body, the last expression is not returned. This does not even compile.
fun z() : Int {
println("something")
1
}
So what exactly is the rule? Is it really so arbitrary like: if in if-else or when statement which is used as expression there is a block of code, then the last expression in the block is returned. Otherwise the last expression is not returned to outer scope. Or am I missing something?
you misunderstand the curly brackets {}, when around with all flow-control statement it is just a block, for example:
if (condition) { //block here
}
WHEN the {} is declared separately it is a lambda expression, for example:
val lambda: () -> Int = { 1 }; // lambda
WHEN you want to return a lambda in if-else expression, you must double the curly brackets {} or using parentheses () to distinguish between the block and the lambda expression or make the {} as lambda explicitly, for example:
val lambda1: () -> Int = if (condition) { { 1 } } else { { 2 } };
val lambda2: () -> Int = if (condition) ({ 1 }) else ({ 2 });
val lambda3: () -> Int = if (condition) { -> 1 } else { -> 2 };
If a function does not return any useful value, its return type is Unit. Unit is a type with only one value - Unit. This value does not have to be returned explicitly.
On the other hand, a common function must have a explicit return statement if its return type if not a Unit:
fun z(): Int { return 1; }
Another case is a function return Nothing, the return statement don't allowed at all, because you can't create a Nothing instance, for example:
fun nothing(): Nothing {
return ?;// a compile error raising
}
WHEN a function has only one expression then you can using single-expression function instead, for example:
fun z() = 1;
There is a difference between a lambda block and just a 'normal' block, in your case the "y" is just a lambda that needs to be executed to get the returned value:
val block: () -> Int = { 5 }
val five: Int = { 5 }()
val anotherFive = block()
So if you want a block that acts as a lambda, you can create a lambda and execute it right away with "()". This way, your "z" function would compile like so:
fun z() : Int = {
println("something")
1
}()
(Which, of course, does not make much sense and is not very efficient)
You are absolutely right, V.K. The choice is completely arbitrary. Well, probably not completely arbitrary but related to parsing complexities arising from curly braces being chosen to denote both blocks and lambdas.
Actually, besides the case you make for block expressions, there also is the situation of (simple) blocks: just group of statements enclosed in braces. For example, Java supports (simple) blocks and you can write:
String toBeComputed ; {
// Relatively long sequence of operations here
toBeComputed= resultingValue ;
}
I use this idiom quite frequently because:
It's not always convenient to extract the code into a function.
Like a function, it delimits the code and documents its nature without introducing additional names or comments.
Sometimes it's preferable to initialize two or more variables in tandem and introducing a result-value class with this specific purpose feels like an overkill.
Also like a function it doesn't pollute the outer namespace with temporary variables only used internally.
Anecdotally, as Java does not support block expressions I would write the example as
int y ; {
println("something");
y= 1 ;
}
Other languages (ALGOL and Scala come to my mind) do support block expressions (and in the case of Scala also lambdas, but with a different syntax). In these languages what you proposed (in Scala syntax)
val y= { println("something"); 1 }
is completely valid and does not require () to force a lambda to evaluate (because there is no lambda!).
In conclusion, Kotlin designers did choose to make the language less consistent than ALGOL and Scala in terms of blocks and block expression, probably in favor of convenience.
I hope my long response shows that what you expected from Kotlin was not illogical, just not the case because of some language design choice. The principle of less surprise did not work this time.

final or val function parameter or in Kotlin?

Why does Kotlin removed the final or val function parameter which is very useful in Java?
fun say(val msg: String = "Hello World") {
msg = "Hello To Me" // would give an error here since msg is val
//or final
...
...
...
}
Kotlin function parameters are final. There is no val or final keyword because that's the default (and can't be changed).
After Kotlin M5.1 support of mutable parameters removed, In earlier versions that can be achieve using
fun foo(var x: Int) {
x = 5
}
According to Kotlin developers, main reasons of removing this feature are below -
The main reason is that this was confusing: people tend to think that this means passing a parameter by reference, which we do not support (it is costly at runtime).
Another source of confusion is primary constructors: “val” or “var” in a constructor declaration means something different from the same thing if a function declarations (namely, it creates a property).
Also, we all know that mutating parameters is no good style, so writing “val” or “var” infront of a parameter in a function, catch block of for-loop is no longer allowed.
Summary - All parameter values are val now. You have to introduce separate variable for re-initialising. Example -
fun say(val msg: String) {
var tempMsg = msg
if(yourConditionSatisfy) {
tempMsg = "Hello To Me"
}
}
And another reason is that val and var differ by only one letter. This can be very confusing. So for function parameters they removed the option completely. Thus eliminating the confusion in this one small area (yet keeping it everywhere else--go figure).
This decision was made to avoid fragile base class problem. It happens when a small change in base classes (superclasses) makes subclasses malfunction.