Methods
.method opens a block the way .try does, and } closes it. The method is compiled once
and kept in the session, so later cells and other methods call it by name. This is the source of a method; copy it, paste it into a session, and press Enter.
.method int32 Fib(int32 n) { ldarg n ldc.i4 2 blt BASE ldarg n ldc.i4 1 sub call int32 Fib(int32) ldarg n ldc.i4 2 sub call int32 Fib(int32) add retBASE: ldarg n ret}Enter continues the block while its braces are open and sends it once they balance, one line at a time, so the transcript reads the same whether the block was typed or pasted. See Editing blocks.
il[1]> .method int32 Fib(int32 n) { method int32 Fib(int32 n)il[1]> ldarg n ┊ [int32]il[1]> ldc.i4 2 ┊ [int32, int32] ◂ topil[1]> blt BASE ┊ []il[1]> ldarg n ┊ [int32]il[1]> ldc.i4 1 ┊ [int32, int32] ◂ topil[1]> sub ┊ [int32]il[1]> call int32 Fib(int32) ┊ [int32]il[1]> ldarg n ┊ [int32, int32] ◂ topil[1]> ldc.i4 2 ┊ [int32, int32, int32] ◂ topil[1]> sub ┊ [int32, int32] ◂ topil[1]> call int32 Fib(int32) ┊ [int32, int32] ◂ topil[1]> add ┊ [int32]il[1]> ret ┊ []il[1]> BASE: ldarg n ┊ [int32]il[1]> ret ┊ []il[1]> } end of method Fibil[2]> ldc.i4 10 ┊ [int32]il[2]> call int32 Fib(int32) ┊ [int32]il[2]> ret = 55 : int32Inside the block, ldarg loads the parameters by name, .locals declares the method’s own
locals, and labels and .try blocks work as they do in a cell. ret returns from the method and
never runs the cell. The stack echo, .show, and the status bar describe the method while it is
open.
Closing the block completes the cell, so the next line starts a new one. Nothing runs. Stack analysis checks every established path before the method is kept. Runtime preparation adds a check for methods it can prepare; remaining runtime checks happen when called. Anything already typed into the cell stays there.
A call names the method with nothing in front of it: call int32 Fib(int32). The return type is
optional, as it is for any member reference. The method is static, so ldftn, calli, and
delegates over it work too.
A void helper
Section titled “A void helper”il[3]> .method void Greet(string name) { method void Greet(string name)il[3]> ldstr "hello, " ┊ [string]il[3]> ldarg name ┊ [string, string] ◂ topil[3]> call string String::Concat(string, string) ┊ [string]il[3]> call void Console::WriteLine(string) ┊ []il[3]> ret ┊ []il[3]> } end of method Greetil[4]> ldstr "methods" ┊ [string]il[4]> call void Greet(string) ┊ []il[4]> rethello, methods = (void)Listing them
Section titled “Listing them”.methods lists what the session has defined. .show inside an open block lists the method with
the stack after each instruction, and .il renders every method beside Run. Once the block is
closed, .dis Fib reads the compiled body back, byte offsets and all, so what the emitter produced
can be compared with what was typed. See Disassembly.
il[5]> .methods int32 Fib(int32 n) void Greet(string name)Closing the block
Section titled “Closing the block”} closes the method. When the stack holds what the return type needs, one value for int32 or
nothing for void, the final ret is implied. A mismatched return is refused at the offending
line. In the terminal editor the submission is withdrawn and the block comes back for correction:
il[5]> .method int32 Answer() { method int32 Answer()il[5]> ldstr "42" ┊ [string]il[5]> ret error: ret needs int32 on the stack but found string ret Expected: return value must be int32 Stack before (bottom → top): [string] return value: expected int32; actual string from line 2: ldstr "42" method Answer abandoned; the block is back in the editorReplace the string load with ldc.i4 42 and submit the corrected block:
il[5]> .method int32 Answer() { method int32 Answer()il[5]> ldc.i4 42 ┊ [int32]il[5]> } end of method Answeril[6]> call Answer ┊ [int32]il[6]> ret = 42 : int32Branches are checked together. A label receiving [] on one path and [int32] on another
produces a diagnostic naming both paths. A forward target remains incomplete while it is being
written; it must be defined before the method closes. The editor and .show use the same analysis,
including changes caused by a later backward branch. See Cells and the stack.
.undo takes back the last line of the block, and taking back the header abandons it. .clear
inside a block abandons the method and leaves the cell alone. Neither advances the cell number.
.reset drops every method along with the declarations. .save writes the methods into the
assembly beside Run.
Redefinition
Section titled “Redefinition”Defining a method again with the same name replaces it when the block closes, and the note says
replaced method Fib. The other methods and the cell body are checked against the new signature
when you type the header, so a change that would break a caller is refused before you write the
body; .clear the cell or keep the signature. Calls resolve as you type them, so two methods that
call each other take three steps: define the second with a placeholder body, define the first
with its call, then define the second again with its real body.
To keep the original while changing a copy, use .edit. This also works with framework and loaded
methods. See Editing and comparing methods.