I can't seem to find this question yet, but what is the simplest, most-idiomatic way of opening/creating a file, writing to it, and then closing it? Looking at the kotlin.io reference and the Java documentation I managed to get this:
fun write() {
val writer = PrintWriter("file.txt") // java.io.PrintWriter
for ((member, originalInput) in history) { // history: Map<Member, String>
writer.append("$member, $originalInput\n")
}
writer.close()
}
This works, but I was wondering if there was a "proper" Kotlin way of doing this?
A bit more idiomatic. For PrintWriter, this example:
File("somefile.txt").printWriter().use { out ->
history.forEach {
out.println("${it.key}, ${it.value}")
}
}
The for loop, or forEach depends on your style. No reason to use append(x) since that is basically write(x.toString()) and you already give it a string. And println(x) basically does write(x) after converting a null to "null". And println() does the correct line ending.
If you are using data classes of Kotlin, they can already be output because they have a nice toString() method already.
Also, in this case if you wanted to use BufferedWriter it would produce the same results:
File("somefile.txt").bufferedWriter().use { out ->
history.forEach {
out.write("${it.key}, ${it.value}\n")
}
}
Also you can use out.newLine() instead of \n if you want it to be correct for the current operating system in which it is running. And if you were doing that all the time, you would likely create an extension function:
fun BufferedWriter.writeLn(line: String) {
this.write(line)
this.newLine()
}
And then use that instead:
File("somefile.txt").bufferedWriter().use { out ->
history.forEach {
out.writeLn("${it.key}, ${it.value}")
}
}
And that's how Kotlin rolls. Change things in API's to make them how you want them to be.
Wildly different flavours for this are in another answer: https://stackoverflow.com/a/35462184/3679676
Other fun variations so you can see the power of Kotlin:
A quick version by creating the string to write all at once:
File("somefile.txt").writeText(history.entries.joinToString("\n") { "${it.key}, ${it.value}" })
// or just use the toString() method without transform:
File("somefile.txt").writeText(x.entries.joinToString("\n"))
Or assuming you might do other functional things like filter lines or take only the first 100, etc. You could go this route:
File("somefile.txt").printWriter().use { out ->
history.map { "${it.key}, ${it.value}" }
.filter { ... }
.take(100)
.forEach { out.println(it) }
}
Or given an Iterable, allow writing it to a file using a transform to a string, by creating extension functions (similar to writeText() version above, but streams the content instead of materializing a big string first):
fun <T: Any> Iterable<T>.toFile(output: File, transform: (T)->String = {it.toString()}) {
output.bufferedWriter().use { out ->
this.map(transform).forEach { out.write(it); out.newLine() }
}
}
fun <T: Any> Iterable<T>.toFile(outputFilename: String, transform: (T)->String = {it.toString()}) {
this.toFile(File(outputFilename), transform)
}
used as any of these:
history.entries.toFile(File("somefile.txt")) { "${it.key}, ${it.value}" }
history.entries.toFile("somefile.txt") { "${it.key}, ${it.value}" }
or use default toString() on each item:
history.entries.toFile(File("somefile.txt"))
history.entries.toFile("somefile.txt")
Or given a File, allow filling it from an Iterable, by creating this extension function:
fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) {
this.bufferedWriter().use { out ->
things.map(transform).forEach { out.write(it); out.newLine() }
}
}
with usage of:
File("somefile.txt").fillWith(history.entries) { "${it.key}, ${it.value}" }
or use default toString() on each item:
File("somefile.txt").fillWith(history.entries)
which if you had the other toFile extension already, you could rewrite having one extension call the other:
fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) {
things.toFile(this, transform)
}
It mostly looks ok to me. The only thing different I would do is use the "use" extension defined in ReadWrite to auto close the writer.
PrintWriter("file.txt").use {
for ((member, originalInput) in history) { // history: Map<Member, String>
it.append("$member, $originalInput\n")
}
}
At the very minimum, you could use:
FileWriter(filename).use { it.write(text) }
FileWriter is a convenience class for writing character files (provided by Java, and hence available in Kotlin). It extends Closeable, and hence can be used by Kotlin's ".use" extension method.
The .use extension method automatically closes the calling object once the block exits, thus providing an idiomatic way to close the file after it's written.
Some Kotlin magic allows to omit referencing the stream on each read or write call:
fun <T : Closeable, R> T.useWith(block: T.() -> R): R = use { with(it, block) }
File("a.in").bufferedReader().useWith {
File("a.out").printWriter().useWith {
val (a, b) = readLine()!!.split(' ').map(String::toInt)
println(a + b)
}
}
Scanner(File("b.in")).useWith {
PrintWriter("b.out").useWith {
val a = nextInt()
val b = nextInt()
println(a + b)
}
}
try{
val fileWriter = FileWriter("test.txt", true)
fileWriter.write(string+ "\n")
fileWriter.close()
} catch (exception: Exception){
println(exception.message)
}
Example as easy
val path = context!!.filesDir.absolutePath // => /data/user/0/com.example.test/files
File("$path/filename.txt").writeText("hello")
File(requireContext().filesDir, "TodayTaskListChange.txt").writeText("write your test here...")
Related
I have a data structure which has members that are not thread safe and the caller needs to lock the resource for reading and writing as appropriate. Here's a minimal code sample:
class ExampleResource : LockableProjectItem {
override val readWriteLock: ReadWriteLock = ReentrantReadWriteLock()
#RequiresReadLock
val nonThreadSafeMember: String = ""
}
interface LockableProjectItem {
val readWriteLock: ReadWriteLock
}
fun <T : LockableProjectItem, Out> T.readLock(block: T.() -> Out): Out {
try {
readWriteLock.readLock().lock()
return block(this)
} finally {
readWriteLock.readLock().unlock()
}
}
fun <T : LockableProjectItem, Out> T.writeLock(block: T.() -> Out): Out {
try {
readWriteLock.writeLock().lock()
return block(this)
} finally {
readWriteLock.writeLock().unlock()
}
}
annotation class RequiresReadLock
A call ExampleResource.nonThreadSafeMember might then look like this:
val resource = ExampleResource()
val readResult = resource.readLock { nonThreadSafeMember }
To make sure that the caller is aware that the resource needs to be locked, I would like the IDE to issue a warning for any members that are annotated with #RequiresReadLock and are not surrounded with a readLock block. Is there any way to do this in IntelliJ without writing a custom plugin for the IDE?
I think this is sort of a hack, but using context receivers might work. I don't think they are intended to be used in this way though.
You can declare a dummy object to act as the context receiver, and add that as a context receiver to the property:
object ReadLock
class ExampleResource : LockableProjectItem {
override val readWriteLock: ReadWriteLock = ReentrantReadWriteLock()
// properties with context receivers cannot have a backing field, so we need to explicitly declare this
private val nonThreadSafeMemberField: String = ""
context(ReadLock)
val nonThreadSafeMember: String
get() = nonThreadSafeMemberField
}
Then in readLock, you pass the object:
fun <T : LockableProjectItem, Out> T.readLock(block: context(ReadLock) T.() -> Out): Out {
try {
readWriteLock.readLock().lock()
return block(ReadLock, this)
} finally {
readWriteLock.readLock().unlock()
}
}
Notes:
This will give you an error if you try to access nonThreadSafeMember without the context receiver:
val resource = ExampleResource()
val readResult = resource.nonThreadSafeMember //error
You can still access nonThreadSafeMember without acquiring a read lock by doing e.g.
with(ReadLock) { // with(ReadLock) doesn't acquire the lock, just gets the context receiver
resource.nonThreadSafeMember // no error
}
But it's way harder to accidentally write something like this, which I think is what you are trying to prevent.
If you call another function inside readLock, and you want to access nonThreadSafeMember inside that function, you should mark that function with context(ReadLock) too. e.g.
fun main() {
val resource = ExampleResource()
val readResult = resource.readLock {
foo(this)
}
}
context(ReadLock)
fun foo(x: ExampleResource) {
x.nonThreadSafeMember
}
The context receiver is propagated through.
I currently face the problem of correctly closing resources that never leave their containing Either.
The relevant code looks something like this:
object SomeError
class MyRes : AutoCloseable { [...] }
fun createRes(): Either<SomeError, MyRes> { [...] }
fun extractData(res: MyRes): String { [...] }
fun theProblem(): Either<SomeError, String> {
return createRes()
.map { extractData(it) }
}
What is the most idiomatic way of closing the created MyRes? Closing it before that map prevents extractData from accessing it, and after the map I can't access it anymore via Either's operations. Closing it in extractData severely limits composability.
Currently I have an external List<AutoCloseable> that I iterate over after all the computations, but that can't be the intended way.
I am open to using Arrow Fx (e.g. Resource) if that helps, but I haven't found anything on how to combine Either and Resource in an elegant way.
It's possible to combine the either and Resource safely.
object SomeError
class MyRes : AutoCloseable { [...] }
fun createRes(): Resource<Either<SomeError, MyRes>> { [...] }
fun extractData(res: MyRes): String { [...] }
suspend fun solution(): Either<SomeError, String> = either {
createRes().use { either: Either<SomeError, MyRes> ->
val res = either.bind()
val string = extractData(res)
// call other Either code + `bind()` safely here
[...]
} // <-- MyRes will automatically close here
}
If in this code you encounter Either.Left and you call bind() on it the Resource will first close, because we jump outside of use, and then either will return the encountered Either.Left.
One possible solution I found was wrapping the block passed to map:
fun <B : AutoCloseable, C> andClose(f: (B) -> C): (B) -> C =
{ b: B -> b.use { f(b) } }
fun theProblemSlightlySolved(): Either<SomeError, String> {
return createRes()
.map(andClose { extractData(it) })
}
I'd like to have an applyif to work like:
builder.applyif(<condition expression>) {
builder.set...
}
to be equal with:
builder.apply {
if (<condition expression>) {
builder.set...
}
}
Is that possible?
Yes, of course. You can nearly program anything, but don't reinvent the wheel. Look at the bottom of the answer to see a standard Kotlin approach without own extension function(s) which may already suffice your needs (not exactly applyIf though).
Now, however, lets see how an applyIf might be implemented:
inline fun <T> T.applyIf(predicate: T.() -> Boolean, block: T.() -> Unit): T = apply {
if (predicate(this))
block(this)
}
Don't forget the inline if you are implementing extension functions with lambdas.
Here is an example usage of the above.
// sample class
class ADemo {
fun isTrue() = true
}
// sample usage using method references
ADemo().applyIf(ADemo::isTrue, ::println)
// or if you prefer or require it, here without
ADemo().applyIf( { isTrue() } ) {
println(this)
}
If you just want to supply a boolean instead, you can use the following extension function:
inline fun <T> T.applyIf(condition : Boolean, block : T.() -> Unit) : T = apply {
if(condition) block(this)
}
and call it with:
val someCondition = true
ADemo().applyIf(someCondition) {
println(this)
}
And now a possible Kotlin standard way with which more people could be familiar:
ADemo().takeIf(ADemo::isTrue)
?.apply(::println)
// or
ADemo().takeIf { it.isTrue() }
?.apply { println(this) }
If they do remember (I actually didn't until I saw Marko Topolniks comment) they should immediately know what's going on.
However, if you require the given value (i.e. ADemo()) after calling takeIf this approach might not work for you as the following will set the variable to null then:
val x = ADemo().takeIf { false }
?.apply { println(this) /* never called */ }
// now x = null
whereas the following will rather set the variable to the ADemo-instance:
val x = ADemo().applyIf(false) { println(this) /* also not called */ }
// now x contains the ADemo()-instance
Chaining the builder calls might not be so nice then. Still you can also accomplish this via standard Kotlin functions by combining the takeIf with apply or also (or with, let, run, depending on whether you want to return something or not or you prefer working with it or this):
val x = builder.apply {
takeIf { false }
?.apply(::println) // not called
takeIf { true }
?.apply(::println) // called
}
// x contains the builder
But then again we are nearly there where you were already in your question. The same definitely looks better with applyIf-usage:
val x = builder.applyIf(false, ::println) // not called
.applyIf(true) {
println(this) // called
}
// x contains the builder
Sure you can, you just need an extension function so you can call it on the builder, and you need it to take a Boolean parameter and the lambda to execute.
If you look at the source of the apply function itself, it will help with most of the implementation:
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
Based on this, applyIf can be as simple as:
inline fun <T> T.applyIf(condition: Boolean, block: T.() -> Unit): T {
return if (condition) this.apply(block) else this
}
Usage looks like this:
builder.applyIf(x > 200) {
setSomething()
}
fun <T> T.applyIf(condition: Boolean, block: T.() -> T) = if (condition) block() else this
fun main() {
println("a".applyIf(true) { uppercase() }) // A
println("a".applyIf(false) { uppercase() }) // a
}
In Kotlin DSL example they use plus signs to implement raw content inserting:
html {
head {
title {+"XML encoding with Kotlin"}
}
// ...
}
Is it possible to define "nameless" functions in receiver to be able to write
html {
head {
title {"XML encoding with Kotlin"}
}
// ...
}
Are there any plans to do so in future versions of Kotlin?
Is there such things in languages, other than Kotlin?
I can think of two solutions to your problem:
Make the lambda with receiver return a String:
fun title(init: Title.() -> String) {
val t = Title().apply {
children.add(TextElement(init()))
}
children.add(t)
}
You can now call the title as suggested in OP. Actually this seems to be overhead in this particular scenario though and I'd recommend the following.
Create another title method that takes a String directly:
class Head : TagWithText("head") {
fun title(init: Title.() -> Unit) = initTag(Title(), init)
fun title(text: String) {
val t = Title().apply {
children.add(TextElement(text))
}
children.add(t)
}
}
Used like this:
head {
title("XML encoding with Kotlin")
}
To read Stars from a file in the Facebook Hacker Cup's 2016 Boomerang Constelations problem, following extension function can be defined:
fun BufferedReader.readStars(n: Int): Set<Star> {
return Array(n) {
val (l1, l2) = readLine().split(" ").map { it.toInt() }
Star(l1, l2)
}.toHashSet()
}
Code is compact but the values are first read into an array and then converted to a HashSet. Is there a way to directly initialize a HashSet with the size of n and initializator function in Kotlin?
UPDATE: Is there an existing way in standard Kotlin libs?
You can always use apply to initialize objects in-place:
HashSet<Star>(n).apply {
repeat(n) {
val (l1, l2) = readLine()!!.split(' ').map { it.toInt() }
put(Star(l1, l2))
}
}
If that's too inconvenient too type every time, write an extension function:
inline fun <T> createHashSet(n : Int, crossinline fn: (Int) -> T) = HashSet<T>(n).apply {
repeat(n) { add(fn(it)) }
}
Usage:
createHashSet<Star>(n) {
val (l1, l2) = readLine()!!.split(' ').map { it.toInt() }
Star(l1, l2)
}
Since HashSet is a java class so you can only initialize it in a way provided by JDK.
While there's no helper method in Kotlin runtime it's easy to write it yourself like so:
public fun <T> hashSetOf(size: Int, initializer: (Int) -> T): HashSet<T> {
val result = HashSet<T>(size)
0.rangeTo(size - 1).forEach {
result.add(initializer(it))
}
return result
}
As #miensol has pointed out HashSet initialization is limited to the constructors made available by the JDK. Kotlin has added a hashSetOf function which initializes an empty HashSet and then adds the specified elements to it.
To avoid first reading the values into an array you can use a kotlin.Sequence who's "values are evaluated lazily":
fun BufferedReader.readStars(n: Int): Set<Star> {
return lineSequence().take(n).map {
val (l1, l2) = it.split(" ").map { it.toInt() }
Star(l1, l2)
}.toHashSet()
}
It seems like you are asking an XY question (http://xyproblem.info/). You really want to know how to write readStars in the most efficient way, but instead you ask about HashSet. I think #mfulton26 answers your question as well depending on what is being asked.
Here is the answer for "how do I write this in the most efficient way:"
You have two options. First, a version that auto-closes the stream at the end:
fun BufferedReader.readStars(n: Int): Set<Star> {
return use {
lineSequence().map { line ->
val idx = line.indexOf(' ')
Star(line.substring(0, idx).toInt(), line.substring(idx + 1).toInt())
}.toSet()
}
}
And second, a version that does not:
fun BufferedReader.readStars(n: Int): Set<Star> {
return lineSequence().map { line ->
val idx = line.indexOf(' ')
Star(line.substring(0, idx).toInt(), line.substring(idx+1).toInt())
}.toSet()
}
Neither version creates an array, neither do they make copies of data. They stream the data through a sequence which creates the Set and fills it directly.
Other notes
No need to use split if you are really concerned about allocations and performance. Just use indexOf(char) and split the string yourself using substring.
If you do a split, then please use split(char) not split(String) when you are looking to split on a char