A method is a subroutine, attached to a class, that can have any number of predefined inputs and outputs. A method is executed by passing the method name and arguments to an object. You can't call methods on primitive objects; Instead, they can be transformed with stateless functions that are built into the Ozark language.
Methods
A method declaration specifies named inputs, named outputs, and a method body. The body is made of imperative statements. All methods are public (accessible to any context that has reference to the object.)
inheritance Musician method begin concerto: Song, orchestra: Orchestra concerto movement 1 -> movement1 orchestra perform movement1 concerto movement 2 -> movement2 orchestra perform movement1 concerto movement 3 -> movement3 orchestra perform movement3 method conclude concerto: Song, orchestra: Orchestra orchestra conclude concerto
Methods do not have a "return value" like in other object-oriented languages. Statements are not expressions to be evaluated; They are instructions to be executed, and they may or may not have any number of outputs. Separating the concept of evaluable expressions from the that of executable instructions is one of the core uniquenesses of Ozark.
An object can't call its own methods, as we believe that procedural concept doesn't belong in an object oriented langauge. See this article for a discussion of the issue.
Inputs & outputs
Methods have any number of predefined inputs and outputs. Within a method, inputs are constant, meaning they cannot have their value changed. The only mutable items are the outputs of the method, the properties of the current object, and any defer
red inputs to dispatched inline method calls.
When calling a method, the created outputs are constants that cannot be changed.
Within a method signature, inputs are declared sequentially after the method name, and outputs are declared after an arrow symbol (->
).
The types of the variables and collections are defined explicitly in the method signature. Inputs are both named and ordered, allowing verbose method names. A method signature can use the implied
keyword to specify that the first input and/or output name should be omitted when calling.
inheritance Boat property @location: Location? property @launch: Launch property @navigate: Navigate property @dock: Dock method setup create Launch; assign to @launch; setup create Navigate; assign to @navigate; setup create Dock; assign to @dock; setup method sail destination: WaterfrontLocation -> duration: TimeInterval @launch! destination port -> port port location -> location @navigate! destination: location -> assign to @location, duration; assign to duration @dock! port: port
Properties
Ozark code operates on one small scope at a time. A method may access the properties of the instance object, and the inputs and outputs of the method itself. No other predefined values are available to it.
Conversely, using a method is the only way of accessing the properties of a given object.
Overriding & extending parent methods
As discussed in Inheritance, a class inherits all methods and properties from its parent classes. To override a method in a child class, drop the method
keyword and instead declare a replacement
.
To extend a parent method, declare an extension
instead. This is commonly used with the setup
method. The body declared for the extension will execute after the code declared in the parent method. You can choose to add additional inputs and outputs to the extension.
Outside of extensions, methods with the same name but different named parameters are considered different methods.
inheritance Plant property @color: Color extension setup create Color; assign to @color; random
To add additional input & output parameters to an extension, prefix them with the ampersand (&
) symbol.
inheritance Plant property @color: Color extension setup -> & facing: Direction create Direction; assign to facing; random
Calling methods
Method calls are the building blocks of other methods. Every line inside a method body is either a method call or a control flow statement. Call a method by passing the name of the method and the arguments to the object on which the method will be called.
A method call follows a cadence of:
subject, verb, argument, value, argument, value, ...
See the Ozark Style Guide for more information.
inheritance Musician property @guitar: writable Guitar method play string: GuitarString -> note: implied Note string play -> assign to note
Functions
Ozark includes a number of built-in, stateless functions that can operate on primitive values, collections of any type, and the memory addresses of pointers. These functions loosely represent the logic gates available to the host machine.
There are two types of functions: prefix and infix. Prefix functions have syntax like a method but with no subject. Infix functions can be chained together according to the basic mathematical order of operations to yield a single output. Some infix functions can use special tuple matching nouns like any
and nil
, and operate on a variable or pointer of any kind.
In functions and methods alike, primitive inputs can often receive values of other primitive types. See Primitive Types for more info.
Note that since a string is an array, all functions that operate on arrays may also operate on strings.
Key For Tables Below[]
An array{}
A tuple (note that using a single value is OK here)
When calling the methods, actual values are used in place of unnamed input types, and the function yields outputs of the unnamed types listed.
Infix Functions | |
---|---|
Number + Number -> Number | Add |
Number - Number -> Number | Subtract |
Number * Number -> Number | Multiply |
Number / Number -> Number | Divide |
Integer % Integer -> Integer | Modulus |
Number ^ Number -> Number | Power |
Boolean and Boolean -> Boolean | And |
Boolean nand Boolean -> Boolean | Not and |
Boolean or Boolean -> Boolean | Or |
Boolean nor Boolean -> Boolean | Nor |
Boolean xor Boolean -> Boolean | Exclusive or |
Boolean xnor Boolean -> Boolean | Exclusive nor |
Number << Integer -> Number | Left shift |
Number >> Integer -> Number | Sign-propagating right shift |
Number >>> Integer -> Number | Zero-fill right shift |
Boolean Infix Pattern Matching Functions | |
---|---|
@Type is @Type | Equals / Object equivalence |
@Type is not @Type | Not equals / Object non-equivalence |
@Type in [@Type] | Containment |
@Type not in [@Type] | Non-containment |
Number > Number | Greater than |
Number >= Number | Greater than or equal |
Number < Number | Less than |
Number <= Number | Less than or equal |
Prefix Functions |
---|
flip Boolean -> Boolean |
reverse [@Type] -> [@Type] |
round Number -> Integer |
roundUp Number -> Integer |
roundDown Number -> Integer |
stepTo Integer, step: Integer? -> [Integer] |
join [@Type] glue: [@Type] -> [@Type] |
zip array: [[@Type]] -> [[@Type]] |
zip tuple: [{}] -> [{}] |
split [@Type], [@Type] -> [@Type], [@Type] |
extract [@Type], @Type -> [@Type], [@Type] |
interpret String -> Number |
interpret String -> integer: Number |
serialize {} -> String |
open String |
close String |
run String |
print String |