diff --git a/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/reference/experimental.scrbl b/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/reference/experimental.scrbl index 8b80ddff..fda49f8f 100644 --- a/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/reference/experimental.scrbl +++ b/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/reference/experimental.scrbl @@ -7,9 +7,6 @@ These features are currently experimental and subject to change. -@defform[(Class args ...)]{A type constructor for typing classes created using @racketmodname[racket/class].} -@defform[(Instance c)]{A type constructor for typing objects created using @racketmodname[racket/class].} - @defform[(declare-refinement id)]{Declares @racket[id] to be usable in refinement types.} diff --git a/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/reference/typed-classes.scrbl b/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/reference/typed-classes.scrbl new file mode 100644 index 00000000..6dc5ddf4 --- /dev/null +++ b/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/reference/typed-classes.scrbl @@ -0,0 +1,201 @@ +#lang scribble/manual + +@begin[(require "../utils.rkt" scribble/eval racket/sandbox) + (require (for-label (only-meta-in 0 [except-in typed/racket for])))] + +@(define the-eval (make-base-eval)) +@(the-eval '(require (except-in typed/racket #%top-interaction #%module-begin))) +@(define the-top-eval (make-base-eval)) +@(the-top-eval '(require (except-in typed/racket #%module-begin))) + +@(define-syntax-rule (ex . args) + (examples #:eval the-top-eval . args)) + +@title{Typed Classes} + +Typed Racket provides support for object-oriented programming with +the classes and objects provided by the @racketmodname[racket/class] +library. + +@defform[#:literals (init field augment) + (Class class-type-clause ...) + #:grammar ([class-type-clause name+type + (init init-type ...) + (field name+type ...) + (augment name+type ...) + (code:line #:implements type-alias-id) + (code:line #:row-var row-var-id)] + [init-type name+type + [id type #:optional]] + [name+type [id type]])]{ + The type of a class with the given initialization argument, method, and + field types. + + The types of methods are provided either without a keyword, in which case + they correspond to public methods, or with the @racketidfont{augment} + keyword, in which case they correspond to a method that can be augmented. + + An initialization argument type specifies a name and type and optionally + a @racket[#:optional] keyword. An initialization argument type with + @racket[#:optional] corresponds to an argument that does not need to + be provided at object instantiation. + + When @racket[type-alias-id] is provided, the resulting class type + includes all of the initialization argument, method, and field types + from the specified type alias (which must be an alias for a class type). + Multiple @racket[#:implements] clauses may be provided for a single class + type. + + @ex[ + (define-type Point<%> (Class (field [x Real] [y Real]))) + (: colored-point% (Class #:implements Point<%> + (field [color String]))) + ] + + When @racket[row-var-id] is provided, the class type is an abstract type + that is row polymorphic. A row polymorphic class type can be instantiated + at a specific row using @racket[inst]. Only a single @racket[#:row-var] + clause may appear in a class type. +} + +@defform[#:literals (field) + (Object object-type-clause ...) + #:grammar ([object-type-clause name+type + (field name+type ...)])]{ + The type of an object with the given field and method types. + + @ex[ + (new object%) + (new (class object% (super-new) (field [x : Real 0]))) + ] +} + +@defform[(Instance class-type-expr)]{ + The type of an object that corresponds to @racket[class-type-expr]. + + This is the same as an @racket[Object] type that has all of the + method and field types from @racket[class-type-expr]. The types for + the @racketidfont{augment} and @racketidfont{init} clauses in the + class type are ignored. +} + +@;; This uses a trick to link to racket/class's class identifier +@;; in certain cases rather than the class defined here +@(module id-holder racket/base + (require scribble/manual (for-label racket/class)) + (provide class-element) + (define class-element (racket class))) +@(require 'id-holder) + +@defform[#:literals (inspect init init-field field inherit-field + public pubment override augment private inherit + begin) + (class superclass-expr + maybe-type-parameters + class-clause ...) + #:grammar ([class-clause (inspect inspector-expr) + (init init-decl ...) + (init-field init-decl ...) + (field field-decl ...) + (inherit-field field-decl ...) + (public maybe-renamed/type ...) + (pubment maybe-renamed/type ...) + (override maybe-renamed/type ...) + (augment maybe-renamed/type ...) + (private id/type ...) + (inherit id ...) + method-definition + definition + expr + (begin class-clause ...)] + [maybe-type-parameters (code:line) + (code:line #:forall type-variable) + (code:line #:forall (type-variable ...))] + [init-decl id/type + [renamed] + [renamed : type-expr] + [maybe-renamed default-value-expr] + [maybe-renamed : type-expr default-value-expr]] + [field-decl (maybe-renamed default-value-expr) + (maybe-renamed : type-expr default-value-expr)] + [id/type id + [id : type-expr]] + [maybe-renamed/type maybe-renamed + [maybe-renamed : type-expr]] + [maybe-renamed id + renamed] + [renamed (internal-id external-id)])]{ + Produces a class with type annotations that allows Typed Racket to type-check + the methods, fields, and other clauses in the class. + + The meaning of the class clauses are the same as in the @class-element + form from the @racketmodname[racket/class] library with the exception of + the additional optional type annotations. Additional class clause + forms from @class-element that are not listed in the grammar above are + not currently supported in Typed Racket. + + @ex[ + (define fish% + (class object% + (init [size : Real]) + + (: current-size Real) + (define current-size size) + + (super-new) + + (: get-size (-> Real)) + (define/public (get-size) + current-size) + + (: grow (Real -> Void)) + (define/public (grow amt) + (set! current-size (+ amt current-size))) + + (: eat ((Object [get-size (-> Real)]) -> Void)) + (define/public (eat other-fish) + (grow (send other-fish get-size))))) + + (define dory (new fish% [size 5.5])) + ] + + Within a typed class form, one of the class clauses must be a call + to @racket[super-new]. Failure to call @racket[super-new] will result in + a type error. In addition, dynamic uses of @racket[super-new] (e.g., + calling it in a separate function within the dynamic extent of the + class form's clauses) are restricted. + + @ex[ + (class object% + (code:comment "Note the missing `super-new`") + (init-field [x : Real 0] [y : Real 0])) + ] + + If any identifier with an optional type annotation is left without an + annotation, the type-checker will assume the type @racket[Any] + (or @racket[Procedure] for methods) for that identifier. + + @ex[ + (define point% + (class object% + (super-new) + (init-field x y))) + point% + ] + + When @racket[type-variable] is provided, the class is parameterized + over the given type variables. These type variables are in scope inside + the body of the class. The resulting class can be instantiated at + particular types using @racket[inst]. + + @ex[ + (define cons% + (class object% + #:forall (X Y) + (super-new) + (init-field [car : X] [cdr : Y]))) + cons% + (new (inst cons% Integer String) [car 5] [cdr "foo"]) + ] +} + diff --git a/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/ts-reference.scrbl b/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/ts-reference.scrbl index 919362c8..c6e5e16a 100644 --- a/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/ts-reference.scrbl +++ b/pkgs/typed-racket-pkgs/typed-racket-doc/typed-racket/scribblings/ts-reference.scrbl @@ -32,6 +32,7 @@ For a friendly introduction, see the companion manual @include-section["reference/exploring-types.scrbl"] @include-section["reference/no-check.scrbl"] @include-section["reference/typed-regions.scrbl"] +@include-section["reference/typed-classes.scrbl"] @include-section["reference/optimization.scrbl"] @include-section["reference/legacy.scrbl"] @include-section["reference/compatibility-languages.scrbl"]