-
Notifications
You must be signed in to change notification settings - Fork 81
Raw material
The documents in this page come from the original BSVino's files but now are obsolete and need heavy rearrangement. ASAP this text will be updated and moved from here.
BAKING
… this section is not written yet! Sorry. (The #bake
directive emits a function with a combination of arguments baked in. For example, #bake sum(a, 1)
becomes equivalent to a += 1
.)
Jai does not and will never feature garbage collection or any kind of automatic memory management.
STRUCT POINTER OWNERSHIP
Marking a pointer member of a struct with !
indicates that the object pointed to is owned by the struct and should be deleted when the struct is deallocated. Example:
node :: struct {
owned_a : !* node = null;
owned_b : !* node = null;
}
example: node = new node;
example.owned_a = new node;
example.owned_b = new node;
delete example; // owned_a and owned_b are also deleted.
Here, owned_a
and owned_b
are marked as being owned by node
, and will be automatically deleted when the node is deleted. In C++ this is accomplished through a unique_ptr<T>
, but Jai considers this the wrong way to do it, because the template approach now masks the true type of the object. A unique_ptr<node>
is no longer a node
—it’s a unique_ptr
masquerading as a node
. It’s preferable to retain the type of node*
, and retain the properties of node*
-ness that go along with it, because we don’t really actually care about unique_ptr
for its own sake.
LIBRARY ALLOCATORS
… this section is not written yet! Sorry. (Jai provides mechanisms for managing the allocations of an imported library without requiring work from the library writers.)
INITIALIZATION
Member variables of a class are automatically initialized.
Vector3 :: struct {
x: float;
y: float;
z: float;
}
v : Vector3;
print("% % %\n", v.x, v.y, v.z); // Always prints "0 0 0"
You can replace these with default initializations:
Vector3 :: struct {
x: float = 1;
y: float = 4;
z: float = 9;
}
v : Vector3;
print("% % %\n", v.x, v.y, v.z); // Always prints "1 4 9"
va : [100] Vector3; // An array of 100 Vector3
print("% % %\n", va[50].x, va[50].y, va[50].z); // Always prints "1 4 9"
Or you can block the default initialization:
Vector3 :: struct {
x: float = ---;
y: float = ---;
z: float = ---;
}
v : Vector3;
print("% % %\n", v.x, v.y, v.z); // Undefined behavior, could print anything
You can also block default initialization at the variable declaration site:
Vector3 :: struct {
x: float = 1;
y: float = 4;
z: float = 9;
}
v : Vector3 = ---;
print("% % %\n", v.x, v.y, v.z); // Undefined behavior, could print anything
va : [100] Vector3 = ---;
print("% % %\n", va[50].x, va[50].y, va[50].z); // Undefined behavior, could print anything
By explicitly uninitializing variables rather than explicitly initializing variables, Jai hopes to reduce cognitive load while retaining the potential for optimization.
Things that C/C++ should have had a long time ago:
- Multi-line block comments
- Nested block comments
- Specific data types for 8, 16, and 32 bit integers
- No implicit type conversions
- No header files
-
.
operator for both struct membership and pointer dereference access—no more->
- A
defer
statement, similar to that of Go
Here’s a short list of planned features to be added to Jai.
- Automatic build management—the program specifies how to build it
- Captures
- LLVM integration
- Automatic versioning (see below)
- A better concurrency model
- Named argument passing
- A permissive license
Jai will not have:
- Smart pointers
- Garbage collection
- Automatic memory management of any kind
- Templates or template metaprogramming
- RAII
- Subtype polymorphism
- Exceptions
- References
- A virtual machine (at least, not usually—see below)
- A preprocessor (at least, not one resembling C’s—see below)
- Header files
If it sounds odd to you that Jai is a modern high-level language but does not have some of the above features, then consider that Jai is not trying to be as high-level as Java or C#. It is better described as trying to be a better C. It wants to allow programmers to get as low-level as they desire. Features like garbage collection and exceptions stand as obstacles to low-level programming.
These are a few proposed features that have not been implemented yet. To my knowledge they’re not yet in the language. Syntax is preliminary and likely to change.
- Joint Allocations:
Mesh :: struct {
name: string;
filename: string;
flags: uint;
positions: [] Vector3;
indices: [] int; @joint positions
uvs: [] Vector2; @joint positions
}
example_mesh: Mesh;
example_mesh.positions.reserve(positions: num_positions,
indices: num_indices,
uvs: num_uvs);
Here we want to avoid multiple memory allocations, so we have the compiler do a joint allocation between positions, indices, and uvs, and divide the memory up accordingly. Currently this is done manually in C, and is prone to errors.
- Optional Types:
do_something :: (a: Entity?) {
a.x = 0; // ERROR!
if (a) {
a.x = 0; // OK
}
}
The idea here is to prevent one of the most common causes of crashes, null pointer dereferencing. The ? in the above code means that we don’t know whether or not the pointer is null. Trying to dereference the variable without testing to see if it is null would result in a compile-time error.
- Automatic Versioning:
Entity_Substance :: struct { @version 37
flags: int;
scale_color: Vector4; @15
spike_flags: int; @[10, 36]
}
Here we are providing markup for our data structures that indicate to the compiler what version of the struct each member was present in. These versioning schemes would be used as part of an automatic serialization/introspection interface, but there are no details on that, other than that the language should have some capability of introspection.
Compilation keyword #bake to specialize polymorphic functions. A polymorphic function can contain also 'internal' polymorphic type but they can only be used after 'baking' them.
Compilation keyword #modify is used to make constraints/transformations on polymorphic types. For example, it allows to define default output polymorphic type, make only one implementation functions for different type u8..32-->u64, complex mapping to reduce the number of generated functions NdT: Powerful, but can be used to build function difficult to understand. It uses parameters names as input.
Compilation keyword #body_text takes the types of the parameters, then return a string containing the body of the function It's planned to have another keyword #body_if for 'inline' compile-time code generation.
#bake_values: a compile time specialization of some function with some (or all) parameters hardcoded. Useful to control inlining, somewhat duplicate (force) inline, but easier to use with functions with lots of arguments.
End of new features, demonstration of map which shows 'high-levelness' of Jay, but requires to free the allocated memory or there is a memory leak (no GC). And of map taking an allocator param which allows usage of the stack (faster than heap) for 'inline map'.
In the Q&A video, Blow think that 'libraries' will be pre-parsed code but not binary, to allow these features working.
04/08/2015 Demo: Bounds check, here strings, overloading. [renox, I didn't have the patience to listen to the full Q&A]
- Array Bound Checking (ABC): By default arrays(both SoA and AoS) and strings are bound checked, for optimization there is a 'no array bound checking' directive: #no_abc (which works either on a statement or on a block), you can also disable globally ABC, or enforce always ABC (ignoring the #no_abc directive).
SoA pointers are also bound checked as they're 'fat pointers' aka arrays.
- Here strings:
# string <end keyword>
...
<end keyword>
Currently no indentation support and the must be at the beginning of the line. Strings are Unicode strings. Can be empty.
- overloaded function: Overloading works as usual (and also with 'inheritance': Jai 'using' feature). One main improvement: with integer literals, the smaller int type which can support the literal is called. Works with multiple parameters. If there are several possible overload with the same level of conversion, it's a compilation error. Integer conversion are preferred to float conversion.
There are 'surprising' features related to overloading on which JB ask feedback:
-
overloading is scoped: if you can find a match in the local scope, it is selected, even if there is another better match in the outside scope baz :: (a: u8) { ... } { baz :: (a: u16) { ... } baz(100) // this use the u16 version. }
-
overloading only work on constant function definition (not on functions pointers, lambda).
-
overloading induce a 'file scope'? [renox. I didn't catch this point]
In the Q&A: parametrized type cannot be overloaded currently.
These documents were verified using Grammarly free browser plugin for Chrome. Please use some spell checker before submitting new content.
- Variables and assignments
- Language data types
- Simple user-defined data types
- Expressions and operators
- Type-casting
- Pointers
- Declarations
- Arguments / Parameters
- Return values
- Overloading / Polymorhism
- Advanced features
- Lambdas
- Arrays
- Strings
- Composition of Structs
- Metaprogramming
- Templates / Generics