standard-combination now takes a dispatch position not a picker

darcs
slava 2006-02-25 06:47:35 +00:00
parent 2691f48493
commit e55a401791
12 changed files with 50 additions and 71 deletions

View File

@ -62,7 +62,7 @@ ARTICLE: "method-combination" "Method combination"
"which methods out of the set of applicable methods are called" "which methods out of the set of applicable methods are called"
} }
"The " { $link POSTPONE: GENERIC: } " parsing word creates a generic word using the " { $emphasis "simple method combination" } ". Most generic words that come up in practice use this method combination:" "The " { $link POSTPONE: GENERIC: } " parsing word creates a generic word using the " { $emphasis "simple method combination" } ". Most generic words that come up in practice use this method combination:"
{ $subsection simple-combination } { $subsection standard-combination }
"The " { $link POSTPONE: G: } " parsing word allows a different method combination to be specified:" "The " { $link POSTPONE: G: } " parsing word allows a different method combination to be specified:"
{ $subsection POSTPONE: G: } { $subsection POSTPONE: G: }
"The simple method combination is a special case of the standard method combination:" "The simple method combination is a special case of the standard method combination:"
@ -179,7 +179,7 @@ GLOSSARY: "delegate" "an object acting as a sink for unhandled method calls on b
ARTICLE: "tuple-delegation" "Delegation" ARTICLE: "tuple-delegation" "Delegation"
"Each tuple can have an optional delegate tuple. Most generic words called on the tuple that do not have a method for the tuple's class will be passed on to the delegate." "Each tuple can have an optional delegate tuple. Most generic words called on the tuple that do not have a method for the tuple's class will be passed on to the delegate."
$terpri $terpri
"More precisely, any generic word using " { $link simple-combination } " delegates, and this includes all generic words defined via the " { $link POSTPONE: GENERIC: } " parsing word." "More precisely, any generic word using " { $link standard-combination } " delegates, and this includes all generic words defined via the " { $link POSTPONE: GENERIC: } " parsing word."
$terpri $terpri
"Factor uses delegation in place of implementation inheritance, but it is not a direct substitute; in particular, the semantics differ in that a delegated method call receives the delegate on the stack, not the original object." "Factor uses delegation in place of implementation inheritance, but it is not a direct substitute; in particular, the semantics differ in that a delegated method call receives the delegate on the stack, not the original object."
{ $warning "Delegation to objects that are not tuples is not fully supported. Generic words support delegation to arbitrary types, as do slot accessors which are built from generic words. However, type-specific primitives do not." } { $warning "Delegation to objects that are not tuples is not fully supported. Generic words support delegation to arbitrary types, as do slot accessors which are built from generic words. However, type-specific primitives do not." }

View File

@ -40,7 +40,7 @@ vectors ;
IN: sequences IN: sequences
G: each ( seq quot -- | quot: elt -- ) G: each ( seq quot -- | quot: elt -- )
[ over ] standard-combination ; inline 1 standard-combination ; inline
M: object each ( seq quot -- ) M: object each ( seq quot -- )
swap dup length [ swap dup length [
@ -54,12 +54,12 @@ M: object each ( seq quot -- )
swapd each ; inline swapd each ; inline
G: find ( seq quot -- i elt | quot: elt -- ? ) G: find ( seq quot -- i elt | quot: elt -- ? )
[ over ] standard-combination ; inline 1 standard-combination ; inline
: find-with ( obj seq quot -- i elt | quot: elt -- ? ) : find-with ( obj seq quot -- i elt | quot: elt -- ? )
swap [ with rot ] find 2swap 2drop ; inline swap [ with rot ] find 2swap 2drop ; inline
G: map [ over ] standard-combination ; inline G: map 1 standard-combination ; inline
M: object map ( seq quot -- seq ) M: object map ( seq quot -- seq )
swap [ dup length [ (map) ] collect ] keep like 2nip ; swap [ dup length [ (map) ] collect ] keep like 2nip ;

View File

@ -4,7 +4,7 @@ IN: sequences
USING: generic kernel lists strings sequences-internals ; USING: generic kernel lists strings sequences-internals ;
G: tree-each* ( obj quot -- | quot: elt -- ) G: tree-each* ( obj quot -- | quot: elt -- )
[ over ] standard-combination ; inline 1 standard-combination ; inline
: tree-each ( obj quot -- | quot: elt -- ) : tree-each ( obj quot -- | quot: elt -- )
[ call ] 2keep tree-each* ; inline [ call ] 2keep tree-each* ; inline

View File

@ -158,7 +158,7 @@ USING: compiler errors generic kernel math memory words ;
: STH d-form 44 insn ; : STHU d-form 45 insn ; : STH d-form 44 insn ; : STHU d-form 45 insn ;
: STW d-form 36 insn ; : STWU d-form 37 insn ; : STW d-form 36 insn ; : STWU d-form 37 insn ;
G: (B) ( dest aa lk -- ) [ pick ] standard-combination ; G: (B) ( dest aa lk -- ) 2 standard-combination ;
M: integer (B) i-form 18 insn ; M: integer (B) i-form 18 insn ;
M: word (B) 0 -rot (B) relative-3 ; M: word (B) 0 -rot (B) relative-3 ;

View File

@ -3,7 +3,7 @@ USING: generic help ;
HELP: define-typecheck "( class generic quot -- )" HELP: define-typecheck "( class generic quot -- )"
{ $values { "class" "a class word" } { "generic" "a generic word" } { "quot" "a quotation" } } { $values { "class" "a class word" } { "generic" "a generic word" } { "quot" "a quotation" } }
{ $description { $description
"Defines a generic word with the " { $link simple-combination } " and having one method on " { $snippet "class" } "." "Defines a generic word with the " { $link standard-combination } " using dispatch position 0, and having one method on " { $snippet "class" } "."
$terpri $terpri
"This creates a definition analogous to the following code:" "This creates a definition analogous to the following code:"
{ $code { $code

View File

@ -2,21 +2,26 @@ IN: generic
USING: arrays errors hashtables kernel kernel-internals lists USING: arrays errors hashtables kernel kernel-internals lists
math namespaces sequences vectors words ; math namespaces sequences vectors words ;
: error-method ( picker word -- method ) : picker ( dispatch# -- quot )
[ no-method ] curry append ; { [ dup ] [ over ] [ pick ] } nth ;
: empty-method ( picker word -- method ) : unpicker ( dispatch# -- quot )
over [ dup ] = [ { [ nip ] [ >r nip r> swap ] [ >r >r nip r> r> -rot ] } nth ;
: error-method ( dispatch# word -- method )
>r picker r> [ no-method ] curry append ;
: empty-method ( dispatch# word -- method )
[ [
[ dup delegate ] % dup unit , error-method , \ ?if , over picker % [ delegate dup ] %
] [ ] make over unpicker over add ,
] [ [ drop ] -rot error-method append , \ if ,
error-method ] [ ] make ;
] if ;
: class-predicates ( picker assoc -- assoc ) : class-predicates ( picker assoc -- assoc )
[ [
first2 >r "predicate" word-prop append r> 2array first2 >r >r picker r> "predicate" word-prop append
r> 2array
] map-with ; ] map-with ;
: sort-methods ( assoc n -- vtable ) : sort-methods ( assoc n -- vtable )
@ -38,22 +43,22 @@ math namespaces sequences vectors words ;
nip car second [ ] nip car second [ ]
] if ; ] if ;
: vtable-methods ( picker alist-seq -- alist-seq ) : vtable-methods ( dispatch# alist-seq -- alist-seq )
dup length [ dup length [
type>class [ swap simplify-alist ] [ car second [ ] ] if* type>class [ swap simplify-alist ] [ car second [ ] ] if*
>r over r> class-predicates alist>quot >r over r> class-predicates alist>quot
] 2map nip ; ] 2map nip ;
: <vtable> ( picker word n -- vtable ) : <vtable> ( dispatch# word n -- vtable )
#! n is vtable size; either num-types or num-tags. #! n is vtable size; either num-types or num-tags.
>r 2dup empty-method \ object bootstrap-word swap 2array >r 2dup empty-method \ object bootstrap-word swap 2array
>r methods >list r> swons r> sort-methods vtable-methods ; >r methods >list r> swons r> sort-methods vtable-methods ;
: small-generic ( picker word -- def ) : small-generic ( dispatch# word -- def )
2dup methods class-predicates >r empty-method r> alist>quot ; 2dup methods class-predicates >r empty-method r> alist>quot ;
: big-generic ( picker word n dispatcher -- def ) : big-generic ( dispatch# word n dispatcher -- def )
[ >r pick % r> , <vtable> , \ dispatch , ] [ ] make ; [ >r pick picker % r> , <vtable> , \ dispatch , ] [ ] make ;
: tag-generic? ( word -- ? ) : tag-generic? ( word -- ? )
"methods" word-prop hash-keys [ types ] map concat "methods" word-prop hash-keys [ types ] map concat
@ -62,18 +67,16 @@ math namespaces sequences vectors words ;
: small-generic? ( word -- ? ) : small-generic? ( word -- ? )
"methods" word-prop hash-size 3 <= ; "methods" word-prop hash-size 3 <= ;
: standard-combination ( word picker -- quot ) : standard-combination ( word dispatch# -- quot )
swap { swap {
{ [ dup tag-generic? ] [ num-tags \ tag big-generic ] } { [ dup tag-generic? ] [ num-tags \ tag big-generic ] }
{ [ dup small-generic? ] [ small-generic ] } { [ dup small-generic? ] [ small-generic ] }
{ [ t ] [ num-types \ type big-generic ] } { [ t ] [ num-types \ type big-generic ] }
} cond ; } cond ;
: simple-combination ( word -- quot )
[ dup ] standard-combination ;
: define-generic ( word -- ) : define-generic ( word -- )
[ simple-combination ] define-generic* ; [ 0 standard-combination ] define-generic* ;
PREDICATE: generic simple-generic ( word -- ? ) PREDICATE: generic standard-generic
"combination" word-prop [ simple-combination ] = ; 1 swap "combination" word-prop ?nth
\ standard-combination eq? ;

View File

@ -1,45 +1,24 @@
USING: generic help ; USING: generic help sequences ;
HELP: standard-combination "( word picker -- quot )" HELP: standard-combination "( word dispatch# -- quot )"
{ $values { "word" "a generic word" } { "picker" "a quotation with stack effect " { $snippet "( -- obj )" } } { "quot" "a new quotation" } } { $values { "word" "a generic word" } { "dispatch#" "a dispatch position" } { "quot" "a new quotation" } }
{ $description { $description
"Performs standard method combination:" "Performs standard method combination."
{ $list "Generic words using the standard method combination dispatch on the class of the object at the given stack position, where 0 is the top of the stack, 1 is the object underneath, and 2 is the next one under that. If no suitable method is defined on the class of the dispatch object, the generic word is called on the dispatch object's delegate. If the delegate is " { $link f } ", an exception is thrown."
"the word dispatches on the object produced by the picker,"
"only the method with most specific class is invoked."
}
"There is an additional feature if the picker is " { $snippet "[ dup ]" } ":"
{ $list
"if no suitable method is found, the generic word is called on the object's delegate."
}
} }
{ $examples { $examples
"A generic word for append strings and characters to a sequence, dispatching on the second stack element:" "A generic word for append strings and characters to a sequence, dispatching on the object underneath the top of the stack:"
{ $code { $code
"G: build-string [ over ] standard-combination ;" "G: build-string 1 standard-combination ;"
"M: string build-string swap nappend ;" "M: string build-string swap nappend ;"
"M: integer build-string push ;" "M: integer build-string push ;"
} }
} }
{ $see-also POSTPONE: G: define-generic* } ; { $notes "The " { $link POSTPONE: GENERIC: } " parsing word defines generic words using the standard method combination with dispatch position 0." }
{ $examples "Most generic words in the standard library use this method combination with a dispatch position of 0. A handful of combinators such as " { $link each } " dispatch on position 1, since position 0 (the top of the stack) is a quotation." }
HELP: simple-combination "( word -- quot )" { $see-also POSTPONE: GENERIC: define-generic POSTPONE: G: define-generic* } ;
{ $values { "word" "a generic word" } { "quot" "a new quotation" } }
{ $description
"Performs standard method combination with " { $snippet "[ dup ]" } " as the picker quotation. That is,"
{ $list
"the word dispatches on the top of the stack,"
"only the method with most specific class is invoked,"
"if no suitable method is found, the generic word is called on the object's delegate."
}
}
{ $examples "Most generic words in the standard library use this method combination." }
{ $see-also POSTPONE: GENERIC: define-generic } ;
HELP: define-generic "( word -- )" HELP: define-generic "( word -- )"
{ $values { "word" "a word" } } { $values { "word" "a word" } }
{ $description "Defines a generic word with the " { $link simple-combination } " method combination. If the word is already a generic word, existing methods are retained." } { $description "Defines a generic word with the " { $link standard-combination } " method combination, and a dispatch position of 0." }
{ $see-also POSTPONE: GENERIC: define-generic* } ; { $see-also POSTPONE: GENERIC: define-generic* } ;
HELP: simple-generic f
{ $description "The class of generic words with the " { $link simple-combination } ". They are typically defined by the " { $link POSTPONE: GENERIC: } " parsing word." } ;

View File

@ -10,7 +10,7 @@ GENERIC: dispatching-values ( node word -- seq )
M: object dispatching-values 2drop { } ; M: object dispatching-values 2drop { } ;
M: simple-generic dispatching-values drop node-in-d peek 1array ; ! M: simple-generic dispatching-values drop node-in-d peek 1array ;
M: 2generic dispatching-values drop node-in-d 2 swap tail* ; M: 2generic dispatching-values drop node-in-d 2 swap tail* ;

View File

@ -49,7 +49,7 @@ M: object digit> not-a-number ;
dup >r /mod >digit , dup 0 > dup >r /mod >digit , dup 0 >
[ r> integer, ] [ r> 2drop ] if ; [ r> integer, ] [ r> 2drop ] if ;
G: >base ( num radix -- string ) [ over ] standard-combination ; G: >base ( num radix -- string ) 1 standard-combination ;
M: integer >base ( num radix -- string ) M: integer >base ( num radix -- string )
[ [

View File

@ -197,7 +197,7 @@ HELP: GENERIC: "word"
"A " { $link "method-combination" } " facility exists for customizing method dispatch behavior." "A " { $link "method-combination" } " facility exists for customizing method dispatch behavior."
$terpri $terpri
"This parsing word is equivalent to the following usage of the more general " { $link POSTPONE: G: } " word:" "This parsing word is equivalent to the following usage of the more general " { $link POSTPONE: G: } " word:"
{ $code "G: word simple-combination ;" } { $code "G: word 0 standard-combination ;" }
} }
{ $see-also define-generic } ; { $see-also define-generic } ;

View File

@ -165,7 +165,7 @@ M: number union-containment drop 2 ;
[ "M: vocabularies unhappy ;" eval ] unit-test-fails [ "M: vocabularies unhappy ;" eval ] unit-test-fails
[ ] [ "GENERIC: unhappy" eval ] unit-test [ ] [ "GENERIC: unhappy" eval ] unit-test
G: complex-combination [ over ] standard-combination ; G: complex-combination 1 standard-combination ;
M: string complex-combination drop ; M: string complex-combination drop ;
M: object complex-combination nip ; M: object complex-combination nip ;
@ -197,9 +197,6 @@ TUPLE: delegating ;
[ T{ shit f } "shit" ] [ T{ shit f } big-generic-test ] unit-test [ T{ shit f } "shit" ] [ T{ shit f } big-generic-test ] unit-test
[ T{ shit f } "shit" ] [ T{ delegating T{ shit f } } big-generic-test ] unit-test [ T{ shit f } "shit" ] [ T{ delegating T{ shit f } } big-generic-test ] unit-test
[ t ] [ \ = simple-generic? ] unit-test
[ f ] [ \ each simple-generic? ] unit-test
[ f ] [ \ object simple-generic? ] unit-test
[ t ] [ \ + 2generic? ] unit-test [ t ] [ \ + 2generic? ] unit-test
[ "SYMBOL: not-a-class C: not-a-class ;" parse ] unit-test-fails [ "SYMBOL: not-a-class C: not-a-class ;" parse ] unit-test-fails

View File

@ -62,7 +62,7 @@ sequences strings vectors words ;
] each-object nip ; inline ] each-object nip ; inline
G: each-slot ( obj quot -- ) G: each-slot ( obj quot -- )
[ over ] standard-combination ; inline 1 standard-combination ; inline
M: array each-slot ( array quot -- ) each ; M: array each-slot ( array quot -- ) each ;