[id='experimental-traits_{context}']

= Traits

The same fact may have multiple dynamic types which do not fit naturally in a class hierarchy. Traits allow to model this very common scenario. A trait is a type that can be applied to (and eventually removed from) an individual object at runtime. To create a trait rather than a traditional bean, one has to declare it explicitly as in the following example:

[source]
----
declare trait GoldenCustomer
    // fields will map to getters/setters
    code     : String
    balance  : long
    discount : int
    maxExpense : long
end
----

At runtime, this declaration results in an interface, which can be used to write patterns, but can not be instantiated directly. In order to apply a trait to an object, we provide the new `don` keyword, which can be used as simply as this:

[source]
----
when
    $c : Customer()
then
    GoldenCustomer gc = don( $c, GoldenCustomer.class );
end
----

When a trait is applied to a fact, a proxy class is created on the fly (one such class will be generated lazily for each fact/trait class combination). The proxy instance, which wraps the fact and implements the trait interface, is inserted automatically and will possibly activate other rules. An immediate advantage of declaring and using interfaces and getting the implementation proxy is that multiple inheritance hierarchies can be exploited when writing rules. The fact declarations, however, need not implement any of those interfaces statically. To be possible to assign a trait to a fact, the fact type definition must contain the annotation `@Traitable`.

[source]
----
import org.drools.core.factmodel.traits.Traitable;
declare Customer
    @Traitable
    code: String
    balance: long
end
----

The only connection between fact classes and trait interfaces is at the proxy level: a trait is not specifically tied to a fact class. This means that the same trait can be applied to totally different facts. For this reason, the trait does not transparently expose the fields of its fact object. So, when writing a rule using a trait interface, only the fields of the interface will be available, as usual. However, any field in the interface that corresponds to a fact field, will be mapped by the proxy class:

[source]
----
when
    $o: OrderItem($p: price, $code: custCode)
    $c: GoldenCustomer(code == $code,$a : balance,$d: discount)
then
    $c.setBalance($a - $p*$d);
end
----

In this case, the `code` and `balance` would be read from the underlying `Customer` object. Likewise, the `setAccount` will modify the underlying object, preserving a strongly typed access to the data structures. A hard field is a field that must have the same name and type both in the fact class and all trait interfaces. The name is used to establish the mapping: if two fields have the same name, then they must also have the same declared type. The annotation `@org.drools.core.factmodel.traits.Alias` allows to relax this restriction. If an `@Alias` is provided, its value string will be used to resolve mappings instead of the original field name. `@Alias` can be applied both to traits and core beans.

[source]
----
import org.drools.core.factmodel.traits.*;
declare trait GoldenCustomer
    balance: long @Alias("org.acme.foo.accountBalance")
end

declare Person
    @Traitable
    name: String
    savings: long @Alias("org.acme.foo.accountBalance")
end

when
    GoldenCustomer(balance > 1000) // will react to new Person(2000)
then
end
----

More work is being done on relaxing this constraint (see the experimental section on "logical" traits later). Now, one might wonder what happens when a fact class does NOT provide the implementation for a field defined in an interface. We call hard fields those trait fields which are also fact fields and thus readily available, while we define soft those fields which are NOT provided by the fact class. Hidden fields, instead, are fields in the fact class not exposed by the interface.

So, while hard field management is intuitive, there remains the problem of soft and hidden fields. Hidden fields are normally only accessible using the fact class directly. However, one can also use the "fields" `Map` on a trait interface to access a hidden field. If the field can't be resolved, `null` will be returned. Notice that this feature is likely to change in the future.

[source]
----
when
    $sc: GoldenCustomer(fields["age"] > 18)  // age is declared by the underlying fact class, but not by GoldenCustomer
then
----

Soft fields, instead, are stored in a Map-like data structure that is specific to each fact object and referenced by the proxy(es), so that they are effectively shared even when an object has multiple traits assigned.

[source]
----
when
    $sc: GoldenCustomer($c: code, // hard getter
                        $maxExpense: maxExpense > 1000 // soft getter)
then
    $sc.setDiscount(...); // soft setter
end
----

A fact object also holds a reference to all its proxies, so that it is possible to track which traits have been added to an object, using a sort of dynamic "instanceof" operator, which we named `isA`. The operator can accept a `String`, a class literal or a list of class literals. In the latter case, the constraint is satisfied only if all the specified traits have been assigned.

[source]
----
$sc: GoldenCustomer($maxExpense: maxExpense > 1000,
                    this isA "SeniorCustomer",
                    this isA [NationalCustomer.class, OnlineCustomer.class])
----

Eventually, the business logic may require that a trait is removed from a fact object. For this, we provide two options. The first is a "logical don", which will result in a logical insertion of the proxy resulting from the trait assignment. The Truth Maintenance System will ensure that the trait is removed when its logical support is removed.

[source]
----
then
    don($x, // core object
        Customer.class, // trait class
        true // optional flag for logical insertion)
----

The second option is the use of the `shed` keyword, which causes the removal of any type that is a subtype (or equivalent) of the one passed as an argument.

[source]
----
then
    Thing t = shed($x, GoldenCustomer.class)
----

This operation returns another proxy implementing the `org.drools.core.factmodel.traits.Thing` interface, where the `getFields()` and `getCore()` methods are defined. Internally, in fact, all declared traits are generated to extend this interface (in addition to any others specified). This allows to preserve the wrapper with the soft fields which would otherwise be lost.

A trait and its proxies are also correlated in another way. Whenever a fact object is "modified", its proxies are "modified" automatically as well, to allow trait-based patterns to react to potential changes in hard fields. Likewise, whenever a trait proxy (matched by a trait pattern) is modified, the modification is propagated to the fact class and the other traits. Moreover, whenever a `don` operation is performed, the fact object is also modified automatically, to reevaluate any `isA` operation which may be triggered.

Potentially, this may result in a high number of modifications, impacting performance (and correctness) heavily. So two solutions are currently implemented. First, whenever a fact object is modified, only the most specific traits (in the sense of inheritance between trait interfaces) are updated and an internal blocking mechanism is in place to ensure that each potentially matching pattern is evaluated once and only once. So, in the following situation:

[source]
----
declare trait GoldenCustomer end
declare trait NationalGoldenCustomer extends GoldenCustomer end
declare trait SeniorGoldenCustomer extends GoldenCustomer end
----

A modification of an object that is both a `GoldenCustomer`, a `NationalGoldenCustomer` and a `SeniorGoldenCustomer` would cause only the latter two proxies to be actually modified. The first would match any pattern for `GoldenCustomer` and `NationalGoldenCustomer`, the latter would instead be prevented from rematching `GoldenCustomer`, but would be allowed to match `SeniorGoldenCustomer` patterns. It is not necessary, instead, to modify the `GoldenCustomer` proxy since it is already covered by at least one other more specific trait.

The second method, up to the user, is to mark traits as `@PropertyReactive`.
Property reactivity is trait-enabled and takes into account the trait field mappings, so to block unnecessary propagations.

== Cascading traits

*WARNING* : This feature is extremely experimental and subject to changes.

Normally, a hard field must be exposed with its original type by all traits assigned to an object, to prevent situations such as

[source]
----
declare Person
  @Traitable
  name: String
  id: String
end

declare trait Customer
  id: String
end

declare trait Patient
  id: long  // Person can't don Patient, or an exception will be thrown
end
----

Should a `Person` get assigned both `Customer` and `Patient` traits, the type of the hard field `id` would be ambiguous. However, consider the following example, where `GoldenCustomers` refer their best friends so that they become `Customers` as well:

[source]
----
declare Person
  @Traitable(logical = true)
  bestFriend: Person
end

declare trait Customer end

declare trait GoldenCustomer extends Customer
  refers: Customer @Alias("bestFriend")
end
----

Aside from the `@Alias`, a Person-as-GoldenCustomer's best friend may be compatible with the requirements of the trait `GoldenCustomer`, provided that they are some kind of `Customer` themselves. Marking a `Person` as "logically traitable" - i.e. adding the annotation `@Traitable(logical = true)` - will instruct the {RULE_ENGINE} to try and preserve the logical consistency rather than throwing an exception due to a hard field with different type declarations (`Person` vs `Customer`). The following operations would then work:

[source,java]
----
Person p1 = new Person();
Person p2 = new Person();
p1.setBestFriend(p2);
...
Customer c2 = don(p2, Customer.class);
...
GoldenCustomer gc1 = don(p1, GoldenCustomer.class);
...
p1.getBestFriend(); // returns p2
gc1.getRefers(); // returns c2, a Customer proxy wrapping p2
----

Notice that, by the time `p1` becomes `GoldenCustomer`, `p2` must have already become a `Customer` themselves, otherwise a runtime exception will be thrown since the very definition of `GoldenCustomer` would have been violated.

In some cases, however, one may want to infer, rather than verify, that `p2` is a `Customer` by virtue that `p1` is a `GoldenCustomer`. This modality can be enabled by marking `Customer` as "logical", using the annotation `@org.drools.core.factmodel.traits.Trait(logical = true)`. In this case, should `p2` not be a `Customer` by the time that `p1` becomes a `GoldenCustomer`, it will be automatically assigned the trait `Customer` to preserve the logical integrity of the system.

Notice that the annotation on the fact class enables the dynamic type management for its fields, whereas the annotation on the traits determines whether they will be enforced as integrity constraints or cascaded dynamically.

[source]
----
import org.drools.factmodel.traits.*;

declare trait Customer
    @Trait(logical = true)
end
----