tentacode thoughts

A place to house devlogs of member’s projects.
Post Reply
syn9
Posts: 20
Joined: Sun Jan 09, 2022 4:59 pm

tentacode thoughts

Post by syn9 »

Update:
I've started language documentation with links to source and binaries here: Tentacode Documentation.
I'll be removing items from the list below as they become documented at that link.

Original:
We were discussing the idea of making a simplified c dialect in the discord today. I thought I'd post my personal language loves/hates on here to keep track of in case we decide to actually make something. Feel free to contribute. This list is a work in progress and by no means a list of must-haves.

Things I like
loops and breaks to labels

Code: Select all

my_label: loop { // infinite loop with label
	loop { // inner infinite loop
		if break_inner() {
			break;
		} else {
			break my_label; // break out of outer loop
		}
	}
}
range syntax

Code: Select all

a = [0..5]; // vector with values: 0, 1, 2, 3, 4
b = [0..=5]; // vector with values: 0, 1, 2, 3, 4, 5
foreach context for for loop

Code: Select all

for c in "my string of characters" {
	println("character: {c}");
}
enumeration version

Code: Select all

my_list = [1, 2, 3];
for it in iterator(my_list) {
  x = it.value;
  y = it.key;
}
// or
for {key, value} in iterator(my_list) {
  x = value;
  y = key;
}
unicode strings, but able to access raw character array if desired
helpful compiler / interpreter warnings
ability to break to repl
being able to break and inspect the values of variables at runtime
being able to give someone a small exe that has all the library dependencies built in and is small
easily being able to run on web
ability to print formatted strings to console + ability to build formatted strings

Code: Select all

x = 5.758889;
println("raw val: {x}, 2 decimal places: {x:.2}, truncated to i32: {}", x as i32);

s1 = "fizz";
s2 = "buzz";
y = string("{s1}_{s2}_{}", x);
z = s1 + "_" + s2 + "_" + x as string; // equivalent to above
ability to load resources in background threads
the ability to eval("code();");
being able to join vectors

Code: Select all

b = [1, 2, 3];
c = [4, 5];
d = 6;
a = [b, c]; // a = [1, 2, 3, 4, 5]
a = [a, d]; // a = [1, 2, 3, 4, 5, 6]
structures with functions --> ok to get rid of entirely by using namespacing, maybe only used for constructors...

Code: Select all

struct MyStruct {
	a, // type will be inferred later
	b: i32, // explicit type
	c: string, // trailing comma is ok

	def member_func() {
		println("value of member vars: {a}, {b}, {c}");
	}
}
memory allocation for a struct is only the memory required for the member vars, nothing else
memory allocation and default instantialization of user defined types with zeros
being able to put underscores inside numbers for readability

Code: Select all

a = 1234567;
b = 1_234_567; // equivalent
default pass by value to functions, with optional pass by reference

Code: Select all

x = "string";
x = reverse(x); // pass by value and return reversed string
reverse_by_ref(x); // pass by ref and reverse in place
would be neat to have some ECS ideas as first class elements of the language
the ability to include other source files so you can break up your code

Code: Select all

include "subdir/code.ext"; // equivalent of dumping the contents of code.ext into this location
include "code.tt" as mod; // public include
internal include "code.tt" as mod; // private include
ability to print out the type of something

Code: Select all

x = 1.5;
y = "test";
z = MyStruct();
println("x is a {x:?}, y is a {:?}, z is a {:?}", y, z);
built in map types

Code: Select all

x = ["a" = 5];
y: map<string, i32> = ["b" = 7];
z: map<int, vec<f32>> = [5 = [1.1, 2.2, 5.5]];
z["c"] = MyStruct();
candymap = ["a" = "apple", "b" = "banana"; "c" = "chocolate"];
for k, v in candymap {
	println("candymap[ {k} ] = {v}");
}
built in set types

Code: Select all

x = {1, 2, 3};
y: set<string> = {"a", "bb", "ccc"};
set operations

Code: Select all

// all equivalent to x = {2, 3};
x = {1, 2, 3} & {2, 3};
x = {1, 2, 3} - {1};
x = {1, 2, 3}; x{1} = {};
matrixable arrays

Code: Select all

x: vec<vec<f32>> = [[0, 1, 2], [4, 5, 6]];
x[0][1] = 4;
pre-filled arrays

Code: Select all

x = [1; 5]; // equivalent to x = [1, 1, 1, 1, 1];
slicing using ranges

Code: Select all

x = [0; 5];
x[2..5] = [1..=3]; // equivalent to x = [0, 0, 1, 2, 3];
clearing/empty notation

Code: Select all

// empties an existing map/vec/set, or creates a new one if not already existing
x = [];
y = {};
tuple destructuring

Code: Select all

v = (1, "a", 3.5);
x, y, z = v;
array to set to array conversion

Code: Select all

x = [1, 1, 2, 2, 3];
y = x.to_set(); // y = {1, 2, 3};
z = x.to_set().to_vec(); // z = [1, 2, 3]; equivalent to z = x.unique();
built in nan and inf types

Code: Select all

x = 1/0; // equivalent to x = inf;
finding inside vectors, getting index of values

Code: Select all

x = [1, 2, 1, 2, 3, 4];
i = x.find(1); // i = [0, 2];
i = find(x == 1); // i = [0, 2];
i = x.find(2, "first"); // i = [1];
i = x.find(1, "last"); // i = [2];
i = find(x == 1, "last"); // i = [2];
i, v = find(x > 2); // i = [4, 5], v = [3, 4];
_, v = find(x > 2); // temporary created for index and immediately freed
y = [1, 2, 3, 4];
z = x[y > 2]; // z = [3, 4]; ??
w = x == 1; // w = [0, 2];
vector subset using a vector

Code: Select all

x = [10, 11, 12, 13, 14];
i = [1, 2, 3];
y = x[i]; // y = [11, 12, 13];
empty checking

Code: Select all

x = [];
if empty(x) { println("x is empty"); }
if x.is_empty() { println("x is empty"); }
built in binary and ascii file handling
built in graph / tree / linked list
built in swap using destructuring

Code: Select all

x = 1; y = 2;
x,y = y,x; // x = 2, y = 1
RAII and auto-free when leaving scope

Code: Select all

x = MyStruct(1); // allocate and construct x
{
	x = MyStruct(2); // allocate and construct local x
	f = fopen("test.dat", "w");
	f.println("{}", x.val());
	// f gets closed when leaving scope, equivalent to manually calling f.close();
	// local x gets free'd when leaving scope
}
// original x is here
boolean types

Code: Select all

x = true;
y = false;
functions as objects

Code: Select all

mult = @ i32 = (a, b) { println("returning {a} * {b}"); a * b } // anonymous function object
y = mult(1, 2);

grid_mult = # [i32] = (&a, &b) { a[GRID_ID] * b[GRID_ID] } // grid function object (compute / parallel dispatch)
c = [1, 2, 3]; d = [4, 5, 6];
y = grid_mult(c, d);
ability to extend the functionality of an object like adding ECS components to entities
assigment using block as expression

Code: Select all

x = {
	a = 2;
	b = 3;
	a * b // no semicolon, block return value is the value of the last line
}; // x = 6
one thing i like about c/++ is that if statements evaluate from left to right and break out early if not satisfied
built in random number generation without having to load a library or module, to include range notation

Code: Select all

x = rand(); // float value between 0 and 1
y = rand(0..3); // integer value in [0, 3)
z = rand(0..=3); // integer value in [0, 3]
built in assert capability

Code: Select all

x = 1;
assert(x == 2); // shows assert at line number
assert(x == 2, "assert message"); // optional additional message to display if assert gets triggered
built in reflection on structures / types
inferred types for function parameters and return values if you're not explicit.

Code: Select all

def myfunction(x, y) { // parameter type inferred from caller
	return x * y; // return type inferred from parameter types
}
block assignment

Code: Select all

vec2f pos = { 2.2, 3.3 };
tuple<f32, enum> z = { 5.99, :COFFEE };
set<i32> w = { 5, 3, 1 };
Brighämmer: destructuring syntax mirrors the literal syntax

Code: Select all

const {foo, bar} = getObj(); const [first, second] = getArray();
from rob: braces can be removed for implicit destructuring

Code: Select all

i32, i32 my_func()
//equivalent to
{i32, i32} my_func()

a, b = my_func();
//equivalent to
{a, b} = my_func();
"using" syntax for typedefs

Code: Select all

using TileMap = vec<i32>;
Brighämmer: I really want to be able to write something like

Code: Select all

const foo <= bar(each items) 
and bar gets dispatched across however many threads for every item, and foo ends up being a joinable channel or promise or something

----



Things I kinda like
big hurdles to using pointers
no null data type - things can only be concrete
no automated type conversion, or at least compiler warnings whenever types are not explicitly converted
functions and variables in structs that are default private but can be public
assignment using match arms

Code: Select all

x = match y % 2 {
	0: "fizz", // if y mod 2 is 0, then set x to "fizz"
	1: "buzz",
};
return expressions

Code: Select all

def bool = is_equal(a, b) {
	if a == b {
		return true; // explicit return
	}
	false // expression return
}
constants and when the compiler warns me if a const isn't upper case

Code: Select all

x = 5; // mutable and inferred type
MY_CONST: const = 10; // immutable and inferred type
MY_CONST_STRING: const string = "an immutable string";
having a built in for raise-to-the-power

Code: Select all

x = y ** 3; // equivalent to: x = y * y * y;
built in performance profiling
easy to play languages/interfaces like matlab, processing, and shadertoy
inline if/for/while/loop without having to use curly braces

Code: Select all

if 4 < 5 : println("pass");
for x = 0..3 : println("{x}");



----



Things I hate
whitespace as scope
fussing with project files just to get something to run
math functions as member variables: (5.6).cos();
having to have header files
when the compiler forces me to use a certain text case for things, except constants
when I can't do: x += 1; and am forced to use x = x + 1;


Link for future self when this is ready to be a compiled language: https://llvm.org/docs/tutorial/MyFirstL ... index.html
Last edited by syn9 on Sat Sep 14, 2024 9:10 pm, edited 22 times in total.
syn9
Posts: 20
Joined: Sun Jan 09, 2022 4:59 pm

Re: tentacode thoughts

Post by syn9 »

I put together a simple interpreter based on the Crafting Interpreters book including some of the above ideas and feedback in the channel.

Here is a small guess-the-number game.
guess-output.png
guess-output.png (7.06 KiB) Viewed 1746 times
guess-code.png
guess-code.png (25.51 KiB) Viewed 1746 times
User avatar
Sirocco
Site Admin
Posts: 806
Joined: Fri Feb 12, 2021 10:25 pm
Location: Outer Demoscenia
Contact:

Re: tentacode thoughts

Post by Sirocco »

As far as C goes, vectors being a native type and not something that was bolted on would be nice. GLSL has nice bit-swizzling. I'd love to be able to easily add or multiply vectors in a single command.

Obviously with strings, *anything* is better than what comes out of the box. Dirt simple concatenation would be great.
Also I feel like tokenization could be simplified (strtok) and I use that fairly often to parse strings for config files, scripts, etc.

I'll probably think of more later. The problem with working in C is that after so many years, my brain has worked around all the wonky bits, and just doesn't think too much about it. But then you hit something with strings and then it's right back to the reference pages/manuals lol.
syn9
Posts: 20
Joined: Sun Jan 09, 2022 4:59 pm

Re: tentacode thoughts

Post by syn9 »

oooo, built in swizzling like GLSL would be pretty sweet, good idea.

a full up rock-paper-scissors game in 75 lines:
rps-output.png
rps-output.png (23.39 KiB) Viewed 1741 times
rps-code.png
rps-code.png (63.65 KiB) Viewed 1741 times
syn9
Posts: 20
Joined: Sun Jan 09, 2022 4:59 pm

Re: tentacode thoughts

Post by syn9 »

testing out some built in raylib support


Image
wave-code.png
wave-code.png (36.33 KiB) Viewed 1732 times
Post Reply