
Structure
Overview
Fan software is structured into three levels of modularity:
- Pod: module of deployment and versioning
- Type: basic unit of object oriented type system
- Slot: fields and methods
Pod
Pods are the top of Fan's namespace as well as the unit of deployment. A pod's name is globally unique and is used to organize the top level of Fan's namespace. Pod names are similar to Java packages or C# namespaces. To guarantee uniqueness, organizations should prefix their pod names using reverse DNS names in camel case. For example a company which owns "acme.com" and wishes to create a pod called "Foo" would name the pod "comAcmeFoo".
Pods are also the fundamental unit of deployment, versioning, and dependency management. In this role pods are like Java JAR files or .NET DLLs (although as of 1.6 Java's module management via JARs is pretty weak). A pod is a standard zip file which bundles the Fan code for the pod's types, meta-data, plus any associated file resources.
The sys::Pod
type is the reflection API for working with pods installed in a given Fan installation. Code examples for common pod operations:
Pod.list // list the pods installed Pod.find("comAcmeFoo") // find a pod (throws exception if not found) Pod.find("comAcmeFoo", false) // find a pod (returns null if not found) myPod.files[`/img/icon.png`] // lookup a resource file in myPod
Type
A Type is an object oriented class which encapsulates state and behavior. Types are contained within pods and identified by a name unique within that pod. The ::
double colon is used to combine the pod name with the type name to create the qualified name or qname. Because pod names are globally unique, a type's qname is also globally unique. For example sys::Str
is the qname of the Str
type which is contained by the sys
pod.
There are two variations of Types in Fan: classes and mixins.
The sys::Type
type is the reflection API for working with types at runtime. Code snippets for common type operations:
someObj.type // get the type of the an object someObj.type.pod // get the pod of a type myPod.types // list the types in myPod myPod.findType("Foo") // find a type within myPod by its simple name Type.find("myPod::Foo") // lookup a type by its qualified name Int# // type literal for sys::Int someType.fits(Num#) // reflective version of is/instanceof operator
Slot
Types encapsulate state and behavior as a collection of slots. Slots are named uniquely within a given type. The .
dot is used to combine the parent type's qname to create the slot's qname. For example sys::Time.now
is the globally unique qualified name which identifies the now
method within the Time
type within the sys
pod.
There are two types of slots:
The sys::Slot
type is the reflection API for working with slots at runtime. Code examples for commonly used slot operations:
someType.slot("xyz") // lookup the slot called xyz on someType Slot.find("myPod::Foo.xyz") // looukp a slot by its qualified name method.call([arg0, arg1]) // invoke method using reflection method.func // the function which implements the method field.get // get a field using reflection
All slots are keyed by a unique name. This means Fan does not support methods overridden by parameter type like Java or C#. Although you may find this to be a drag on occasion, there are a couple features in Fan that make this restriction quite palatable. First method parameters may have defaults - this eliminates the convenience methods commonly used in Java or C# APIs. Second all types subclass from Obj - this eliminates the API bloat required to support all the primitives in an API like java.io.PrintWriter
. Lastly, constructors in Fan are named which eliminates another common requirement for parameter based overloading. The benefit of this restriction is the really cool ability to lookup methods simply by name or qname - this makes reflective programming and dynamic invocation a zillion times simpler.
Method
Methods are the basic unit for encapsulating behavior in Fan. Methods are really just slot wrappers for a function. Every method has a return type and zero or more typed parameters. Methods which don't return an object have a return type of sys::Void
.
The sys::Method
API is used to work with methods reflectively at runtime.
Methods are discussed in depth in the Methods chapter.
Field
Fields are used to model state in a given type. Fields in Fan are composed of three concepts:
- Getter: a method used to access the current value of the field;
- Setter: a method used to change the current value of the field;
- Storage: a storage location in memory for the current value;
Most fields have all three components, but typically the getter and setter is auto-generated by the compiler. Const fields have only storage and no getter or setter. Fan also allows abstract and calculated fields which have a getter and setter, but no storage.
The sys::Field
API is used to work with fields reflectively at runtime.
We'll take a deep dive into fields later in the Fields chapter.