**************************************************************************
** title:      Facets
** author:     Brian Frank
** created:    09 Sep 07
** copyright:  Copyright (c) 2007, Brian Frank and Andy Frank
** license:    Licensed under the Academic Free License version 3.0
**************************************************************************

Overview [#overview]
********************
Facets are a mechanism to annotate types and slots with metadata.  Facets
are similar to Java *annotations* or C# *attributes*.  A facet is a serialized
instance of const class declared on a type or slot which implements the
`sys::Facet` mixin.

Facet Classes [#classes]
************************
Facets are defined as normal classes using the 'facet' positional keyword:

  // simple marker facet with no fields
  facet class Indexed {}

  // struct facet with one or more const fields
  facet class Table
  {
    const Str name := ""
    const Bool autoCreate
  }

All facets classes automatically inherit the `sys::Facet` mixin.  Facets
are implied to be [const classes]`Classes#const` which means all their
fields must be const.

Facet classes are not allowed to define their own constructor.  Instead
the compiler will generate one for you.  If your facet has fields, then
it is implied to be [Serializable]`Serialization` and all its fields must
be serializable types.

The classes above will have the following synthetic definitions:

  // marker facet with no instance fields is singleton
  const class Indexed : Facet
  {
    static const Indexed defVal := Indexed()
    private new make() {}
  }

  // struct facet with instance fields gets it-block constructor
  @Serializable
  const class class Table : Facet
  {
    new make(|This|? f) { f?.call(this) }
  }

Annotations [#annotations]
**************************
Any type or slot can be annotated with facets using the '@' symbol:

  @Indexed
  @Table { name = "Employees"; autoCreate = true }
  class Employee {}

Struct facets assign their field values inside curly braces similiar to
an [it-block]`Closures#itBlocks`.  Only simple literal expressions may
be used in facet annotations which the compiler can determine how to
serialize.

Reflection [#reflection]
************************
Facets are available at runtime via the following methods:
  - [Type.facet]`sys::Type.facet`
  - [Type.facets]`sys::Type.facets`
  - [Type.hasFacets]`sys::Type.hasFacet`
  - [Slot.facet]`sys::Slot.facet`
  - [Slot.facets]`sys::Slot.facets`
  - [Slot.hasFacets]`sys::Slot.hasFacet`

Always prefer the 'facet' and 'hasFacet' methods over 'facets' since it is
much more efficient.  Some examples:

  // check if a type is serializable, returns null if not
  Serializable? ser := obj.typeof.facet(Serializable#, false)

  // check if a field is transient
  field.hasFacet(Transient#)

Inheritance [#inheritance]
**************************
You can annotate a facet class with the `sys::FacetMeta` facet to
declare that a type-level facet should be inherited:

  @FacetMeta { inherited = true }
  facet class F {}

  @F class A {}
  class B : A {}

In the example above the class 'B' will inherit the facet 'F'.  Facet
inheritance works on any type (class or mixin) in the [inheritance
hierarchy]`sys::Type.inheritance`.

