Why does this Kotlin method have enclosing backticks? - kotlin

What are the backticks used for in the snippet below?
Why add them around the fun is(amount:Int ):Boolean { ... }?
verifier.`is`(amount)

It's because is is a reserved keyword in Kotlin. Since Kotlin is supposed to be interoperable with Java and is is a valid method (identifier) name in Java, the backticks are used to escape the method so that it can be used as a method without confusing it as a keyword. Without it it will not work because it would be invalid syntax.
This is highlighted in the Kotlin documentation:
Escaping for Java identifiers that are keywords in Kotlin
Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. If a Java library uses a Kotlin keyword for a method, you can still call the method escaping it with the backtick (`) character
foo.`is`(bar)

Useful for tests
Backticks are very useful in tests for long function names:
#Test
fun `adding 3 and 4 should be equal to 7`() {
assertEquals(calculator.add(3, 4), 7)
}
This makes the function names more readable. We can add spaces and other special characters in the function names. However, remember to use it only in tests, it's against the Kotlin coding conventions of the regular code.

It allows you to call a Java method whose name is a Kotlin keyword. It won't work if you leave out the backticks.

The backtick are a "workaround" to allow you to call methods that have a name representing a Kotlin keyword.
See kotlinlang:
Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. If a Java library uses a Kotlin keyword for a method, you can still call the method escaping it with the backtick (`) character

is in list of Kotlin reserved words
To use Kotlin reserved word (such as is or object) for function/class name you should wrap it to backticks

Some of the Kotlin keywords are valid identifiers in Java: in, object, is, etc. If a Java library uses a Kotlin keyword for a method, you can still call the method escaping it with the backtick (`) character
https://kotlinlang.org/docs/reference/java-interop.html

Related

How to shadow member function with a custom Kotlin extension function? (like Kotlin stdlib does)

I am reading Kotlin in Action 2nd edition.
Chapter 3 says:
If the class has a member function with the same signature as an extension function, the member function always takes precedence
At the same the book demonstrates the CharSequence.split Kotlin's stdlib extension function (which API is less confusing than an API of Java's String#split).
The thing I do not understand is how this split extension functions takes precedence on the following call:
"12.345-6.A".split(".") // <-- Kotlin's extension function gets invoked here even though there is a member function on String class in Java with matching signature
The book also leaves the following comment on this case:
Kotlin hides the confusing method and provides as replacements several overloaded extensions named split that have different arguments
How does Kotlin hide a member function? Can I also shadow some member function which I do not like with my custom extension function? Or it is a trick which is only available to Kotlin language developers?
Actually Kotlin has a separate implementation of CharSequence and String.
These kotlin String/Charsequence does not have its split function. Kotlin team has made all those string implementation functions separately with help of extension functions.Your string will be referring to kotlin String instead of Java String.
If you need to create java String, you need to refer String with package like below.
var str : java.lang.String = java.lang.String("a b c")
str.split("")
Here it will always call Java split function.
Even if you create split function for java.lang.String , it will call only member function as you have read.
member function always takes precedence

Does Kotlin allow the use of backtick names for test classes?

Kotlin/JUnit advertise the use of backticked function names for tests. I've discovered that you can also use backticked class names...
But I can't find any reference. Is thing something in the Kotlin specification, or just a "may go away soon" unintended feature?
code example:
#Nested
inner class `when the entity path only specifies one location` {
#BeforeEach
fun setup() {
entity = Entity(
id = "entityid1",
name = "entity1",
type = "type",
team = TeamColor.BLUE,
currentLocation = Location(0.0, 10.0, 0.0),
path = EntityPath(
startTime = "00:00:00",
timeLocation = listOf(
TimeLocation("00:00:00", Location(0.0, 10.0, 0.0)),
)
),
)
}
#Test
fun `it returns the first (only) location`() {
val actualLocation = entityLocator.getEntityLocation(entity, calculation);
val expectedLocation = Location(0.0, 10.0, 0.0)
assertEquals(actualLocation, expectedLocation);
}
}
Backticks are part of the general language syntax: anywhere you can write a name (whether it's a function, class, property, variable or whatever), you can put it in backticks and include almost any characters (except for newlines, or backticks themselves).
(The original use case may have been for interoperability with Java methods having the same names as Kotlin keywords, such as System.out; but it's more generally useful, as shown in the tests you quote.)
It's documented in the language grammar itself — in the definition of Identifier — so it's an intended part of the language, and unlikely to go away!
Update:
But although Kotlin is guaranteed to support backticks for all identifiers, does that mean you should choose names that need them? In most situations, it's not recommended.
The two main places where you might see them are:
Methods, fields, and packages from the Java standard library or from other Java libraries, that are valid in Java but not in Kotlin — usually because they're reserved words in Kotlin. (For example: System.out, and Mockito's when method.) Backticks are of course necessary for these, as there's no other way to access them from Kotlin.
Method names in unit tests, as demonstrated in this question. This is a matter of style. Some people like long method names with embedded spaces and punctuation, that describe what's being tested in plain English; they also like test methods that look unmistakably different from the code being tested. Other people find them ugly, awkward, and hard to read.As gotube says, the Kotlin coding conventions specifically allow test method names with spaces. But they don't require it; you're free to follow the usual conventions if you prefer. And they only allow it for method names, not for names of classes, objects, packages, properties, or local variables — so it's best to stick to the usual conventions for all those other identifiers, even when writing tests.
Kotlin coding convention specifies that backticks are for use in tests only:
Names for test methods
In tests (and only in tests), you can use method names with spaces enclosed in backticks.

how does kotlin allow using minus operator on java time objects

if i do in Kotlin:
val newInstant = Instant.now() - Duration.ofMinutes(10)
it seems to work as expected, ie 10 mins are subtracted from the current time.
However, I want to know how is this possible since Instant is a java class and doesnt implement the operator overloading functions of Kotlin. So what Kotlin mechanism is being used to implement the minus operator in the expression?
Instant has public Instant minus(TemporalAmount amountToSubtract) method, which is used as binary operator -.
Since Java has no way of marking methods for which it makes sense to use the operator syntax, Kotlin allows using any Java methods with the right name and signature as operator overloads and other conventions (invoke() etc.) Calling Java methods using the infix call syntax is not allowed.
https://kotlinlang.org/docs/reference/java-interop.html#operators,
https://kotlinlang.org/docs/reference/operator-overloading.html

How do I replace multiple characters in a String?

How do I replace multiple characters in a String?
Like Java's replaceAll(regex:replacement:) function.
str.replaceAll("[$,.]", "") //java code
This answer is very close but I want to change more than one character at the same time.
[$,.] is regex, which is the expected input for Java's replaceAll() method. Kotlin, however, has a class called Regex, and string.replace() is overloaded to take either a String or a Regex argument.
So you have to call .toRegex() explicitly, otherwise it thinks you want to replace the String literal [$,.]. It's also worth mentioning that $ in Kotlin is used with String templates, meaning in regular strings you have to escape it using a backslash. Kotlin supports raw Strings (marked by three " instead of one) which don't need to have these escaped, meaning you can do this:
str = str.replace("""[$,.]""".toRegex(), "")
In general, you need a Regex object. Aside using toRegex() (which may or may not be syntactical sugar), you can also create a Regex object by using the constructor for the class:
str = str.replace(Regex("""[$,.]"""), "")
Both these signal that your string is regex, and makes sure the right replace() is used.
If you're happy to work with regular expressions, then refer to the accepted answer here. If you're curious as to how you can achieve this without regular expressions, continue reading.
You can use the String.filterNot(predicate:) and Set.contains(element:) functions to define a String.removeAll extension function as follows:
/**
* #param charactersToRemove The characters to remove from the receiving String.
* #return A copy of the receiving String with the characters in `charactersToRemove` removed.
*/
fun String.removeAll(charactersToRemove: Set<Char>): String {
return filterNot { charactersToRemove.contains(it) }
}
You would call on this function as follows: myString.removeAll(setOf('$', '.'))

Escape dot from GString

I would like to learn how to escape dot in GString so groovy (1.8) does not treat it as a part of an variable inside sql.execute. I have the following code:
Map<String, String> dbSettings = [schemaName:"testSchema"];
String myDbPrefix = dbSetting.schemaName + ".";
sql.execute "DELETE FROM ${myDbPrefix}myTable"
And I got this error:
Ignoring groovy.lang.MissingPropertyException: No such property: myTable for class: java.lang.String
Clearly indicating that . was interpreted as part of variable ${myDbPrefix}.
Does escaping the embedded variable help?
  sql.execute "DELETE FROM ${Sql.expand myDbPrefix}myTable"
I got hit by this problem today. GStrings get handled by a special way in GroovySQL. It's mentioned in the javadoc. It does automatic parameter binding.
Each value in the GString will become a parameter (?) which gets set as a JDBC prepared statement parameter.
What a surprise!
I'm going to fix the problem in my application by subclassing the Sql class and overriding the GString handling with plain ".toString()" .
Documented in Groovy wiki:
GString Use Cases - GSQL Another use case for GString is GSQL where
parameters can be passed into SQL statements using this same mechanism
which makes for a neat way to integrate Groovy with other languages
like SQL. GroovySql then converts the expressions to ? and uses a JDBC
PreparedStatement and passes the values in, preserving their types.
If you explicitly want to coerce the GString to a String you can use
the toString() method. Groovy can also automatically coerce GStrings
into Strings for you.