Mochaccino
Share
Explore

icon picker
Principles

In Mochaccino, the rules are simple. Everything is built towards code organisation and easy debugging. Let’s go through some unique features of the Mochaccino language.
Modularity
Modules
Modules are the building blocks of your program. A module contains properties and methods needed for a certain functionality. For example, DBTools can be a module. It can include fields to store the HTTP Client, endpoint configurations as well as methods to make calls, process data.
module DB {
final var client<HttpClient> = HttpClient.create();
func getObjectById(id<string>)<promise<map>> async {
return await dbutils.fetch(id: id);
}
}
Package
You can bundle multiple modules under a package using the package keyword followed by an identifier. Every Mochaccino program must have a package main that provides an entry point to your program.
Inside the package main, you must define a module that implements the EntryPoint struct. This built-in struct requires that you define a function named main that takes no arguments and returns void.
Dock
The dock keyword allows you to import packages. Mochaccino doesn’t have a package registry, so you can only import built-in packages or other local Mochaccino files. The dock statement supports selective imports, wildcard imports, and import aliases.
Include
You can split up a package across multiple files. The inlcude keyword allows you to include the contents of another file inside the current package. Each of the included files must have a partof keyword followed by the package that is inclduing that file.
A.mono
package A;
include B;
include C;
B.mono
package B;
partof A;
C.mono
package C;
partof A;
Warning
One caveat of using include is that included packages cannot have their own dock statements. All imports must be done by the package using the include keyword.
Static Typing
Type Annotations
Like any statically-typed language, Mochaccino uses type annotations to give variables and values types. The default type inferred is <dynamic>. You can implicitly define a variable’s type too:
var a<string> = "Hello";
Similarly, whenever a type is expected, it should be enclosed in angled brackets. You can also provide type arguments where appropriate:
var b<map<string, int>> = {'a':1};
Built-In Types
The default types in Mochaccino are:
string
int
double
bool
map<K, V>
array<E>
void
promise<V>
null
Note
Actually, there’s another default type in Mochaccino, <EntryPoint>, which is used by the module containing the main function. However, this type is considered an exception, and the term “default types” excludes this type.
The default types are written in lowercase, while custom types are written in CamelCase.
Custom Types with Structs
To define a custom type, you use the struct keyword. This allows you to define an interface that can be used to constrain data with certain properties and methods.
Constructors and Type Assertions
A struct can have a constructor, which is empty by default, that converts data to its own type. The constructor is called whenever a type conversion (aka assertion) is taking place. A type conversion looks like this:
12::<string>
On the left is the value that needs to be converted and on the right is the conversion target type. In this case, the constructor for <string> is called with 12 as the argument.
Guarded Keyword
The guarded keyword in Mochaccino causes the succeeding statement to only be executed if it does not throw an error. If an except clause is specified, then the offending statement will be run, and the error will be handled by the except clause. This is typically used in type assertions, where one type is converted to another.
guarded 12::<Service> except pause; // program exits without errors
guarded 12::<Service>; // no type conversion takes place
Type Arguments
Implementing Structs
Extending Structs
Debugging
Breakpoint Keywords
There are two breakpoint keywords in Mochaccino, ok and notok, which are used for debugging. The ok keyword logs its line number and column position when reached. The notok keyword prints its position, the result of the preceding statement to the console, and exits the program. Furthermore, their functionality can be extended through the use of debug flags, discussed later.
if (someVar.someMethod()!='abc') {
notok;
} else {
ok;
}
This is the console log for the above code:
exit[0]: notok
line: 3, column: 3
Debug Flags
Taking the same example as just now, this is how we can use debug flags for richer console logs:
if (someVar.someMethod()!='abc') {
#label: abc is null
notok;
} else {
ok;
}
The above code will result in a log like this:
exit[0]: abc is null
line: 3, column: 3
Rich Error Messages
Aside from pointing out the location and type of errors, Mochaccino can also suggest personalised troubleshooting tips. For exampe:
exit[1]: 1 errors
PackageResolution: package 'B' not found.
3| include B;
Try:
- ensuring the package has the "package B;" and "partof A" directives at the top.
- ensuring the package is within the project scope, by running "moc scope add "path/to/file.moc" from the same directory as your mochaccino.configs.json file.
Built-In onChange Notifier
Variables in Mochaccino come with a special onChange function that can be configured with a callback whenever said variable is changed.
var a<string> = "hello";
a.onChanged((newValue<dynamic>) {
if (newValue==null) {
throw "newValue for 'a' is null";
}
});
Used with other debugging tools, you’ll no longer have to spend hours pulling your hair out wondering where that null value is coming from.
Share
 
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.