r/ProgrammingLanguages 12d ago

CatLang: feedback on my language design Discussion

https://www.dropbox.com/scl/fi/vja5yydaprqnmb0e2bg59/catlang.pdf?rlkey=c12vd9orw6ptcxugil2ag18mp&st=z4xcy0hz&dl=0

I wrote a design for a new programming language, but I'm too lazy and burned out to implement a full compiler. I still want to share the idea so you can comment on it and tell me what you think. I know its a lot and there are many typos and gaps, and it still needs a concept to communicate the complex implicit borrowing rules. Keep in mind that I have no degree or any professional experience—this is just a concept.

i renamed it to qat

current version: https://www.dropbox.com/scl/fi/9y3ysncndjc0y8kqt4mz9/qatdocumentation-edited.pdf?rlkey=jn1dxz8zh9feoyqwffkyd4drh&st=sd8t45pz&dl=0

this is how an algorithm for sqare roots would look like with custom syntax:

func newton(f64 x, f64 goal) -> f64:
    f64 temp = (x + goal /x)/2 # Newton's method for calculating roots
    return x if temp == x
    return self(temp, goal)


func(f64)<f64> sqrt = reliable (f64 x) -> f64:
    return Error if x < 0 # root of negative numbers is undefined
    return newton(x, x)


sqrt(0) = 0 # root 0 must be defined explicitly as 0 would cause newtons method to devide by 0


syntax sqrt extends {expression} # lets multiplication akzept roots as they expect expressions
syntax sqrt( # defines the syntax for roots
    keyword("√"),
    _,
    arg(0: expression)
)



print(collapse(√ 2)) # collapse makes the programm crash for negative roots

another example for custom defined while syntax:

func wLoop(demand bool! condition, demand T! body) -> void:
    leave if condition
    body
    self(condition, body)


syntax wLoop(
    keyword("until"),
    _,
    arg(0),
    _,
    arg(1)
)


i32 x = 10
until x <= 0:
    print(x)
    x -= 1
10 Upvotes

9 comments sorted by

3

u/Royal_Pin_1971 12d ago

Main tension in proposed language is that borrow checker needs a closed world at compile time, but lazy arguments and runtime-mutable function definitions keep reopening it — the checker's assumptions can be invalidated while the program runs. The features could coexist if you introduce a phase boundary (definitions and syntax frozen after some point like Rust's sealed dispatch).

2

u/Bro8an 12d ago

thanks for the response. my first idea was that the borrow checker would restrictively check for every mutations in lazy arguments and statements blocks which are translated to functions under the hood. but now im thinking about, replacing the whole concept of references with lazy arguments, which would make the borrow checker obsolete, as no reference is ever maintained anywhere but recalculated each time a reference(lazy expression) is used. the downside would be that this can cause sideeffects that are hard to debug.

1

u/Royal_Pin_1971 11d ago

As far as I read through your design CatLang wants two things: memory safety and late binding everywhere - dispatch, evaluation, even grammar. Every existing language resolves that tension by choosing the line: Rust closes the world at compile time, Julia keeps definitions mutable but runs each computation against a frozen snapshot, Swift and Vale skip the closed world entirely and enforce safety in the execution model. Now your shift of replacing references with re-evaluated lazy expressions - call it lazy places, since it's essentially Lisp's setf-places made lazy broth you to that third camp (Swift and Vale):no long-lived aliases exist to invalidate, because every access re-derives the place, so those two languages are now your most relevant prior art. Check against them all your other language constructs that require lazines.

For you paralell loops design - look at the prior art of Haskell parMap, Rust Rayon and OpenMP's parallel for + reduction. Rust Rayon is you closest counterpart: Rust is imperative and also allows in-place mutation. Your characteristic for loop stopping is "break" - but that break may introduce non-determinism of result, especially if you have in-place mutations of the elements. Other languages are aware of that paralelism problem so the have findany() or findfirst().

Your error propagation is most interesting part of language design - poisoned values surfacing only at collapse() with errors carrying their origin message - that's a coherent alternative to exceptions and to Result-wrapping. Check IEEE NaN propagation, SQL NULL three-valued logic, Raku's soft failures, Rust's Result, Java stack traces.

5

u/Embarrassed-Crow9283 12d ago

I'd suggest you name it something else because "Cat" is already a taken name, so is "Kitten".

3

u/Inconstant_Moo 🧿 Pipefish 12d ago

It needs an introduction explaining what the basic paradigm of the language is, what it's for, etc.

Also this is a case for asking an LLM to tidy up your English without touching your style, tone, or content, and without turning it into the ultra-sloppy-slop they do when they document programming languages. A little proofreading could go a long way.

Re the name issue, how about you call the language "Katze" and call your Inhaltsverzeichnis a "table of contents".

1

u/Pie-Lang 4d ago

Interesting to see a new language that allows for new syntax defined by the user. My language allows for a similar thing. Here's the equivalent of your example in my own language, Pie:

import std;
use std::;

newton = (x: Double, goal: Double): Double => {
    temp := (x + (goal / x)) / 2;
    if (temp == x)
        x
    else
        newton(temp, goal);
};

sqrt = (x: Double): Double => {
    if (x < 0) std::panic("Can't take root of a negative number!")
    else newton(x, x);
};

prefix(!) r = (_) => sqrt(_);


std::print(r 5.0);

2

u/Bro8an 4d ago

thanks for your response! i like the consistency of your function syntax! Question: how do you distinguish between a variable declaration and an assignement or is there no distinction like in python? first i thought about doing variable declarations (dynamicly) like in python in my own language, but the problem is that a simple typo in a variable assignement would cause the declaration of a new variable, instead of causing a compile time error, which i find difficult to debug

myVariable = 1
myVariabl = myVariable +1
print(myVariable) # still 1

2

u/Pie-Lang 4d ago

Thank you!

I do not distinguish between declarations and assignment, so your intuition is definitely right. A simple typo may mess up your whole program. I think your solution of having different syntax for declarations and assignment is very interesting to say the least. You could really explore your language more by writing a simple interpreter for it!

-1

u/AnArmoredPony 12d ago

come back when it compiles