Repository navigation
reflection
A program can look at its own classes, objects and functions. dir lists the names a value has:
class Point { x: int; y: int; length() := sqrt(x*x + y*y) }
p = Point(3, 4)
dir(p) # ["x" "y" "length"]
p.fields and p.methods split them, p.class is Point, type(p) its type. dir of a list or text lists its
type's methods, the builtin ones like count and sort included, as Python's dir does; of a map, its keys.
help(Point) describes a class in a few lines:
class Point
fields: x y
methods: length
A function knows its parameters, signature, body and effects:
area(width: int, height: int) := width * height
area.params # ["width" "height"]
area.signature # (width:int, height:int) -> int
area.dump # area(width:int, height:int) := width*height
area.body is the body alone, f.effects what it does besides computing (IO for printing, effects); dir(area)
lists these words. The words take the function itself, never call it.
A body is code, as is what parse gives: it prints as its source and tests as its form too.
type area.body # code
area.body # width*height
area.body is operation # yes
type parse("1+1") # code
A real field always wins: an object with a field params gives its field. Runnable: samples/reflection.warp.
A function describes itself with a text as the first statement of its body, as in Python. That text is not run:
fun twice(x) {
"doubles a number"
x*2
}
twice.doc # doubles a number
The comment right above a definition is its doc too:
# doubles a number
twice(x) := x*2
help(twice) # twice(x) -> int
# doubles a number
help(f) shows the doc below the signature. A function without one has the empty doc ""; a body that is only a
text keeps it as its value. Only the comment directly above counts: after a blank line it is no doc.
function f is the function itself, a value like any other. It knows its .name, .signature, .return_type
and .doc, also when it is only known at run time, as an item of a list. type(f) names the signature:
use math
type(gcd) # function: (a, b) -> int
f = function gcd
f.name # gcd
f(12, 18) # 6
A built-in, a function the language provides, is a function value of type builtin, a kind of function:
type(function floor) # builtin: (x:number) -> int
f = function upper
type(f) # builtin
f is function # yes
print f # upper(t:text) -> text
methods lists functions themselves: of a module (methods(math), math.methods, methods of math), of a class
(methods(Dog), d.methods) or of a value's type (methods("hi")):
for f in methods(math): print f.doc
Printed on its own, a function shows its definition, the doc as a comment line above it. In a list it shows its name:
# the value a fraction t of the way from a to b
lerp(a, b, t) := a+(b-a)*t
A bare name is a call: print now prints the time, and print hi of a function hi() without parameters calls it.
That gets a warning, since print function hi was probably meant.
help of a standard module lists its words, as warp help sound does. help of one word gives its head and the
comment above it, and function(name).dump gives its definition as written:
use sound
help(midi) # midi(pitch)
# the MIDI note nearest a frequency: midi(C4) is 60, midi(440Hz) 69
for trick in dir(sound): print function(trick).dump
A help(x) on its own line prints, as in Python; t = help(x) only keeps the text. The name can come at run time, like trick here. function beep is the function beep itself, while function trick
of a variable holding a name means the word with that name. A name that isn't a word is an error naming it.
Runnable: samples/sound_features.warp.