https://kotlinlang.org logo
i

iex

02/21/2020, 5:27 PM
Given this code:
Copy code
data class Flow(
    val ids: List<MyId>,
    val steps: MySteps
) {

    constructor(ids: List<MyId>) : this(
        ids,
        MySteps(ids.toSteps(), ids.toSteps().first())
    )
}

data class MySteps(val steps: List<MyStep>, val currentStep: MyStep)
How can I throw an error in the convenience constructor if
ids
is not empty (such that it crashes before
ds.toSteps().first()
?
w

wbertan

02/21/2020, 5:33 PM
Copy code
constructor(ids: List<MyId>) : this(
    ids.ifEmpty { error("Not possible") },
    MySteps(ids.toSteps(), ids.toSteps().first())
)
i

iex

02/21/2020, 5:37 PM
@wbertan awesome, thanks!
s

streetsofboston

02/21/2020, 5:38 PM
Avoid throwing exceptions during construction of an object. Consider creating a factory method/function instead that will either throw that exception or return an instance of that class if all input is correct. For a factory method to look like a constructor, add the
operator fun invoke(...): Flow { ... }
to the `Flow`'s companion object.
2
w

wbertan

02/21/2020, 5:42 PM
@streetsofboston OMG! That is amazing, I wasn’t aware of that! @iex
Copy code
companion object {
        operator fun invoke(ids: List<MyId>): Flow {
            if(ids.isEmpty()) {
                error("Not possible!")
            }
            return Flow(
                ids,
                MySteps(ids.toSteps(), ids.toSteps().first())
            )
        }
    }
💯 1
i

iex

02/21/2020, 5:49 PM
@streetsofboston thanks, aware of factory methods... But I don't see how this helps in my particular case.
s

streetsofboston

02/21/2020, 5:53 PM
Copy code
data class Flow private constructor(
    val ids: List<MyId>,
    val steps: MySteps
) {
    companion object {
        operator fun invoke(ids: List<MyId>) : Flow {
            if (ids.isEmpty()) error("....)"
            return Flow(ids, MySteps(ids.topSteps(), ids.toSteps().first())
        }
    }
}
m

Mike

02/21/2020, 6:00 PM
Are there particular downsides to throwing an exception from the constructor? Or is it more of a style/expectations thing?
s

streetsofboston

02/21/2020, 6:05 PM
It is more like a style but you also avoid the construction of an object, allocation of memory, followed by throwing an exception which will cause the object to be GCed. Also, in the future you may want to return something else, not a
Flow
or throwing an exception, but maybe something more like a
Either<Error, Flow>
. A factory method can be changed to make that happen, a constructor can only return a Flow, never something else
i

iex

02/21/2020, 6:13 PM
avoid memory allocation + flexible return types
k

Kroppeb

02/21/2020, 6:20 PM
Or
Flow?
m

Mike

02/21/2020, 6:30 PM
Thank you for the follow up. Firms up my suspicions. I've been adopting
Either
more and more as I like the separation of business errors from truly exceptional occurrences.
2 Views