1

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
    }
}
5
  • 1
    remove the curly brackets: var commonId: CommonIdFactory = MDC.get("someKey") Commented Dec 9, 2021 at 8:37
  • When I do that my IDE says " Type mismatch. Required: CommonIdFactory /* = () → String */ Found: String!" I could change the type Alias to just be a string but I would like for it to be a lambda Commented Dec 9, 2021 at 8:46
  • And you miss closing double quotes: MDC.get("someKey) Commented Dec 9, 2021 at 9:04
  • 1
    well you have to decide what you want. { xxx } is defining a function. This function is stored in commonId. If you call this function via CommonIdFacade().commonId() it will return a String, which is exactly what you describe with () -> String. If you want commonId to just return a String, you have to say so when defining the typealias: typealias CommonIdFactory = String. It's either one or the other. "String" or "function that returns a String" Commented Dec 9, 2021 at 9:46
  • @hello2244 what exactly do you want to set when you set it? A value or a different factory? Commented Dec 9, 2021 at 10:18

1 Answer 1

6

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?

Sign up to request clarification or add additional context in comments.

1 Comment

@hello224 If this answer was helpful for you/correct, please mark it so by clicking the checkmark below its upvote count.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.