Skip to content

1. Features

Tambapps edited this page Feb 11, 2023 · 21 revisions

This pages enumerates all Marcel's features.

All titles annotated with NYI means that the features described by the section and its sub-sections are is Not Yet Implemented

Variable declarations and assignments

You can declare/assign a variable like you would in Java

// declaration
int myInteger = 1
float myFloat = 2f

// assignments
myInteger = 3

Multi Variable declarations

def (String a, String b) = "A B".split(" ")

When you declare a variable, you must always specify a value

Types

Primitives

Marcel supports the following primitive types

  • void
  • boolean
  • byte
  • int
  • long
  • float
  • double

Classes

Marcel supports classes. You can use all existing Java classes from the JDK.

Define classes

You can define classes like in Java

class Foo {

}

Define fields (NYI)

String

String interpolation

You can specify variables in String

"$firstName $lastName is $age years old"

If you need to access a property, use the brackets

"${person.firstName} ${person.lastName} is ${person.age} years old"

Control flows

Marcel truth

A truthy value is a value that is considered true for an if, or a while. A falsey value is a value that is considered false in those places.

The only falsey values are the following:

  • null
  • Optional.empty()
  • An empty collection
  • An empty array

Any other value is truthy.

You can also override the truth for a class if you define a function fun truthy() bool

If expression

In Java, Ifs are statement but in Marcel you can use them as expression, similar as Kotlin's Ifs. If an if/else if/else has only one statement in it, you can omit brackets

int a = if (something()) 1 else if (somethingElse()) 2 else 3

if (a == 1) {
  a++
  println("foo")
} else {
  a--
  println("bar")
}

if variable declaration

Marcel truth allows you to declare variable in an if condition, and execute the code block if the variable is truthy

if (Something result = fetchSomething()) {
  println("Fetched $result")
}

You can also deconstruct Optional values such as in the below example (NYI)

// assuming getOptionalInteger() returns an Optional<Integer>
if (Integer result = getOptionalInteger()) {
  println(result)
}

For statements

There are different ways to iterate over values

For i

The Java for i is compatible with Marcel

for (int i = 0; i < 10; i++) {
  println(i)
}

For in

The in keyword allows to iterate over values in an array, or any objects implementing Iterable (meaning all Collections).

int[] ints = getInts()
for (int i in ints) {
  println(i)
}

Marcel also have a Ranges, allowing you to iterate with the below syntax

// inclusive range
for (int i in 0..9) {
  println(i)
}

// exclusive range
for (int i in 0..<10) {
  println(i)
}

// also work in reverse orde
for (int i in 9..0) {
  println(i)
}

// exclusive range
for (int i in 10>..0) {
  println(i)
}

Switch (NYI)

TODO

Ternary

You can use ternary expression. Marcel truth also applies in them, meaning you can specify values of any type.

The below code will print 2

int a = Optional.empty() ? foo() : bar()
println(a)

fun foo() int {
  return 1
}

fun bar() int {
  return 2
}

Functions

Use the fun keyword to define functions

fun sum(int a, int b) int {
  return a + b
}
fun foo() {
  // do nothing
}

Call a method

int result = sum(1, 2)

Function visibility

In marcel, there are 3 kinds of visibility.

  • public -> which refers to Java's public visibility. Your class/method may be accessible from any package
  • protected -> which refers to Java's protected visibility. Your class/method may only be accessible from other classes in the same package or inheriting your class
  • internal-> which refers to Java's package-private visibility. Your class/method may only be accessible from classes in the same package
  • private -> Your method may be accessible only from the class it was defined in

To specify a visibility for your method, put it before the fun keyword.

private fun sum(int a, int b) int {
  return a + b
}

Functions are public by default.

Function named parameters (NYI)

Function arguments can have default constant values You can specify method argument names when calling a function. To use sum method defined above we would do.

int result = sum(a = 1, b = 2)

Parameter default value (NYI)

Function parameters can have default values, which are used when you skip the corresponding argument.

fun sum(int a = 0, int b = 8) int {
  return a + b
}

sum(a = 2)
sum(b = 5)
sum(a = 2, b = 5)

Return multiple values (NYI)

A function can return multiple values

fun foo() (int, int) {
  return a + 8, b + 10
}

int a, b = foo()

Arrays ans Collections

Array of primitives (NYI)

You can declare litteral arrays like in the below example

long[] array = [1, 2, 3, 4]
Object[] = ["some", 1, new Object()]

Collections and Iterator of primitive types

Marcel allows to use collections with primitive elements.

All Collections of primitive types can be declared using the lowercase type's name of Java equivalent

List

list<int> list = [1, 2, 3, 4]

Set

set<long> set = [1d, 2, 4d, 4d]
// this set will contain 1, 2 and 4

You can declare a set using a similar syntax. The given array will be transformed into a set, and all duplcated elements will be filtered

Map

map<float, Object> map = {1.3: "1", 1.4: "2"}

Operators

Elvis operator

When dealing with nullable/Optional variables, this operator can be handy to have a default value.

String displayName = user.name ?: 'Anonymous' 

The default value will be used if the variable is null or it is an empty Optional.

You can also use this operator to return from a function when the value is null

String displayName = user.name ?: return           

Safe navigation operator

The Safe Navigation operator is used to avoid a NullPointerException. Typically when you have a reference to an object you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator will simply return null instead of throwing an exception, like so

Person person = fetchPerson()
String name = person?.name

Safe index operator

This operator allows you to access safely an array/List by index, fallbacking to null if the index is out of bounds

int value = array?[10] ?: 0

Define operators (NYI)

You can define operators for your classes like in Groovy

Define the appropriate function on your class to be able to use the corresponding operator on your class instances.

Comments

Define comments like you would in Java. // for a single line comment, and /* ... */ for a multi-line comment

Dynamic properties in script (NYI)

You can get and set properties dynamically in your script. Such properties are accessible in your script's main function, and all non-static functions of your script

set a = 1
set b = [1, 2]
// do some stuff
int something = get a
// enforce type checking with the 'as' keyword
list<int> list = get b as list<int>

Dynamic Objects (NYI)

Allows to get dynamically properties dynamically, like in Groovy (TBD)

Type casting

keyword as

This will do its best to cast at compile time (e.g. for arrays to collections) but if not it will add a cast check at runtime