Hey! Another Providers-related question: I'm addin...
# community-support
j
Hey! Another Providers-related question: I'm adding lazy dependencies to the configuration, like:
Copy code
configurations[configurationName].dependencies.addLater(
    myProvider.map { myValue ->
        println("myValue=$myValue")
        return ...
    }
)
And yes, this gets printed 20-30 times when the project is being configured. Is that expected, and I shouldn't interfere with that, or is using a cached provider a good choice here?
v
It is expected. A
map
on a provider (unless
finalizeValue()
or
finalizeValueOnRead()
is used at an appropriate place) is called each time the provider is queried. So if this gets printed 20-30 times, the provider is queried 20-30 times. If what you do is stable and fast, you should probably not care too much. "cached provider" are unfortunately not existing yet. "cached provider" or maybe better "memoized provider" are requested by me in https://github.com/gradle/gradle/issues/25550 together with a way to "fake" them right now for example for expensive calculations.
j
I already have a cachedProvider present and in use:
Copy code
internal inline fun <reified T : Any> cachedProvider(
    objects: ObjectFactory,
    providers: ProviderFactory,
    crossinline value: () -> T,
) = objects
    .property<T>()
    .value(providers.provider { value() })
    .apply {
        disallowChanges()
        finalizeValueOnRead()
    }
but I am reviewing all the code now and started wondering if regular providers (and zips) shouldn't be used instead.
v
Ah, I think I gave you that link already previously, looks very much like an adaption of my code 😄
j
Some of those dependencies read from the file system or perform other calculations.
Yes, that comes from your previous ideas which work great. 🙂
v
My examples in the issue now also support
List
,
Map
, and
Set
, and there is now also
cachedZip
🙂
j
@Vampire I'm looking at your helpers right now and wondering...
Copy code
@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
inline fun <reified T : Any> Project.cachedProvider(
    crossinline block: () -> T?
): Provider<out T> =
    providers.cachedProvider(objects, block)
why
out T
? This causes troubles i.e. when
Copy code
directoryProperty.set(project.cachedProvider {
    File("...")
})
due to
Copy code
[ARGUMENT_TYPE_MISMATCH] Argument type mismatch: actual type is 'Provider<CapturedType(out File)>', but 'Provider<File!>!' was expected.
To fix that, I have to
.map { it }
🙃
v
Hm, I'm not sure I'm following. Assuming
directoryProperty
is a
DirectoryProperty
, then
set
does only accept
File
,
Directory
, or
Provider<out Directory>
.
And if
directoryProperty
is a
Property<File>
, then it also works, because the set parameter is
Provider<? extends T>
in Java-speak, so
Provider<out File>
in Kotlin-speak.
j
Oh gosh, most likely an incorrect class was used when adding all the imports 🤦‍♂️
However, now it complains with something different:
Copy code
e: file:///Users/hsz/Projects/JetBrains/intellij-platform-gradle-plugin/src/main/kotlin/org/jetbrains/intellij/platform/gradle/utils/cache.kt:76:46 Type argument is not within its bounds: should be subtype of 'Any'
And it points to
out T
in
Copy code
@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
inline fun <T, reified S : Any> Provider<out T>.cachedMap(
    project: Project,
    crossinline transformer: (T) -> S?
): Provider<out S> =
    cachedMap(project.objects, transformer)
Actually all of helpers have problem with that.
Making it
T: Any
and
U: Any
helps, but is that expected?
v
Hm, maybe due to the new JSpecify annotations. My code is still in a Gradle 7.6.4 Project where the JSpecify annotations are not there yet. But I also just had them copied into a 9.1.0 build script 5 minutes ago 😕
Ah, I only used IntelliSense, when trying to execute, the same error comes
Yep, with Gradle 8 it works, so most likely due to the new nullability annotations
I wonder that IJ does not show the problem
So I guess you need to add
: Any
to a all
T
declarations
j
And then to
U
But then it complains about
R
v
Ah, IJ does show the problem but just as warning, not error
j
Which already has it
v
R has it, but it complains because it is
R?
I guess
I updated the issue with a variant that compiles against Gradle 9+ API, but it is yet untested, let me know how it goes 🙂
j
Oh, they're folded — that makes code undiscoverable.
v
Yeah, hard UX there. How to present two variants that are quite long. Collapse both? Collapse one? Collapse none? ...? Hardly doable right. :-(
1
Ah, I was able to add a teaser, what do you think now? 🙂
j
Yes, that's better definitely
👍 1