kdiff 0.6.0
Three ordinary Kotlin shapes that the processor could not handle now work, and each of them failed in a
way the project's own rules forbid: an error inside generated code, an annotation that silently did
nothing, or two diagnostics pointing at each other with no way through.
Added
-
A nullable collection property is compared and applied.
List<E>?,Set<E>?andMap<K, V>?
follow the rule a nullable nested property already followed: a null on one side is oneValueChanged
at the property carrying both sides, two nulls are no change, and two present collections are compared
as that collection always is — by key, by position, by membership or by entry key. Applying mirrors it:
a change at the property sets it wholesale, and a change beneath a null one is reported as
NothingBeneathNull.Before this, such a property made the generated file fail to compile, with a type mismatch in a file
the author had not written. The hand-written route gains it through the same builders —list,
keyedList,setandmapnow accept a nullable property exactly asnesteddid, so no call site
changes. -
An
objectsubclass of a@Diffablesealed type needs no annotation.data object Unpaid : Paymentalongside@Diffable data class Card(...)now compiles and is dispatched on: two references
to one singleton report nothing, and a swap to or from it reports the type change and the sealed
parent's own properties, as any subclass swap does. Applying a change addressed beneath a singleton
reports it as naming a property the type does not have.Before this the shape was a dead end —
@Diffablerejected the object, and the sealed parent required
every subclass to carry it.@Diffableon the object stays an error, and now says the object needs no
annotation of its own. -
A collection whose elements are nullable and reached through a differ is a compile error at the
property, naming the element type and the two ways out, rather than an error inside generated code.
List<String?>is unaffected, because equality is defined for null, and so is everySet. -
Two new runtime helpers,
patchNullableandpatchSingleton, which is the whole of the public API
change. Widening the four collection compare helpers to accept a nullable side is source- and
binary-compatible, so nothing else in the dump moved.
Changed
-
BREAKING —
@DiffKey,@DiffIgnoreand@DiffWithon a property of a class that is not
@Diffablenow fail the build, naming the property and the missing annotation. They are only ever read
off a@Diffableclass, so anywhere else each one silently configured nothing while its author
believed comparison was set up. This is the rule the tracking annotations have carried since0.1.0,
applied to the three that lacked it.Migration: add
@Diffableto the class, or remove the annotation. A module carrying a stray one
compiled before and does not now, which is the point. -
BREAKING —
@DiffWithtogether with@DiffIgnoreon one property is rejected as a conflict: an
ignored property is never compared, so a differ named for it could never run.@DiffKeybeside
@DiffIgnoreis deliberately not a conflict and still compiles — a key identifies the element
while@DiffIgnorekeeps it out of that element's own comparison, which is what you want. -
A change addressed to a nullable nested property that a value change at that same property
replaces wholesale is now reported asNotApplicableToValueinstead of being dropped in silence. The
rebuilt value is unchanged; what changes is thatfailuresaccounts for every change it was given,
which is what the library promises everywhere else. A caller asserting on an emptyfailureslist for
such a diff sees the new entry.The same rule now covers nullable lists, sets and maps, which is where it was noticed: a wholesale
replacement makes the property a value for that application, so the last change at it wins and the
rest could not be used. -
The generated API surface is otherwise unchanged. A class that compiles today regenerates
byte-identically: the nullable-collection wrapper and the singleton branches appear only for shapes
that could not compile before.