hello2244
hello2244

Reputation: 59

Lambda with no parameter is returning function and not result of function

I have this lambda that I would like to return the result of String via CommonIdFacade.commonId, but what is actually returned is the function. MDC.get returns a string

typealias CommonIdFactory =  () -> String
class CommonIdFacade {
    companion object {
        var commonId: CommonIdFactory =  { MDC.get("someKey") }
            internal set
    }
}

Upvotes: 1

Views: 432

Answers (1)

Joffrey
Joffrey

Reputation: 37710

In your code, the type alias says that CommonIdFactory is a function that returns a string, not just a string:

typealias CommonIdFactory =  () -> String

So if you declare commonId as a CommonIdFactory, it will itself be a function that needs to be invoked to get the string.

There are several options depending on how you want to access the variable and set it.

Option 1: String property - get and set as a string

If you want commonId to be a string when you access it, it shouldn't be of type CommonIdFactory, but of type String instead.

class CommonIdFacade {
    companion object {
        var commonId: String = MDC.get("someKey")
            internal set
    }
}

// get value directly
val id = CommonIdFacade.commonId
// set a new value
CommonIdFacade.commonId = "some value"

This would initialize commonId immediately to the value of MDC.get("someKey"), and it will not change unless you set it to a different value. Setting a value will not affect the underlying MDC here, because MDC is only used for the initialization of commonId, then commonId has its own independent value that can be changed at will.

Option 2: Computed string property - recompute the value each time

If what you want is that each access to commonId gets a fresh value from MDC, you should write it in a getter:

class CommonIdFacade {
    companion object {
        var commonId: String
            get() = MDC.get("someKey")
            internal set(value) {
                MDC.set("someKey", value)
            }
}

// get value directly
val id = CommonIdFacade.commonId
// set a new value
CommonIdFacade.commonId = "some value"

In this case you should likely implement the setter in a way that modifies MDC, which may or may not be your intention.

Option 3: Get it as function, set as function

Now, if you do want commonId to be a function, you can declare it as you did, but then you need to access it as a function:

typealias CommonIdFactory =  () -> String
class CommonIdFacade {
    companion object {
        var commonId: CommonIdFactory =  { MDC.get("someKey") }
            internal set
    }
}

// get value by invoking the function
val id = CommonIdFacade.commonId()
// set a different factory
CommonIdFacade.commonId = { SomewhereElse.getValue() } 

Option 4: Get it as string, but set new factories

Last but not least, maybe you want to set different factory functions but access it as a string property nonetheless:

typealias CommonIdFactory =  () -> String
class CommonIdFacade {
    companion object {
        internal var commonIdFactory: CommonIdFactory = { MDC.get("someKey") }

        val commonId: String
            get() = commonIdFactory.invoke()
    }
}

// get the value directly
val id = CommonIdFacade.commonId
// set a different factory
CommonIdFacade.commonIdFactory = { SomewhereElse.getValue() }

In this case you can set new factory functions via a different property, and access the result of the factory via the commonId property.


Side note: if there is no instance-level state in CommonIdFacade, you can declare it as an object itself instead of class, so you don't have to shove everything into its companion object:

object CommonIdFacade {
    internal var commonIdFactory: CommonIdFactory = { MDC.get("someKey") }

    val commonId: String
        get() = commonIdFactory.invoke()
}

Side note 2: mutable globals have a tendency to break things. Do you really need this?

Upvotes: 6

Related Questions