@@ 78,24 78,24 @@ Accepts two forms:
`(@ SomePrototype :some-field)` - Translates into `:some-field`, if
`some-field` is defined on `SomePrototype`.
-`(@ SomePrototype some-object :some-field)` - Asserts (as above) at
-compile time that `some-field` is defined on `SomePrototype`; at
-runtime, checks that `some-object` is a descendent of
-`SomePrototype` and if so, translates to `(some-object :some-field)`.
+`(@ SomePrototype some-object :some-field)` - Asserts (as above) at compile
+time that `some-field` is defined on `SomePrototype`; at runtime, checks that
+`some-object` is a descendent of `SomePrototype` and if so, translates to
+`(some-object :some-field)`.
-[1]: fugue.janet#L797
+[1]: fugue.janet#L851
## Root
**table** | [source][2]
```janet
-@{:_init <function identity> :_meta @{ :prototype-allocations @{} :getters @{} :object-type :prototype :fields () :instance-defaults @{}} :_name "Prototype" :new <function new-from-Root>}
+@{:_init <function identity> :_meta @{ :fields () :getters @{} :instance-defaults @{} :object-type :prototype :prototype-allocations @{}} :_name "Prototype" :new <function new-from-Root>}
```
Root of the Fugue object hierarchy.
-[2]: fugue.janet#L40
+[2]: fugue.janet#L37
## Root*?
@@ 105,8 105,7 @@ Root of the Fugue object hierarchy.
(Root*? obj)
```
-Proto ancestor predicate: return if `obj` is a
-descendent of Root.
+Proto ancestor predicate: return if `obj` is a descendent of Root.
[3]: eval#L-1
@@ 118,8 117,7 @@ descendent of Root.
(Root? obj)
```
-Proto instance predicate: return if `obj` is an
-instance (that is, a direct child) of Root.
+Proto instance predicate: return if `obj` is an instance (that is, a direct child) of Root.
[4]: eval#L-1
@@ 131,12 129,12 @@ instance (that is, a direct child) of Root.
(allocate obj key value)
```
-Allocation-aware put. If `obj` has inherited an allocation to a
-specific prototype for this key, then `fugue/allocate` will put `value`
-at `key` in the appropriate prototype, and it will be inherited by
-all descendents of that prototype.
+Allocation-aware put. If `obj` has inherited an allocation to a specific
+prototype for this key, then `fugue/allocate` will put `value` at `key` in
+the appropriate prototype, and it will be inherited by all descendents of
+that prototype.
-[5]: fugue.janet#L362
+[5]: fugue.janet#L386
## declare-open-multi
@@ 152,7 150,7 @@ Extending an open multimethod (see `extend-multi`) from any other
environment makes the case extension available wherever the
multimethod has been imported.
-[6]: fugue.janet#L676
+[6]: fugue.janet#L723
## defgeneric
@@ 162,12 160,11 @@ multimethod has been imported.
(defgeneric name & rest)
```
-Define a generic function. When this function is called, if the
-first argument has a method corresponding to the name of the
-function, call that object 's method with the arguments. Otherwise,
-evaluate `body`.
+Define a generic function. When this function is called, if the first
+argument has a method corresponding to the name of the function, call that
+object 's method with the arguments. Otherwise, evaluate `body`.
-[7]: fugue.janet#L399
+[7]: fugue.janet#L426
## defmethod
@@ 177,15 174,15 @@ evaluate `body`.
(defmethod name proto args & body)
```
-Simple single-dispatch method definition. Roughly equivalent to
-`put` ing a function directly into a prototype.
+Simple single-dispatch method definition. Roughly equivalent to `put` ing a
+function directly into a prototype.
Defines a few symbols for reference in the body of the method.
- `__parent` - Bound to the parent of `proto`.
- `__super` - Bound to the method at `name` within `__parent`.
-[8]: fugue.janet#L417
+[8]: fugue.janet#L451
## defmulti
@@ 195,13 192,12 @@ Defines a few symbols for reference in the body of the method.
(defmulti name multi-types args & body)
```
-Define a multimethod based on all the arguments passed to the
-function.
+Define a multimethod based on all the arguments passed to the function.
Example usage :
```
-> (defproto Foo ())
+> (defproto Foo nil)
> (defmulti add [Foo] [f] (put f :value 1))
> (defmulti add [:number] [x] (+ x 1))
> (defmulti add [:string] [s] (string s "!"))
@@ 214,17 210,36 @@ Example usage :
"s!"
```
-`defmulti` takes a sequence of type-or-prototypes, and builds a
-function which will check its arguments against those types (as well
-as all other ones specified in other `defmulti` calls to the same
-function name), and execute the function body for the matching type
-signature.
+`defmulti` takes a sequence of *multimethod specifications*, and builds a
+function which will check its arguments against those types (as well as all
+other ones specified in other `defmulti` calls to the same function name),
+and execute the function body for the matching type signature.
-In addition to type names or prototypes, you can use the symbol `_`
-or keyword `:_` as a wildcard that means "match any type". For
-instance,
+A multimethod specification can be any of the following data types:
-```
+- a **keyword** representing the name of a simple or abstract type; for
+instance, `:number` or `:string`. This will match against values of this
+type.
+
+- A **symbol** referring to an existing table. This will match against tables
+which have this table as a prototype.
+
+- The **fallback symbols** `:_` and `_`. These will match against anything.
+
+- A **match specification**, ie, a pattern understood by the `match` macro,
+as long as it isn't one of the above values. This will match against any
+value that would be matched in an execution of `match`. This includes tuples
+with arbitrary predicates.
+
+Multimethod specs match in order of *most specific* to *least specific*; that
+is:
+
+1. Match specifications
+2. Prototypes
+3. Simple types
+4. Fallback
+
+```
repl:2:> (defmulti cat [:string :_] [s1 s2] (string s1 s2))
repl:3:> (cat "hello " "world!")
"hello world!"
@@ 232,23 247,22 @@ repl:4:> (cat "hello " 42)
"hello 42"
repl:5:> (cat 42 "hello")
error: could not apply multimethod <function cat> to args (42 "hello")
- in cat [repl] on line 2, column 1
- in _thunk [repl] (tailcall) on line 5, column 1
+in cat [repl] on line 2, column 1
+in _thunk [repl] (tailcall) on line 5, column 1
```
-Defining a multimethod with the signature `[:string :_]` will match
-on any two arguments if the first one is a string.
+Defining a multimethod with the signature `[:string :_]` will match on any
+two arguments if the first one is a string.
-A multimethod without wilcards will be preferred to one with one in
-the same position. For instance, if we define an additional
-multimethod:
+A multimethod without wilcards will be preferred to one with one in the same
+position. For instance, if we define an additional multimethod:
```
repl:8:> (defmulti cat [:string :number] [s n] (string s " #" n))
```
-Then that more specific method will be preferred and the wildcard
-will be a fallback if the specific one doesn't match:
+Then that more specific method will be preferred and the wildcard will be a
+fallback if the specific one doesn't match:
```
repl:10:> (cat "hello " @"world")
@@ 257,7 271,7 @@ repl:12:> (cat "hello" 100)
"hello #100"
```
-[9]: fugue.janet#L600
+[9]: fugue.janet#L629
## defproto
@@ 271,67 285,66 @@ Object prototype definition.
## Usage
-`name` should be any symbol. The resulting prototype will be
-named after it.
+`name` should be any symbol. The resulting prototype will be named after it.
-`parent-name` is required; it can be an existing prototype, *or*
-some null-ish value. If null-ish (`nil` or `()` should make the most
-sense...) the parent of the prototype will be set to `fugue/Root`.
+`parent-name` is required; it can be an existing prototype, *or* some
+null-ish value. If null-ish (`nil` or `()` should make the most sense...) the
+parent of the prototype will be set to `fugue/Root`.
`fields` should be 0 or more pairs of the following format:
`<field-name> <field-attributes>`
Where `field-name` is a field to define on the prototype and
-`field-attributes` is a struct describing the field. The following
-field attributes are currently recognized:
+`field-attributes` is a struct describing the field. The following field
+attributes are currently recognized:
+
+- `:default`: provide a default value for all new instances of this prototype
+
+- `:init?`: if truthy, then this field will be a required parameter to the
+prototype's constructor
-- `:default`: provide a default value for all new instances of this
-prototype
-- `:init?`: if truthy, then this field will be a required parameter
-to the prototype 's constructor
- `:allocation`: if `:prototype`, then `fugue/allocate` will always act on
the prototype when putting this field.
+
- `:allocate-value`: this field will have this attribute set at the
-prototype, so that any children without their own values will
-inherit it.
-- `:getter`: specify a name for the defined function to access this
-field (by default, has the same name as the field). Specify `false`
-to prevent a getter from being defined.
-
-`defproto` will define a getter function for each of the defined
-fields, unless `:getter` is false.
-
-`defproto` will also create a `:new` method in the created
-prototype. This will take as positional arguments all of the fields
-specified as `init?`, and then accept in `&keys` format any other
-attributes to set on this object.
-
-The special method `:_init` will be called as the last step in the
-`:new` constructor. It can be defined for a prototype (see
-`defmethod`) to take a new instance and to make any arbitrary
-mutations on the instance or prototype as part of object
-instantiation. By default it simply returns the instance.
-
-The value provided to a field's `:default` entry will be inserted
-directly to the instance. Thus, mutable/referenced terms like tables
-and arrays will be shared amongst all instances. In cases where you
-want to insert a new term for each new instance, use the `_init`
-method to put a value at that field.
-
-If `fields` is of an odd length, the last element will be treated as
-a prototype attributes struct. There is currently one valid prototype attribute:
-
-- `:constructor` : Set the name of the defined function that
- calls `:new`. If false, no additional constructor will be
- defined. By default, will be set to `new-<prototype name>`.
+prototype, so that any children without their own values will inherit it.
+
+- `:getter`: specify a name for the defined function to access this field (by
+default, has the same name as the field). Specify `false` to prevent a getter
+from being defined.
+
+`defproto` will define a getter function for each of the defined fields,
+unless `:getter` is false.
+
+`defproto` will also create a `:new` method in the created prototype. This
+will take as positional arguments all of the fields specified as `init?`, and
+then accept in `&keys` format any other attributes to set on this object.
+
+The special method `:_init` will be called as the last step in the `:new`
+constructor. It can be defined for a prototype (see `defmethod`) to take a
+new instance and to make any arbitrary mutations on the instance or prototype
+as part of object instantiation. By default it simply returns the instance.
+
+The value provided to a field's `:default` entry will be inserted directly to
+the instance. Thus, mutable/referenced terms like tables and arrays will be
+shared amongst all instances. In cases where you want to insert a new term
+for each new instance, use the `_init` method to put a value at that field.
+
+If `fields` is of an odd length, the last element will be treated as a
+prototype attributes struct. There is currently one valid prototype
+attribute:
+
+- `:constructor` : Set the name of the defined function that calls `:new`. If
+false, no additional constructor will be defined. By default, will be set to
+`new-<prototype name>`.
---
An example usage:
```
-repl:43:> (fugue/defproto Dog () name {:allocate-value "Fido"})
+repl:43:> (fugue/defproto Dog nil name {:allocate-value "Fido"})
repl:44:> (fugue/defproto Pekingese Dog size {:default "Extremely Small"})
repl:45:> (fugue/defmethod speak Dog [self] (string "My name is " (self :name)))
repl:46:> (fugue/defmethod speak Pekingese [self] (string (prototype-method self) " and I am " (self :size)))
@@ 339,7 352,7 @@ repl:47:> (speak (:new Pekingese))
"My name is Fido and I am Extremely Small"
```
-[10]: fugue.janet#L259
+[10]: fugue.janet#L284
## extend-multi
@@ 354,10 367,10 @@ syntax as `defmulti`.
See that function's documentation for full usage reference.
-Whenever a case is added to `multi`, that case is available
-wherever the multimethod is imported.
+Whenever a case is added to `multi`, that case is available wherever the
+multimethod is imported.
-[11]: fugue.janet#L692
+[11]: fugue.janet#L754
## fields
@@ 370,7 383,7 @@ wherever the multimethod is imported.
Return all the defined fields for `obj` and its prototype
hierarchy.
-[12]: fugue.janet#L50
+[12]: fugue.janet#L45
## get-type-or-proto
@@ 383,7 396,7 @@ hierarchy.
Return the prototype of `obj`, if it has one, otherwise the keyword
output of `type`.
-[13]: fugue.janet#L173
+[13]: fugue.janet#L197
## match
@@ 395,12 408,11 @@ output of `type`.
Prototype-aware version of `match`. Introduces one new case form:
-- `(@ <prototype-name> <dictionary>)`: Will pattern match against an
- instance of `prototype-name`. Additionally, will validate at
- compile-time that every key in `dictionary` is a field that's
- present on the specified prototype.
+- `(@ <prototype-name> <dictionary>)`: Will pattern match against an instance
+of `prototype-name`. Additionally, will validate at compile-time that every
+key in `dictionary` is a field that's present on the specified prototype.
-[14]: fugue.janet#L831
+[14]: fugue.janet#L877
## multimethod-types-match?
@@ 414,7 426,7 @@ Check to see if the types `args` match the sequence `arg-types`,
according to multimethod rules (ie, following prototype membership
and using `:_` as a fallback)
-[15]: fugue.janet#L525
+[15]: fugue.janet#L551
## new-Root
@@ 436,9 448,9 @@ Constructor for Root. Return a new object with Root as the prototype.
(prototype? obj)
```
-Is `obj` the result of a `defproto ` call?
+Is `obj` the result of a `defproto ` call?
-[17]: fugue.janet#L354
+[17]: fugue.janet#L378
## with-slots
@@ 452,16 464,15 @@ Anaphoric macro with transformed getter/setters.
Introduces two useful forms for referring to `obj`.
-It introduces a *reference symbol* - `@` by default
-(see `with-slots-as `to specify the symbol).
+It introduces a *reference symbol* - `@` by default (see `with-slots-as `to
+specify the symbol).
The pattern `(@ <field name>)`, where `<field name>` is a symbol, is
-transformed into `(obj (keyword <field name>))`, if and only if
-`<field name>` is defined for `proto`, so that `(@ name)` or its
-setter form `(set (@ name) foo)` do the right thing.
+transformed into `(obj (keyword <field name>))`, if and only if `<field
+name>` is defined for `proto`, so that `(@ name)` or its setter form `(set (@
+name) foo)` do the right thing.
-The reference symbol by itself is introduces as a reference to
-`obj`.
+The reference symbol by itself is introduces as a reference to `obj`.
Returns `obj`.
@@ 472,15 483,15 @@ Example :
```
repl:2:> (defproto Foo nil name {:default "Jane Doe"})
repl:4:> (with-slots Foo (new-Foo)
- (set (@ name) "Cosmo Kramer")
- (print (@ name))
- (print (Foo? @)))
+(set (@ name) "Cosmo Kramer")
+(print (@ name))
+(print (Foo? @)))
Cosmo Kramer
true
@Foo{:_meta @{:object-type :instance} :name "Cosmo Kramer"}
```
-[18]: fugue.janet#L742
+[18]: fugue.janet#L804
## with-slots-as
@@ 496,5 507,5 @@ Specifies `as` as the reference symbol for `with-slots`.
See `with-slots` documentation for more details.
-[19]: fugue.janet#L779
+[19]: fugue.janet#L840
@@ 24,7 24,7 @@
(defn- base-proto
"Basic prototype table."
- [name defined-fields instance-defaults proto-allocated-fields & kvs]
+ [name defined-fields instance-defaults proto-allocated-fields & rest]
(table
:_meta @{:object-type :prototype
:fields defined-fields
@@ 32,7 32,7 @@
:instance-defaults instance-defaults
:getters @{}}
:_name name
- ;kvs))
+ ;rest))
(def Root
"Root of the Fugue object hierarchy."
@@ 215,11 215,10 @@
"Generate the defn form for the Prototype predicate."
[name]
(let [pred-name (pred-name name)
- pred-docstring (string/format ```
- Proto instance predicate: return if `obj` is an
- instance (that is, a direct child) of %s.
- ```
- (string name))]
+ pred-docstring (string/format
+ (string "Proto instance predicate: return if `obj` is an "
+ "instance (that is, a direct child) of %s.")
+ (string name))]
~(defn ,pred-name
,pred-docstring
[obj]
@@ 238,12 237,10 @@
[name]
(let [pred-name (pred-name name)
rec-pred-name (symbol name "*?")
-
- rec-pred-docstring (string/format ```
- Proto ancestor predicate: return if `obj` is a
- descendent of %s.
- ```
- (string name))]
+ rec-pred-docstring (string/format
+ (string "Proto ancestor predicate: return if `obj` is a "
+ "descendent of %s.")
+ (string name))]
~(defn ,rec-pred-name
,rec-pred-docstring
[obj]
@@ 255,9 252,11 @@
"Generate the init form wrapper."
[name constructor-name]
(when constructor-name
- (let [docstring (string/format "Constructor for %s. Return a new object with %s as the prototype."
- (string name)
- (string name))]
+ (let [docstring (string/format
+ (string "Constructor for %s. Return a new object with %s "
+ "as the prototype.")
+ (string name)
+ (string name))]
~(defn ,constructor-name
,docstring
[& rest]