Code: Select all
// type definition
typedef tval = struct {
type: int;
value: unif {
i: int;
f: float;
}
}
// equivalent to `const foo = struct { ... }`
struct foo {
elem1: cstr = "bar";
elem2 = "baz"; // type inference
}
// equivalent to `const main = func(argc: int, argv: [cstr]) -> int`
func main(argc: int, argv: [cstr]) -> int {
var x = 5;
var y: *int = &x; // '*int' is equivalent to 'ptr -> int'
var z: int32ptr -> int = y; // custom sized relative pointers
// array slicing and iteration
for argv[1..argc] -> arg {
puts(arg);
}
return 0;
}
/* A '$' defines a pattern, which gets substituted
\* In this case, we're substituting types
func add(val1: $T, val2: T) -> T {
return val1 + val2;
}
add(5, 3); // add(val1: int, int) -> int
// A '?' in the place of the return type is shorthand for '-> bool'
func valid(x: int)? {
return x > 0 && x < 10;
}
- From D, I want to borrow the notion of UFCS (Uniform Function Calling Syntax). The first parameter of a function determines what type of object that the function is associated with.
- From Swift, I'm borrowing a bit of the syntax and plan on implementing optional types. I also want to dabble a bit with memory ownership.
- From Lisp, I want to borrow the idea of being able to modify the syntax tree of the source code before it's evaluated or compiled.
- From Golang, I want to borrow CSP (Communicating Sequential Process) channels, structural typing, the error handling mechanism, and deferred statements
- From C#, I'd really like to be able to borrow the ability to define custom attributes and support type introspection and/or reflection; but I haven't really set the type system in stone yet, and I want it to actually be useful (unlike C++'s RTTI). Properties are a bit iffy.
- There is no preprocessor, and thus, no header files. Each source file is considered to be an independent module which can be imported.
- Instead of "union", there's "unif", and instead of "const char *", there's "cstr" (which is guaranteed by the compiler to be interned)
- Enums are namespaced, unless they're anonymous
- Structs will be able to be 'flattened'. That is to say you can place a 'vec3' struct inside of a 'vec4' struct in such as way that the members of the 'vec3' struct can be accessed transparently. I originally planned on using an anonymous label-based syntax for this, but I'm discontent with the idea, so it's back to being a WIP.
- You'll be able to import the namespace of a struct into the body of a function, so you don't have to constantly use indirection. (Kinda like the 'with' keyword in VB, but without creating a new block scope.
- The ability to execute arbitrary code at compile-time so you can compile resources, pre-compute expensive stuff, perform tests, or whatever else suits your fancy. I'm actually considering working at this from the opposite perspective, such that the language is interpreted (JIT-compiled) directly from source by default, but the compiler would be a library and since the language can manipulate it's own syntax trees, it can compile itself statically.
If you're wondering why there's no classes, it has nothing to do with some bold anti-OOP philosophy. On the contrary, I am very much for OOP, but there are a few stipulations:
- I think static classes and singletons are a nonsensical way of trying to create a module. If you're going to divide a huge singleton into several partial classes split amongst multiple files based on groups of functionality, just let files be modules in the first place.
- Don't mix virtual and nonvirtual elements in a class. Let the whole class be virtual, or let it not be virtual at all. Mixing the two just creates problems in the future when the implementation of a class needs to change. In this sense, a class is nothing more than an interface. I've considered an 'interf' keyword to act as a virtual struct, but the idea is still a WIP.
- Classes should only contain fields, not methods; unless the methods are delegates. This has to deal with the fact that most functionality is static, and requiring all of the static functionality to be placed inside of the class makes it annoying or impossible to extend the class with more functionality later. This is ultimately why I opted for UFCS.
EDIT:
A small update, the pattern substitution is now regressed, because I decided that semantically, structs and arrays should be passed to and from functions by reference by default; and that the `$` symbol should be used to override that.
Code: Select all
func A() {
var a1 = [1, 2];
var a2 = [1, 2];
B(a1, a2);
// a1 = [3, 4]
// a2 = [1, 2]
}
func B(a1: [int], a2: $[int]) {
a1 = [3, 4];
a2 = [3, 4];
}
Well, that's the gist of it. What are your thoughts on the design and it's applications?