This smells funny because of the two calls to startSync():
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (null == dataSnapshot.value) {
aThing.putAll(defaultConfig)
dbRef.setValue(botState) { _, _ -> startSync() }
} else {
startSync()
}
}
Is there a Kotlin friendly way of saying "If X then do Y with callback Z(), otherwise do nothing with immediate callback Z()"? But without having to have Z() twice.
I'm coming from JavaScript, where a Promise.resolve().then... would have fit the bill.
Wouldn't like to argue with #yole, after all he is the author of idioms in Kotlin.
But if you really like something JavaScript like, you could do something like this:
dataSnapshot.value.let {
if (it == null) {
::startSync
}
else {
startSync()
null
}
}?.let {
aThing.putAll(defaultConfig)
dbRef.setValue(botState) { _, _ -> it() }
}
But as you can see, it's not shorter than your version, and actually much more confusing.
Sometimes, imperative way is the right way, I assume.
Another way is to use with and method reference:
with(::startSync) {
if (dataSnapshot.value == null) {
aThing.putAll(defaultConfig)
dbRef.setValue(botState) { _, _ -> this() }
}
else {
this()
}
}
Related
Every so often, I find myself wanting to compute a value for some sort of filter operation, but then wanting to use that value when it's already disappeared into the condition-checking thing.
For instance:
val found = list.firstOrNull { slowConversion(it).isWanted() }
if (found != null) {
something(found, slowConversion(found))
}
or
when {
other_conditions -> other_actions
list.any { it.contains(regex1) } -> something(list.firstOrNull { it.contains(regex1) } ?: "!!??")
}
For the slowConversion() I can work with a sequence mapped to pairs, although the terms first and second kinda confuse things a bit...
val pair = list.asSequence().map { it to slowConversion(it) }.firstOrNull { it.second.isWanted() }
if ( pair != null ) {
something(pair.first, pair.second)
}
or if I only want the conversion,
val converted = list.firstNotNullOfOrNull { slowConversion(it).takeIf { it.isWanted() } }
but the best I can come up with to avoid the when duplication involves moving the action part into the condition part!
fun case(s: List<String>, r: Regex) {
val match = s.firstOrNull { it.contains(r) }?.also { something(it) }
return match != null
}
when {
other_conditions -> other_actions
case(list, regex1) -> true
}
At this point, it seems I should just have a stack of function calls linked together with ||
other_things || case(list, regex1) || case(list, regex2) || catchAll(list)
Is there something better or more concise for either of these?
You can write your first example like this:
for(element in list) {
val result = slowConversion(element)
if(result.isWanted()) {
something(element, result)
break
}
}
This might not look very Kotlin-ish, but I think it's pretty straightforward & easy to understand.
For your second example, you can use the find function:
when {
other_conditions -> other_actions
else -> list.find { it.contains(regex1) }?.let(::something)
}
If you have multiple regexes, just iterate over them,
val regexes = listOf(regex1, regex2, ...)
for(regex in regexes) {
val element = list.find { it.contains(regex1) } ?: continue
something(element)
break
}
My apologies for the bad title, I'm fairly new to callbacks and I'm not sure how to explain what I'm trying to achieve.
I have a class called MyClass that has a function connectToService inside of it.
The function connectToService does some calculations and then calls a function with a callback, like this:
fun connectToService() {
//Whatever calculations
val a = 7
var b = 3
var c = a + b
val token = MyToken()
token.actionCallback = object: SuperSecretObject {
override fun onSuccess(asyncActionToken: MyToken) {
c++
}
override fun onFailure(asyncActionToken: MyToken) {
c--
}
}
}
I want to create another class, YourClass which creates an object of MyClass and then calls the connectToService function. When the connectToService function finishes either the onSuccess or onFailurefunctions, I want to do something depending on which one was triggered (something different each time, thats why I can't put it inside the onSuccess or onFailure blocks of code).
Something like this:
//Inside `yourClass`
private fun myFunc() {
val yourClassObj = YourClass()
youClassObj.connectToService {
if(onSuccess)
reinventTheWheel()
else
squareIt()
}
youClassObj.connectToService {
combAWatermelon()
}
youClassObj.connectToService {
sharpenMyHammer()
}
}
Is this possible? If so, how can I achieve it? If it's not, what would be the closest solution to this requirement?
EDIT:
More detailed information has been requested, so while I can't provide exact details, I'll do my best to explain what's going on.
I'm basically working on a library to simplify petitions. For example, MQTT petitions. This is something tht resembles what I want to achieve:
/**
* Subscribes to a list of topics and handles the results
*/
fun subscribe(client: MqttAndroidClient, list: MutableList<String>, onMsg: ((String, MqttMessage)->Unit)?=null, conLost: ((Throwable)->Unit)?=null, delComp: ((IMqttDeliveryToken)->Unit)?=null) {
if (client.isConnected) { //Assert connection
for(x in list.iterator()) { //Subscribe to events
client.subscribe(x, 0)
}
client.setCallback(object : MqttCallback {
override fun connectionLost(cause: Throwable) { //Lost connection
Log.i("TAG", "Connection lost")
conLost?.let { it(cause) }
}
#Throws(java.lang.Exception::class)
override fun messageArrived(topic: String, message: MqttMessage) { //Arrived message
Log.i("TAG", "Message arrived: topic => $topic, message => $message")
onMsg?.let { it(topic, message) }
}
override fun deliveryComplete(token: IMqttDeliveryToken) { //Delivery complete
Log.i("TAG", "Delivery complete")
delComp?.let { it(token) }
}
})
}
}
The messageArrived function must have a behaviour that can be customized depending on the app it's being used on.
For example, on one app I want the onMsg() function to be like this:
when(topic) {
"firstTopic" -> {
localVariable++
}
"secondTopic" -> {
localMethod()
}
"thirdTopic" -> {
localClass.variable.method()
}
}
If I'm using it on an Android device, I'd like to be able to update the interface, doing Android API calls, etc.
I'm not sure I got your question correctly. I think what you are looking for is passing lambdas.
fun connectToService(onSucc: ()->Unit, onFail: ()->Unit) {
//Whatever calculations
MyToken().actionCallback = object: SuperSecretObject {
override fun onSuccess(asyncActionToken: MyToken) {
onSucc()
}
override fun onFailure(asyncActionToken: MyToken) {
onFail()
}
}
}
Then you can call the function like this:
connectToService({ /* Something */ }, { /* Something else */ })
In Kotlin, this code compiles:
private fun bar(): Boolean = TODO()
fun works(): Int {
while (true) {
if (bar()) {
return 5
}
}
}
(This is a pared down example of my real code to illustrate the issue I'm running into.)
I actually need to use a file during this loop, and close on exit:
fun openFile(): InputStream = TODO()
fun doesnt_work(): Int {
openFile().use { input ->
while (true) {
if (bar()) {
return 5
}
}
}
} // line 42
This doesn't compile. I get the error:
Error:(42, 5) Kotlin: A 'return' expression required in a function with a block body ('{...}')
I've found two ways to work around this, but both are kind of awkward.
One way is to use a variable to hold the result, and break from the loop right when it's set:
fun works_but_awkward(): Int {
openFile().use { input ->
val result: Int
while (true) {
if (bar()) {
result = 5
break
}
}
return result
}
}
This is especially awkward in my real code, as I have a nested loop, and so I need to use a labelled break.
The other way to work around this is to have a named function for the loop:
fun workaround_with_named_function(): Int {
fun loop(input: InputStream): Int {
while (true) {
if (bar()) {
return 5
}
}
}
return openFile().use { loop(it) }
}
This seems a bit better, but I'm still surprised that the use abstraction is so leaky that I can't do an early return from within a loop. Is there a way to use use with an early return in a loop that's less awkward?
Cause Kotlin compiler isn't smart enough to undestand that use with code inside will return something from the function. The reason of such behavior is inability to guarantee compiler that lambda will be called exactly once.
Another way to workaround this is throwing exception in the end of the function:
fun doesnt_work(): Int {
openFile().use { input ->
while (true) {
if (bar()) {
return 5
}
}
}
throw IllegalStateException("Something goes wrong")
}
P.S. I am not sure, but seems it can be compiled without any hacks when contract system will be added to Kotlin. And it is probably going to be in version 1.3
This should work.
fun openFile(): InputStream = TODO()
fun doesnt_work(): Int {
return openFile().use { input ->
while (true) {
if (bar()) {
return#use 5
}
}
-1 // unreachable return value
// just to help Kotlin infer the return type
}
}
Remember, use is a function whose return value is exactly the same with the return value of the lambda. So returning the value (here it's 5) in the lambda and return the return value of use should work.
Also, if I were you, I'll write the function like this:
fun doesnt_work() = openFile().use { input ->
while (true) if (bar()) return#use 5
-1
}
I am looking for an idiomatic way to return if not null a variable in Kotlin. For example, I would like something such as:
for (item in list) {
getNullableValue(item).? let {
return it
}
}
But it's not possible to return inside a let block in Kotlin.
Is there a good way to do this without having to do this:
for (item in list) {
val nullableValue = getNullableValue(item)
if (nullableValue != null) {
return nullableValue
}
}
Not sure if this would be called idiomatic, but you could do this:
val nullableValue = list.find { it != null }
if (nullableValue != null) {
return nullableValue
}
Edit:
Based on s1m0nw1's answer, you can probably reduce it to this:
list.find { it != null }?.let {
return it
}
It is possible to return from let, as you can read in the documentation:
The return-expression returns from the nearest enclosing function, i.e. foo. (Note that such non-local returns are supported only for lambda expressions passed to inline functions.)
let() is an inline function and therefore you automatically return from the enclosing function whenever you do return within let, like in this example:
fun foo() {
ints.forEach {
if (it == 0) return // nonlocal return from inside lambda directly to the caller of foo()
print(it)
}
}
To modify the behavior, "labels" can be used:
fun foo() {
ints.forEach lit# {
if (it == 0) return#lit
print(it)
}
}
The "right" idiomatic way of doing this is using the "first" method.
Example:
val x = listOf<Int?>(null, null, 3, null, 8).first { it != null }
His specific example would be
return list.first {getNullableValue(it) != null}
It could be something like:
for (item in list) {
getNullableValue(item)?.also {
return it
}
}
I am assuming the external loop is needed. If that is not the case, Ryba suggested solution should work.
I have a simple method, which just checks if a parameter is empty and then calls one of 2 methods based on a struct field.
How would I test it?
func (cT *customType) someMethod(message string) {
if message == ""{
return
}
if cT.value == nil {
cT.doFunctionOne()
} else {
cT.doFunctionTwo()
}
}
In Javascript, I would create a spy on doFunctionOne() and mock up the object.
Mocking up works well in Go as well, but how would I do the 'spying' part?
Or is there another idiomatic way to test this kind of method?
First: You wouldn't name a method "doFunctionOne" but "methodOne" :-)
If neither doFunctionOne nor doFunctionTwo has any observable effect, then there is absolutely no point in testing it. So we may assume that they do have observable side effect, either on the environment or on the customType they have been invoked on.
Now just test these side effects. This is trivial if both methods do return. If they spin up an endless loop it becomes harder, but still doable.
IMHO there is no need to "test" this method in the sense of "test whether it calls One or Two depending on value": For me this is to lowlevel, too much increasing coverage count for nothing. If you call some method it has to do something (observable effect) and you should check this effect, not the inner workings.
The idiomatic way of mocking an object in Go is to make it explicit. A healthy interface should be testable by itself. So if we have something like this:
type customType struct {
value int
}
func (c customType) doFunctionOne() {
fmt.Println("Method #1")
}
func (c customType) doFunctionTwo() {
fmt.Println("Method #2")
}
func (c customType) someMethod() {
if c.value <= 0 {
c.doFunctionOne()
} else {
c.doFunctionTwo()
}
}
We have to provide a way to change the implementation of doFunctionOne and doFunctionTwo explicitly. We can generalize the someMethod behavior using interfaces:
type customType struct {
myValue int
}
func (c customType) doFunctionOne() {
fmt.Println("Method #1")
}
func (c customType) doFunctionTwo() {
fmt.Println("Method #2")
}
func (c customType) value() int {
return c.myValue
}
type Interface interface {
value() int
doFunctionOne()
doFunctionTwo()
}
func someMethod(i Interface) {
if i.value() <= 0 {
i.doFunctionOne()
} else {
i.doFunctionTwo()
}
}
type customTestingType struct {
t *testing.T
}
func (c customTestingType) doFunctionOne() {
c.t.Log("Working")
}
func (c customTestingType) doFunctionTwo() {
c.t.Error("Not working")
}
func (c customTestingType) value() int {
return 0
}
func TestInterface(t *testing.T) {
someMethod(customTestingType{t})
}
Surely there will be more ways to provide this behavior but it depends on the particular declaration of your type. As an example, you can look at httptest package. That said, if you really want to mock your type in that way (nonidiomatic), you can some unsafe monkey patching:
package main
import (
"fmt"
"reflect"
"github.com/bouk/monkey"
)
type customType struct {
myValue int
}
func (c customType) doFunctionOne() {
fmt.Println("Method #1")
}
func (c customType) doFunctionTwo() {
fmt.Println("Method #2")
}
func (c customType) someMethod() {
if c.myValue <= 0 {
c.doFunctionOne()
} else {
c.doFunctionTwo()
}
}
func main() {
c := customType{0}
monkey.PatchInstanceMethod(reflect.TypeOf(c), "doFunctionOne",
func(c customType) {
fmt.Println("Method #1, but patched")
})
monkey.PatchInstanceMethod(reflect.TypeOf(c), "doFunctionTwo",
func(c customType) {
fmt.Println("Method #2, but patched")
})
c.someMethod()
}
You can add log before each function call.
Inject your own logger implementation, []string for example.
Check the string slice for a matching strings.
But, if you are creating a function factory it would be better if you return the function to the caller and the caller will run the function.
Then testing is straightforward.
Second but, there is only two kind of functions, flow function and logic functions.
You mixed flow and logic in the same function.
Testing difficulty is just one symptom of this bad practice.