Mochaccino Sprint 1
Share
Explore

icon picker
Features 1.0

A language that doesn’t have everything is actually easier to program in than some that do.
If we’re creating a programming language, we probably have some features that set us slightly apart from other languages. In the first Features draft, we should aim to consolidate all these “experimental” features. We need to clarify how they work and whether they can integrate well with the rest of the language.

Static Typing

Type Annotations

Like any statically-typed language, Mochaccino uses type annotations to give variables and values types. The default type inferred is dyn (dynamic). You can implicitly define a variable’s type too:
var a<str> = "Hello";
Similarly, whenever a type annotation is expected, it should be enclosed in angled brackets. You can also provide type arguments where appropriate:
var b<map<str, num>> = {'a':1};
The actual type, the part between the angled brackets, is known as a type literal. Sometimes, type annotations like the ones above are expected, whereas type literals are expected in other cases.

Built-In Types

The default types in Mochaccino are:
dyn
str
num
bool
map<K, V>
arr<E>
void
promise<V>
null
entryPoint

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.

Structs

DOT Type System

Before we get into the thick of it, let’s understand a core principle that structs in Mochaccino were built around — the Data, Object, Type (DOT) Type System. Data refers to raw, low-level data such as a map. A Type is like a scaffolding structure over the data. It provides a systematic way to work with the data to view and modify the data. An Object is an instance of a piece of Data combined with a Type. Confused? Check out this simple example:
struct JSON { // Type
...
}

var data<map> = {...}; // Data
var a<JSON> = data::JSON; // Object
Bear in mind, even primitive types like str and map are Types too, providing a functional layer for even lower-level data. This little elaboration should clarify the role of structs in Mochaccino, and also certain terms that you're going to see later on.

Types of Structs

There are two types of structs in Mochaccino: elementary and protocol structs. Elementary structs allow you to define basic types like JSON and str which can hold values. Protocol structs, however, define interfaces for structs and modules (basically like structs for structs). If the previous sentence makes no sense, here’s an example:
Let’s say we have the struct str. It has the length property, right? But to return the length of the string, the struct must have access to the data it is wrapping. In such cases, using an elementary struct gives you access to the this keyword, which allows you to reference the data wrapped by the struct from within the struct.
So the length property of the str struct might have something like:
...
prop length<num> {
get { return this.chars; }
}
...
However, protocol structs do not wrap over a value. Instead, they are used for struct polymorphism and to define interfaces for structs and modules:
struct entryPoint {
@protocol
func main(args<arr> = [])<void>;
}

module Main implements entryPoint {
func main(args<arr<str>> = [])<void> {
Console.log('hello');
}
}
We’re not going to ever do something like:
var a<entryPoint> = ...;

Constructors and Type Assertions

An elementary 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::str
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 str is called with 12 as the argument. The constructor can then do some initialisation work like storing the "inner value" provided.
To define constructors in structs:
struct str {
constructor(value<dyn>) {
str.toString(value);
}

func compareFirstChar(firstChar<str>)<bool> {
return (firstChar==this.chars[0]);
}
...
}
Some things to note:
The parameters of the contructor will be the data types that can be converted to this type
If you want to have only a few types that can be converted instead of accepting all types, use optional parameters:
constructor(
value<arr>,
value<num>
)<str> {
str.toString(value);
}
Don’t worry about any errors for repeated identifiers — Mochaccino will evaluate constructor arguments differently from ordinary functions.
Hence, the return type of the constructor has to be the same as the struct:
constructor(value<dyn>)<num> {
str.toString(value);
}
Elementary struct constructors cannot use the return keyword.

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
In both of the cases above, no error is thrown and the program exits with code 0.

Type Arguments

How about structs like map? How do we enable structs to receive type arguments?
struct map<K, V> {
@elementary
constructor(...) {
...
if (this.K.type == str) {...}
...
}
}

Props

Props, short for properties, are used to define getters and setters together in structs. Just define the name and type of the property, and the getter’s return type as well as the setter’s paramaters are automatically filled in.
struct JSON {
...
prop id<num> {
get {
return this['id'];
}

set {
this['id'] = id;
}
}
...
}
Notice how the parameter id is exposed within the setter at runtime. Of course, you can choose to have only a getter or setter.

Static Methods

Elementary structs can have elementary methods and static methods. Elementary methods, as their name suggests, are called on Objects directly. But you can also define static methods in elementary structs:
struct A {
static func doStuff()<void> {
...
}
}

Struct Polymorphism

Implementing Structs

Implement: provide concrete implementations of abstract members

Extending Structs

Extend: define more abstract/concrete members

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: $someVar.someMethod 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 B has the declaration "package B;" at the top.
- ensuring the package is within the project scope, by running "barista scope add "path/to/file.moc" from the same directory as your mochaccino.configs.json file.

Built-In onChange Notifier

Elementary structs in Mochaccino come with a special onChange function that can be configured with a callback whenever their data variable is changed.
var a<string> = "hello";
a.onChanged((newValue<dynamic>) {
if (newValue==null) {
throw "newValue for 'a' is null";
}
});
a = someFunctionThatUnexpectedlyReturnsNull();
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.

Command Line Tool

Of course, our programming language should also ship with a command line tool for administrative tasks. Node.js uses node + npm, Dart uses dart + pub, Python uses pip. For Mochaccino, keeping in line with the coffee theme, we have decided to name our package manager Barista.
Commands
0
Keyword
Commands and Flags
Description
1
compile
<filename> -Target
2
init
<title>
Creates the directories and config files for a new Mochaccino project.
3
run
<filename>
4
scope
add
5
refresh
There are no rows in this table

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.