logo

class

sys::Type

sys::Obj
  sys::Type
//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   4 Jan 06  Brian Frank  Creation
//

**
** Type defines the contract of an Obj by the slots its supports.
** Types model the inheritance relationships and provide a mapping
** for all the slots both inherited and declared.  You can create
** new types at runtime via the `Type.makeDynamic` constructor.
**
class Type
{

//////////////////////////////////////////////////////////////////////////
// Management
//////////////////////////////////////////////////////////////////////////

  **
  ** Find a Type by it's qualified name "pod::Type".  If the type
  ** doesn't exist and checked is false then return null, otherwise
  ** throw UnknownTypeErr.
  **
  static Type find(Str qname, Bool checked := true)

  **
  ** Find all the types annotated with the specified facet name/value
  ** pair.  The facet name must be declared as an indexed facet
  ** by an installed pod, otherwise Err is thrown.  Return an empty
  ** list of no matches found.
  **
  ** If 'facetVal' is a 'Type', then you may pass 'true' for 'options'
  ** to check 'facetVals' inheritance hierarchy.
  **
  ** See [Facet Indexing]`docLang::TypeDatabase#facetIndexing` for details.
  **
  static Type[] findByFacet(Str facetName, Obj facetVal, Obj options := null)

//////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////

  **
  ** Make a dynamic type which implements the specified list of existing
  ** types.  Only one 'class' type may be specified and it must be the
  ** first item in the list.  All other types must be mixins.  None of
  ** the 'supers' may be dynamic, abstract, final, or const.
  **
  ** Refer to [Dynamic Types]`docLang::DynamicTypes` for more details.
  **
  ** NOTE: creating dynamics using mixins is not supported yet.
  **
  new makeDynamic(Type[] supers, Str:Obj facets := null)

//////////////////////////////////////////////////////////////////////////
// Naming
//////////////////////////////////////////////////////////////////////////

  **
  ** Parent pod which defines this type.  For parameterized types derived
  ** from List, Map, or Func, this method always returns the sys pod.
  ** Return null if dynamic type.
  **
  ** Examples:
  **   Str#.pod         => sys
  **   acme::Foo#.pod   => acme
  **   acme::Foo[]#.pod => sys
  **
  Pod pod()

  **
  ** Simple name of the type such as "Str".  For parameterized types derived
  ** from List, Map, or Func, this method always returns "List", "Map",
  ** or "Func" respectively.  Return "dynamic" if dynamic type.
  **
  ** Examples:
  **   Str#.name         => "Str"
  **   acme::Foo#.name   => "Foo"
  **   acme::Foo[]#.name => "List"
  **
  Str name()

  **
  ** Qualified name formatted as "pod::name".  For parameterized
  ** types derived from List, Map, or Func, this method always returns
  ** "sys::List", "sys::Map", or "sys::Func" respectively.  Return
  ** "dynamic" if dynamic type.
  **
  ** Examples:
  **   Str#.qname         => "sys::Str"
  **   acme::Foo#.qname   => "acme::Foo"
  **   acme::Foo[]#.qname => "sys::List"
  **
  Str qname()

  **
  ** Return the formal signature of this type.  In the case of non-parameterized
  ** types the signature is the same as qname.  Return "dynamic" if dynamic type.
  ** For parameterized types derived from List, Map, or Func the signature uses
  ** the following special syntax:
  **   List => V[]
  **   Map  => [K:V]
  **   Func => |A,B...->R|
  **
  ** Examples:
  **   Str#.signature => "sys::Str"
  **   Int[]#.signature => "sys::Int[]"
  **   Int:Str#.signature => "[sys::Int:sys::Str]"
  **   Str:Buf[]#.signature => [sys::Str:sys::Buf[]]
  **   |Float x->Bool|#.signature => "|sys::Float->sys::Bool|"
  **   |Float x, Int y|#.signature => |sys::Float,sys::Int->sys::Void|
  **
  Str signature()

//////////////////////////////////////////////////////////////////////////
// Inheritance
//////////////////////////////////////////////////////////////////////////

  **
  ** The direct super class of this type (null for Obj).
  ** Return sys::Obj for all mixin types.
  **
  ** Examples:
  **   Obj#.base        =>  null
  **   Int#.base        =>  sys::Num
  **   OutStream#.base  =>  sys::Obj
  **
  Type base()

  **
  ** Return the mixins directly implemented by this type.
  **
  ** Examples:
  **   Obj#.mixins        =>  [,]
  **   Buf#.mixins        =>  [sys::InStream, sys::OutStream]
  **   OutStream#.mixins  =>  [,]
  **
  Type[] mixins()

  **
  ** Return a recursive flattened list of all the types this type
  ** inherits from.  The result list always includes this type itself.
  ** The result of this method represents the complete list of types
  ** implemented by this type - instances of this type are assignable
  ** to any type in this list.  All types (including mixins) will
  ** include sys::Obj in this list.
  **
  ** Examples:
  **   Obj#.inheritance  =>  [sys::Obj]
  **   Int#.inheritance  =>  [sys::Int, sys::Num, sys::Obj]
  **
  Type[] inheritance()

  **
  ** Does this type implement the specified type.  If true, then
  ** this type is assignable to the specified type (although the
  ** converse is not necessarily true).  This method provides the
  ** same semantics as the 'is' operator, but between two types
  ** rather than an instance and a type.  All types (including
  ** mixin types) fit 'sys::Obj'.
  **
  ** Example:
  **   Float#.fits(Float#) =>  true
  **   Float#.fits(Num#)   =>  true
  **   Float#.fits(Obj#)   =>  true
  **   Float#.fits(Str#)   =>  false
  **   Obj#.fits(Float#)   =>  false
  **
  Bool fits(Type t)

//////////////////////////////////////////////////////////////////////////
// Generics
//////////////////////////////////////////////////////////////////////////

  **
  ** A generic type contains slot signatures which may be parameterized - for
  ** example Map's key and value types are generic as K and V.  Fan supports
  ** three built-in generic types: List, Map, and Func.   A parameterized
  ** type such as Str[] is not a generic type (all of its generic parameters
  ** have been filled in).  User defined generic types are not supported in Fan.
  **
  ** Examples:
  **   Str#.isGeneric   => false
  **   List#.isGeneric  => true
  **   Str[]#.isGeneric => false
  **
  Bool isGeneric()

  **
  ** If this is a parameterized type, then return the map of names to
  ** types.  If this is not a parameterized type return an empty map.
  **
  ** Examples:
  **   Str#.params => [:]
  **   Str[]#.params => ["V":Str, "L":Str[]]
  **   Int:Slot#.params => ["K":Int, "V":Slot, "M":Int:Slot]
  **   |Int x, Float y->Bool|#.params => ["A":Int, "B":Float, "R":Bool]
  **
  Str:Type params()

  **
  ** If this is a generic type, then dynamically create a new parameterized
  ** type with the specified name to type map.  If this type is not generic
  ** then throw UnsupportedErr.  Throw ArgErr if params fails to specify
  ** the required parameters:
  **    List => V required
  **    Map  => K, V required
  **    Func => R required, A-H optional
  **
  ** Examples:
  **   List#.parameterize(["V":Bool#]) => Bool[]
  **   Map#.parameterize(["K":Str#, "V":Obj#]) => Str:Obj
  **
  Type parameterize(Str:Type params)

  **
  ** Convenience for List#.parameterize(["V":this])
  **
  ** Examples:
  **   Int#.toListOf => Int[]
  **   Str[]#.toListOf => Str[][]
  **
  Type toListOf()

//////////////////////////////////////////////////////////////////////////
// Flags
//////////////////////////////////////////////////////////////////////////

  **
  ** Return if this is a dynamic type which was created at
  ** runtime via the `Type.makeDynamic` method.
  **
  Bool isDynamic()

  **
  ** Return if this Type is abstract and cannot be instantiated.  This
  ** method will always return true if the type is a mixin.
  **
  Bool isAbstract()

  **
  ** Return if this Type is a class (as opposed to enum or mixin)
  **
  Bool isClass()

  **
  ** Return if this is a const class which means instances of this
  ** class are immutable.
  **
  Bool isConst()

  **
  ** Return if this Type is an Enum type.
  **
  Bool isEnum()

  **
  ** Return if this Type is marked final which means it may not be subclassed.
  **
  Bool isFinal()

  **
  ** Return if this Type has internal protection scope.
  **
  Bool isInternal()

  **
  ** Return if this Type is a mixin type and cannot be instantiated.
  **
  Bool isMixin()

  **
  ** Return if this Type has public protection scope.
  **
  Bool isPublic()

  **
  ** Return if this Type was generated by the compiler.
  **
  Bool isSynthetic()

//////////////////////////////////////////////////////////////////////////
// Slots
//////////////////////////////////////////////////////////////////////////

  **
  ** List of the all defined fields (including inherited fields).
  **
  Field[] fields()

  **
  ** List of the all defined methods (including inherited methods).
  **
  Method[] methods()

  **
  ** List of the all defined slots, both fields and methods (including
  ** inherited slots).
  **
  Slot[] slots()

  **
  ** Convenience for (Field)slot(name, checked)
  **
  Field field(Str name, Bool checked := true)

  **
  ** Convenience for (Method)slot(name, checked)
  **
  Method method(Str name, Bool checked := true)

  **
  ** Lookup a slot by name.  If the slot doesn't exist and checked
  ** is false then return null, otherwise throw UnknownSlotErr.
  **
  Slot slot(Str name, Bool checked := true)

  **
  ** Add a new slot to a dynamic type.  If not a dynamic
  ** type or a duplicate slot name exists, then throw Err.
  **
  ** Refer to [Dynamic Types]`docLang::DynamicTypes` for more details.
  **
  Void add(Slot slot)

  **
  ** Remove a slot from a dynamic type.  If not a dynamic
  ** type or the slot is inherited, then throw Err.
  **
  ** Refer to [Dynamic Types]`docLang::DynamicTypes` for more details.
  **
  Void remove(Slot slot)

  **
  ** Create a new instance of this Type using a public constructor
  ** called "make".  Throw Err if public constructor "make" is
  ** not available.
  **
  Obj make(Obj[] args := null)

//////////////////////////////////////////////////////////////////////////
// Facets
//////////////////////////////////////////////////////////////////////////

  **
  ** Return all the facets defined for this slot or an empty map
  ** if no facets are defined.  If 'inherited' is true, then this method
  ** returns a map of all the facets of this type's `inheritance`.  If
  ** looking up a facet by name, then use the `facet` method which will
  ** provide better performance.  See the [Facets Doc]`docLang::Facets`
  ** for details.
  **
  Str:Obj facets(Bool inherited := false)

  **
  ** Get a facet by name, or return the 'def' is the facet is not defined.
  ** If 'inherited' is true, then this type's `inheritance` chain is
  ** searched.  See the [Facets Doc]`docLang::Facets` for details.
  **
  Obj facet(Str name, Obj def := null, Bool inherited := false)

//////////////////////////////////////////////////////////////////////////
// Documentation
//////////////////////////////////////////////////////////////////////////

  **
  ** Return the raw fandoc for this type or null if not available.
  ** If there is additional documentation meta-data available it is
  ** included an the start of the string as a series of "@name=value"
  ** lines.
  **
  Str doc()

//////////////////////////////////////////////////////////////////////////
// Conversion
//////////////////////////////////////////////////////////////////////////

  **
  ** Always return signature().
  **
  override Str toStr()

  **
  ** If this type is not dynamic, then return this.  If this
  ** type is dynamic, then NotImmutableErr is thrown.  This method
  ** must be used whenever setting a const Type field.
  **
  Type toImmutable()

//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////

  **
  ** Return the log for this type's pod name.  This is
  ** convenience for 'Log.get(pod.name)'.  Also see `Pod.log`.
  **
  Log log()

}