On a `Property<Boolean>` would you rather initiali...
# plugin-development
t
On a
Property<Boolean>
would you rather initialize it with
.convention(false)
or mark it
@Optional
and use
.getOrElse(false)
? (or possibly both!) Does anyone know of a precedent in the built-in tasks? edit: it looks like Gradle doesn't have any optional boolean property, and there are a few occurrences of convention(false) (and convention(true) in the code.
v
Probably depends on situation, for example is it two-state or three-state (true, false, don't care). I could probably imagine use-cases for any of the combinations. Even if you set
.convention(false)
the question is 2- or 3-state, as you even then can unset the property. If it is 2-state, I'd probably not use
@Optional
with
getOrElse
as that reduces cache hit rate, because the cache is from the property state, so you would segregate into three buckets while without
@Optional
it would only be two buckets.
👍 1
💯 1
t
2-state yes. The cache hit situation is probably why Gradle doesn't seem to use
@Optional
+
.getOrElse(false)
either. Thanks
v
I'd also say it is unclean to have the valid states for a two-states property, why should unset be valid if it will just mean false, that is not optional, but having a default value. Having
@Optional
for me implies it is three-state.
👍 1
t
convention IMO. even more so if the property can be read from multiple places or cascade down through a DSL (ie android build variants)
l
+ 1convention.
l
Or simply an algorithms in your buildSrc or build-definitions repo. Something like:
Copy code
/**
 * Creates a [Property] of type T within this extension.
 *
 * @param T The type of the property.
 * @param defaultValue The default value of the property.
 */
protected fun <T : Any> optionalProperty(defaultValue: T): Property<T> =
  PluginAlgorithms.optionalPropertyIn(project, defaultValue)
... which is backed by...
Copy code
/**
 * Creates a [Property] of type T within this extension.
 *
 * @param T The type of the property.
 * @param defaultValue The default value of the property.
 */
@Suppress("UNCHECKED_CAST", "PLATFORM_CLASS_MAPPED_TO_KOTLIN")
internal fun <T : Any> optionalPropertyIn(project: Project, defaultValue: T): Property<T> {

  val nonNullDefaultValue = Validation.validateNotNull(defaultValue, "defaultValue")
  val nonNullProject = Validation.validateNotNull(project, "project")
  val objectFactory = nonNullProject.objects

  val toReturn = when (nonNullDefaultValue::class.java) {
    Boolean::class.java, Boolean::class.javaObjectType, Boolean::class.javaPrimitiveType -> {

      // Boolean requires special handling, since Gradle requires the value to be a java.lang.Boolean object.
      val truthyDefaultValue: java.lang.Boolean = when (defaultValue.toString().toBoolean()) {
        true -> java.lang.Boolean.TRUE as java.lang.Boolean
        else -> java.lang.Boolean.FALSE as java.lang.Boolean
      }

      val booleanProvider = project.provider { truthyDefaultValue } as Provider<out java.lang.Boolean>
      objectFactory.property(java.lang.Boolean::class.java)
        .convention(booleanProvider)
    }

    else -> {
      val tClass = nonNullDefaultValue::class.java as Class<T>
      objectFactory.property(tClass)
        .convention(nonNullDefaultValue)
    }
  }

  return toReturn as Property<T>
}