Kotlin's multiline string handling is wonderful in so many ways, and it's ability to .trimIndent() allows you to keep a string literal indented with the rest of the code like so:
fun main(args: Array<String>) {
val myString = """
hello
world
""".trimIndent()
println(myString)
Will print out:
hello
world
without the literal indents present in the code. But this breaks down when using Kotlin's powerful string templating system if the value being inserted is multiline:
fun main(args: Array<String>) {
val myString = """
hello
world
""".trimIndent()
println("""
teststring2
$myString
""".trimIndent())
}
will print out
teststring2
hello
world
This appears to happen because the world is on a new line and doesn't receive the indentation that hello gets. Is there an elegant way to handle this?
Here's the first string literal. (To avoid confusion, I'll use underscores to represent spaces.)
____hello
____world
Its trimIndent() call will remove the spaces, leaving it with no indentation, like this:
hello
world
The second string looks like this:
________teststring2
________$myString
Then the $myString will be substituted precisely with the contents of the first:
________teststring2
________hello
world
Note that the indentation that was before $myString remains, giving the spaces you see before the "hello"; but there's no indentation within myString, so you don't see any before "world".
Now, trimIndent() removes “a common minimal indent of all the input lines”. But there's no common indent here, because of the last line. So the second trimIndent() call does nothing.
As to what to do, there are probably several options. If you don't want any indents, then the most obvious would be to remove all indents, not just common ones. (I don't think there's a dedicated function in the standard library, but it should be easy enough to write one. For example, you could do a regular expression replace of "^ *" with "".)
This is a common problem in practice, not trimIndent()'s problem. #gidds has explained it very clearly. If you want to achieve what you want, you can use trimMargin().
fun main(args: Array<String>) {
val myString = """
hello
world
""".trimIndent()
println("""
|teststring2
|$myString
""".trimMargin())
}
Output:
teststring2
hello
world
Related
In Java, now that it supports text blocks, you can do this:
#Schema(description = """
Line one.
Line two.
""")
public void someMethodName() { ... }
In Java, text blocks are compile-time constants and they automatically remove the indents. But in Kotlin, if you do this:
#Schema(description = """
Line one.
Line two.
""")
fun someMethodName() { ... }
you end up with unwanted spaces in front of each line. Unfortunately, you can't use trimMargin() or trimIndent() because they are not compile-time constants. Is there a way to make it look as nice in Kotlin as it does in Java?
Unfortunately for your use case, I don't think so. The point of the triple quote is to provide a way to write "Formatted" text into a string. If Java doesn't behave the same way as Kotlin, then technically it's the odd one out as any other language I've used behaves the same way as Kotlin. Your best alternative would be something like the following:
#Schema(description = "Line one.\n"
+ "Line two.\n"
+ "Line three.")
fun someMethodName() { ... }
The string concatenation will be performed at compile time since it is between literals.
I have tried to debug the next program to understand the execution order, however I'm still confused about the execution order
fun foo(): String{
println("Calculating foo...")
return "foo"
}
fun main(args: Array<String>) {
println("First ${foo()}, Second ${foo()}!")
}
// Result:
//
// Calculating foo...
// Calculating foo...
// First foo, Second foo!
// I though the execution would show something like this:
//
// First Calculating foo...foo,
// Second Calculating foo...foo!
Isn't main the initial function to be executed?
If it is, then println would be the 1st sentence, as such (for me) the execution would start from left to right (am I correct?), so... if it is the first word to be displayed would be First ,then it would be called the foo() function and this would return "foo", that would be extrapolated to string again => ${} ... am I right ?
If not, what I'm misunderstanding ?
Thanks for any clarification.
You can think about it like this
Execute main() function.
Evaluate argument to println() function.
"First ${foo()}, Second ${foo()}!" is using string interpolation, so we need to first interpolate the string.
Interpolate first ${foo()}, by calling foo()
First foo() prints "Calculating foo..."
Interpolate second ${foo()}, by calling foo()
First foo() prints "Calculating foo..."
Now we have the interpolated string First foo, Second foo!
Execute println("First foo, Second foo!")
There are two concepts here :
The string interpolation will take the output of your function to build the output text. The println call in foo() is a side-effect, not included in return value. So, it won't be added to generated string.
println in main function will receive the result of String interpolation. Text is interpreted fully before being passed to println. That's why you see the output as is : to create the final text, kt will execute each string expression first, then builing the entire string to display, and finally pass the ready text to println function.
Code execution order is not strongly bound to the natural reading order. There is operator priority concept, also when executing a function, all its arguments must be evaluated before being passed to it (except for closures/lambda, but that's a more complicated subject). And there'smuch more rules. I can only encourage you to take a general programming courses to discover all these, because there's much to say, it would be tough to include all in a single SO answer.
Kotlin's String templates are resolved statically, and are converted to respective variable/function calls in concatenation with Strings.
A literal like "test ${foo()} test2" will be compiled as "test " + foo() + "test2" in the JVM bytecode.
Basically, your function call,
println("First ${foo()}, Second ${foo()}!")
is chopped down like:
println("First " + foo() + ", Second " + foo() + "!")
This will execute as follows:
println( "First ".plus(foo()).plus(", Second ").plus(foo()).plus("!") )
So first of all both the foo calls have been made after concatenation of all the Strings likewise in the above manner, final String is sent as an argument to the println()
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.
In as many expressions/definitions as possible please.
I'm writing a test function, where after the call fails, the function returns:
`this `fails with` "the state is propagated"`
(with the grave accents surrounding fails with ^ i don't know how to escape, sorry)
You want to use them when something is a Kotlin keyword (like Java's System.in) but you need to call it. Then you can do
System.`in`
instead to make it work.
You can also use this in variables, functions, classes and any other identifiers. There is a small paragraph on this topic on Kotlin's documentation.
Actually, it is more than that.
You can use any class, function, variable, or identifier whose name contains spaces or symbols with grave accents.
class `Class name with spaces` {
fun `method name with spaces, +, -`(`a parameter`: Int) {
val `variable?!` = `a parameter` + 1
println(`variable?!`.toString())
}
}
fun main(args: Array<String>) {
val instance = `Class name with spaces`()
instance.`method name with spaces, +, -`(100)
}
This is a compilable and working code:
This is often used in testing, in order to make the test method names self-explanatory.
class OperationsUnitTest {
#Test
fun `addition should be commutative`() {
...
}
}
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.