What's the advantage of creating a one line function that contains a string, that wouldn't be achievable by just assigning a string to a variable? - kotlin

In Kotlin, I understand that a string can be assigned to a function directly, such as:
fun foo(): String = "Hello World"
But you can also assign a String to a variable directly as well:
var foobar: String = "Hello Word"
My question is, why would you ever create a function when you could just create a variable? I can't see the point in the existence of this functionality.

The interesting thing about
fun foo(): String = "Hello World"
is that it is using the expression syntax, and is equivalent to:
fun foo(): String {
return "Hello World"
}
While just returning a constant isn't very useful, using the expression syntax, avoiding the {block} and return statements allows much more concise function definitions in the case where the entire function can be expressed in one expression.
For example, if foo() was a method on a class, you could say hello with a property of that class:
class Hello(var what : String = "World") {
fun foo(): String = "Hello, $what!"
}
fun main() {
val hello = Hello()
println(hello.foo())
hello.what = "Universe"
println(hello.foo())
}
This prints:
Hello, World!
Hello, Universe!

This is more about when to prefer a function v/s a property.
Kotlin coding conventions has a section that describes this.
A property should be preferred over a function when-
the underlying algorithm does not throw
value is cheap to calculate (or caсhed on the first run)
returns the same result over invocations if the object state hasn't changed
In terms of an API use-case, in some cases exposing a function instead of a property might be a good idea as that gives you the scope to change the implementation of this API in future. What might be a hardcoded value today, could be replaced by code that computes the value in future.

It's simple, think about what the word coding means. Coding rules. Rules that are complicated get broken down in rules that are exactly one level below in abstraction, so that the program is as intelligible as possible.
Well, the function name is just one level above the expression. This is even more true in a language as expressive as kotlin where one line can easily be equivalent to several lines of Java.
If you are talking about strings or primitives exclusively then, yes, an attribute is a more natural choice than a function.

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.

Difference between Any type and Generics in Kotlin

Suppose I have the following function definition.
fun<T> parse(a: Any): T = when (a) {
is String -> a
else -> false
}
I guessed it should be valid. However, the IntelliJ IDEA linter shows a type mismatch error
That being said, I would change the return type of my parse function to Any, right? So that, what is the difference between using Any type and Generics in Kotlin? In which cases should use each of those?
I did read the following question but not understood at all about star-projection in Kotlin due to the fact I am quite new.
Your return type it defined as T, but there is nothing assuring that T and a:Any are related. T may be more restrictive than Any, in which case you can't return a boolean or whatever you provided for a.
The following will work, by changing the return type from T to Any:
fun<T> parse(a: Any): Any = when (a) {
is String -> a
else -> false
}
Any alternate option, if you really want to return type T:
inline fun<reified T> parse(a: Any): T? = when (a) {
is T -> a
else -> null
}
Your example does not use T and thus it's nonsense to make it generic anyways.
Think about this: As a client you put something into a function, e.g. an XML-ByteArray which the function is supposed to parse into an Object. Calling the function you do not want to have it return Any (Casting sucks) but want the function return the type of the parsed object. THIS can be achieved with generics:
fun <T> parse(xml: ByteArray): T {
val ctx: JAXBContext = JAXBContext.newInstance()
val any = ctx.createUnmarshaller().unmarshal(ByteArrayInputStream(xml))
return any as T
}
val int = parse<Int>("123".toByteArray())
val string = parse<String>("123".toByteArray())
Look at the method calls: You tell with generics what type is expected to be returned. The code is not useful and only supposed to give you an idea of generics.
I guessed it should be valid
Why would it be? You return a String in one branch and a Boolean in the other. So the common type for the entire when expression is Any and that's what the compiler (and IDEA) says is "found". Your code also says it should be T (which is "required").
Your generic method should work for any T, e.g. for Int, but Any isn't a subtype of Int and so the code isn't valid.
So that, what is the difference between using Any type and Generics in Kotlin?
This is like asking "what is the difference between using numbers and files": they don't have much in common in the first place. You use generics to write code which can work with all types T (or with all types satisfying some constraint); you use Any when you want the specific type Any.

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() }

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.

Infix notation and with(...) does not work as I expected

Consider the following scenario:
I have a class Test
class Test() {
infix fun say(msg: String) = println(msg)
}
and a main method
fun main(args: Array<String>) {
val test = Test()
test say "Hello World!" //Works
with(test) {
say "Goodbye World!" //Does not work
say("Hello again!") //Works
}
}
As you can see I'm testing out the infix notation. Considering with(...) allows you to work with the object passed as parameter in the with block
without having to access its members through the dot notation, I would expect the infix notation to work like I show in my example above.
Unfortunately this does not work, is there a reason why this does not work? Is it a bug or simply a limitation? Or perhaps I am not interpreting the with(...) function correctly?
Infix notation is about the syntax of the way it's used. It works with an object on the left and the parameter on the right.
When using with you no longer have an object token on the left, so the special syntax for infix notation no longer works. You have to fall back to the regular function notation.
This restriction is necessary for the parser to parse the code without conflicts with other syntax.