Skip to content

Syntax and coding style

Paolo Angeli edited this page Nov 3, 2019 · 27 revisions

A really tiny taste of the language

In the beginning, the Jai language was similar to C with some constructs somewhat inspired by other languages. Now that the language is more mature some weird syntaxes started to appear so as a first impact you might get a bit confused. In this brief intro, to begin to familiarize with the syntax we'll take a look at the very basic stuff.

Comments

// Simple one line comment
/* Multi line comment */
/* A strange /* nested */ comment */ 

Constants

ALERT  :: 0xFFAA00;           // An hexadecimal constant
RAW_PI :: 3.1416;             // A floating point constant
ROLE_1 :: "Wizard";           // A static string constant

Style: for constants prefer using all upper case naming convention;

Variables

The syntax name: type = value; specifies that a variable named name is of the type type will be assigned the value value. It is similar to Typescript style and was proposed by Sean Barrett.

If the type is omitted it will be automatically inferred by the compiler through the type of the assigned value.

Some examples:

// Unassigned declarations will be initialized to default values (zeroes) unless specified
counter     : int;    // Signed 32 bit integer
key         : s64;    // Signed 64 bit integer
flags       : u8;     // Unsigned 8 bit integer

// Declarations and assignments

counter     : int = 0;                 // Simple signed 32 bits integer with assignment
mode        := 10;                     // Type int automatically inferred by the compiler
area        : float = r * r * RAW_PI;  // Single precision 32 bit floating point
average     := 0.5 * (x+y);            // Another float automatically inferred by the compiler
message     : string = "Hello ";       // A standard native unicode 16 bit char string
name        := "Sailor";               // Type string automatically inferred by the compiler

/* Multiple declarations */

// Declare two quaternions initialized with a default value by a factory function
rot1, rot2: Quaternion = q(0, 0, 1, 0);    
// Declare two 3D vectors both assigned to uninitialized values
v1, v2: Vector3 = ---;                 

Style: For variables prefer using all lower case naming convention;

Note: If not necessary avoid type declaration in assignments. Let the compiler infer the type.

Procedures

Are reusable blocks of code that could accept arguments.

// Define a procedure with arguments
do_something :: (what: string){
  printf("I'm doing: %", what); 
}

// Another procedure without arguments
main_loop :: () -> void{
  while !should_exit {
    get_user_input();
    simulate();
    render();
    post_process();
  }
}

Originally procedures were functions that don't return any value ( -> void ) as in C. But now you can omit the return value.

Style: prefer using snake case naming convention for naming procedures and all the compound terms in general

Functions

In Jai functions return single or multiple values

// Define a simple function
square :: (val: float) -> float {
  return val * val;
}

// Define a function with multiple unnamed results
circle_area:: (radious: float) -> float, bool {
  return square(radious) * RAW_PI, radious > 0 ;
}

// Define a function with multiple named results
complex_calc:: (a: float, b: float) -> (result: float, success: bool) {
  r1 := 0.0;
  r2 := true;
  ...
  
  return r1, r2;
}

Note: In the second case, the names for the results are only descriptive. (This might change in the future)

Aggregated data types: structs

// define a new struct type
Spring :: struct {
  relaxed_length : float; // millimeters
  theta          : float; // N/m
  force          : float; // N
  current_length : float; // mm
}

Style: prefer using capitalization for the first letter of the user-defined types.

// declare a new spring allocate it on the stack and initialize to zeroes
a_spring : Spring;

// use dot notation to access the fields
a_spring.relaxed_length = 100;

// or use the 'using' keyword for a block
using a_spring {
  theta = 100.0;
  force = 25;
  current_length = get_current_lenght(a_spring); 
}

// or use the 'using' keyword for the current scope 
stronger_spring := a_spring; // declare another spring and copy the data
using stronger_spring;
theta = 1000.0;
current_length = get_current_lenght(stronger_spring); 

// or use the 'using' keyword in a function
get_current_length(a_spring: Spring){
  using a_spring;
  return theta / relaxed_length * force + relaxed_lenght;
}

Basic collection data type: arrays

// define a new static array on the stack automatically initialized to zeroes
storage : [50] int;
// assign a value to an item by index
storage[0] = 20;

// define a variable-length array and allocate it on the heap
coefficients: [..] float;
// deallocate at the end of the scope
defer array_free(coefficients);

// define a list of constant values
verbs: [] string (:string: "put","get","post","delete");

Arrays do not automatically cast to memory pointers as in C. Because they are special data structures that contain also array size information. Functions and procedures can take array types and query them for the size of the array.

print_int_array :: (a: [] int) {
    n := a.count;
    for i : 0..n-1 {
        print("array[%] = %\n", i, a[i]);
    }
}

Retaining the array size information can help developers avoid the pattern of passing array lengths as additional parameters (see C2x proposal) and assist in automatic bounds checking (see C’s Biggest Mistake).

Note: The libraries of the language have many other useful and powerful collection data types already defined.

Constant sets data types: enumerations

Player_roles :: enum {
  SOLDIER;                 // Automatically assigned to 0
  PALADIN :: 1;            // Can be defined explicitly
  WIZARD :: 100;           // Can be defined leaving gaps
  SUPER_WIZ;               // And this will have the value of 101
}

This syntax mimics a series of constant definitions, so you can easily convert them in an enumeration.


Navigate

Types, constants and variables

  • Variables and assignments
  • Language data types
  • Simple user-defined data types
  • Expressions and operators
  • Type-casting
  • Pointers

Flow control

Procedures and functions

  • Declarations
  • Arguments / Parameters
  • Return values
  • Overloading / Polymorhism
  • Advanced features
  • Lambdas

Aggregated data types

  • Arrays
  • Strings
  • Composition of Structs

Advanced features

Clone this wiki locally