I have to perform high-level operations that are always the same: fetch something, and store it locally. The issue I am facing is that the "fetching" and the "storing" deal with different types depending on certain conditions. Given the proximity of the operations, it seemed like code waste to repeat the code for every type, so I tried making it generic... without much success.
Here is a code example that shows the issue I am facing:
suspend fun startFetching(dataPeriodicity: StockDataPeriodicity) {
val stock = stockRepository.insertStock(stockDetails)
.ifDuplicateGetExistingWith { stockRepository.getStockBy(stockDetails.symbol).trust() }
.trust()
val (fetcher, storer) =
if (dataPeriodicity.isIntraday)
stockDataClient::getIntradayPriceDataForStock to intradayTimeSeriesRepository::insertNonExisting
else
stockDataClient::getInterdayPriceDataForStock to interdayTimeSeriesRepository::insertNonExisting
while (true) {
fetchAndStore(stock, dataPeriodicity, fetcher, storer)
delay(fetchingInterval.inWholeMilliseconds)
}
}
private suspend inline fun <reified T, reified R : Comparable<R>> fetchAndStore(
stock: Stock,
periodicity: StockDataPeriodicity,
crossinline fetcher: suspend (symbol: String, periodicity: StockDataPeriodicity) -> T,
storer: (stock: Stock, values: T) -> Either<Throwable, List<Entity<R>>>
) = storer(stock, fetcher(stockDetails.symbol, periodicity))
Here is a screenshot with intellij type inferences and errors for context:
Here are the signatures for getInterdayPriceDataForStock and getIntradayPriceDataForStock
suspend fun getInterdayPriceDataForStock(
stockSymbol: String,
periodicity: StockDataPeriodicity
): Either<Throwable, StockPriceInterdayValues>
suspend fun getIntradayPriceDataForStock(
stockSymbol: String,
periodicity: StockDataPeriodicity
): Either<Throwable, StockPriceIntradayValues>
Here are the signatures for both insertNonExisting functions for the two different repositories
fun insertNonExisting(relatedStock: Stock, values: StockPriceIntradayValues): Either<Throwable, List<IntradayTimeSeries>>
fun insertNonExisting(relatedStock: Stock, values: StockPriceInterdayValues): Either<Throwable, List<InterdayTimeSeries>>
I was expecting that the compiler was able to, with the reified types, understand the types involved in runtime when the "fetchAndStore" call is reached.
It didn't, and don't really know how to untangle it from here.
Already tried to have a shared interface by the return of getIntradayPriceDataForStock
and getInterdayPriceDataForStock
, but it didn't work.
Also, the signature on the storer
that looks like {type1 & type2}
sounds fishy for me.
Bottom-line: I tried my best with my knowledge of generics but I guess I am missing something. Any help is appreciated.