Reminds me of Nim, but with more Python influence on the standard library and overall syntax. It does share the ideal that a Python-esque syntax can be nice for system's programming.
Its surprising how fun programming can be when you eschew unneeded syntactical complexity! Though personally I prefer having memory management and lifetimes handled automatically by default, but with the option for manual management when desired.
BTW glicol looks & sounds really good. I have always day dreamed how I would DJ but instead of using traditional tools, I'd be using a programming language to do it. I never had guts to do it in real life tho! :)
I wish every programming language website was like this. First thing you see is a short description the language, with an image on the side showing example code. Beneath that, a short example program that does something non-trivial. This is the way.
I'm late to the party, but I want to say thank you for sharing this. It's inspiring to look at how much you've built and (hopefully) enjoyed the process of building! I'm loving everything -- your site, your language design, your docs, your builtin libraries, your dev tools. Beyond impressive. People like you are the ones who make HN one of my best places on the internet.
For context on where I'm coming from, about two weeks ago I picked up Crafting Interpreters [1] for fun. I'm finding your clear-yet-concise Compiler internals [2] to be particularly compelling reading, and jumping back and forth between those "how this all works" docs and the live example of this language you actually built do a WASM-compiled tree-blowing-in-the-wind animation is just... just wow. So freaking cool!
I also enjoyed reading the comment thread that inspired you to start on Yaksha and seeing how this project has a wholesome start as inspiration-by-programming-hero. I hope you recognize that a few years later you've now ascended from inspiree to inspirer. I also hope you're still having tons of fun building out Yaksha!
Do you mind having a "Why a new language?" primer with some deeper philosophy on your choices? I will never question anyone's desire to make a language for learning or hobby. However, when presenting it to the world for practical use, there has to be some persuasion to move people off of existing tools.
I use Nim at work (I'm lucky) so I'd love to see that comparison in particular, it also being a transpiled-to-C language. I also use it to build static binaries with musl-libc and it's quite easy and clean.
Sure, main goal was fun. But I should have a write up some time.
I wanted to see following:
1) Does manual memory management become easier when you use python-esque syntax?
2) OpenCL with @device like syntax so you can mix kernel code and client code in same .yaka file. - Not even started (Not sure if achievable with my time constraints)
A programming language is closer to an instrument, not actual music.
Why make a new instrument that sounds the same as another instrument? You would expect new instruments to make different sounds, not just have a different control scheme.
I'm very surprised that this is actually a single person's workload. "Because I am also a programming language designer and developer, I have worked in it for approximately 3 years, and it also supports compiling to WASM." https://github.com/KusionStack/KCLVM
I have seen its language design and compiler implementation, and I am sure I will continue to follow and watch the development of Yaksha Programming Language. If possible, I would like to contribute.
Very nice. I had experimented with transpiling Python to C straight from the AST in Python itself. Does this plan to add type inference or "generics"? Currently it appears everything must be explicitly typed.
I think the Language Grammar section doesn't correctly report the grammar you have implemented. For example the "if" and "while" statements lack the condition!
Really nice language. Would you mind describing the modules/libraries system? I see you have a Python-style import and I'm curious how you implemented this in a language that compiles to C.
Everything compiles to a big .c file.
capntr - tool that acts as builder knows which part of runtime to compile and link.
Imports are not dynamic like python. Does not have all the features of Python import also.
What's with newer languages putting types after variable/function names? Then you need an extra symbol : or -> and a function keyword. It also breaks readability of long function headers as you have to read the name skip to the end to read the return type then back to the first argument. Is there a good reason for this trend?
Well, note that partly due to the way variables and functions are declared in C and C++, parsing those languages (especially C++) is a complete mess.
I think the readability argument is pretty subjective. Personally I find declarations in for instance Rust a lot easier to quickly scan than C++. For one thing the names of functions are all at the same offset, which to me is actually the most important thing. I can see at a glance whether it's a function or variable being declared. I've never found the fact that the return type is at the end to be a problem - why would it be?
The convention dates back to at least ML in the 70s, possibly even longer time back. So it is not some new thing, it's recent rise in popularity is more a reflection in MLs increasing influence in language design space.
If I'd had to guess, the syntax might be inspired by math notation such as x ∈ ℝ
It makes me wonder why C put the ultimate type on the left and not on the right.
C type/variable declarations are an expression that transforms the type/variable into a primitive type, which is then annotated on the left of the expression. Why not on the right?
Because parsers, like humans, read from left to right. Important parsing decisions are usually made as early as possible. An example is recursive descent parsing, which derives its simplicity from making decisions first, allowing a top-down parse. And when humans skim text, I bet it can be shown that it's easier if the syntactically significant locations are aligned near the beginning of each statement.
The intent, as I understand it, is that "declaration should look like use", so that the base type is on the left. If you declare
int *foo;
then
*foo
is an int.
IMHO the existence of "cdecl" is evidence that it might not have been the right choice.
Declaration should look like use is nonsense though. I mean, what is the practical benefit of putting the pointer to the left of the name instead right to the type? For pointers the difference is literally just on which side of the space the asterisk sits at the expensive of making it unreasonably difficult to represent nesting of type constructs.
Some languages use the colon syntax, such as the Pascal family. Others, like Rust and Gleam, use the arrow syntax.
The arrow syntax meshes better with the idea that there's a difference between the types of values, and the meaning of a function signature. "foo: t" declares a name "foo" as having a type "t", but functions are abstractions — what is the "type" of factorial()? It's not "int".
The type of factorial() could be written:
(int) -> int
or just:
int -> int
If you look at the ML family as well as Haskell, that's exactly how they express it.
They do that for other reasons, too; those languages follow lambda calculus, which only has single-argument functions, so all functions are simply mappings between a single value to another value.
I think the C syntax was actually a compromise to simplify the grammar. Remember C dates back to the 60s, and computers had very little RAM and storage back then, so they had to be very clever in how they designed the language. The C function pointer syntax is the way it is because you can reuse the same grammatical rules for parsing types as you do expressions. Pointers are prefix and function calls are suffix.
Because type before name is simply worse in every metrics, hard to parse, hard to omit when infer (change to auto, var, etc), hard to grep for definition (hence the hack <type>\n<name>).
Why do you care about the return type before the name?
If you had never heard about C and its legacy, and were to create your own programming language, would you come up with a syntax like C's?
The structure 'term: definition' is pretty common in many natural languages and has a lot of advantages: all terms are aligned, you can sort them, you can grep the term you're looking for, etc.
I even think it should be extended to functions, too. That 'def' ruins the harmony. Instead of
def factorial(int) -> int
it should be
factorial: fn(int) -> int
You trade a keyword ('def') for another ('fn') but open the way to lambdas (just the part after the colon).
I agree that the -> serves no purpose, it could be made optional. Alternatively one could require the -> and dismiss the 'fn' keyword, like this:
factorial: (int) -> int
It's slightly harder for the parser who has to wait until the -> to understand what it's reading, but it's doable.
About putting the return type after the parameters, that absolutely reflects how I reason about functions: I will want to first examine its input, and then its output. Even the man pages for common functions and commands explain the parameters first, and leave the return value last.
Variable/Parameter names are nicely aligned so there's less scanning to read them. Personally I usually read function arguments before return type, but I can see instances where I'd want to look at return type first. If you're line breaking on parameters for long function signatures, it's not so bad though—the return type will be in a predictable place.
The : and -> are not strictly speaking necessary. Some languages, like go, put the type after the variable name and return type at the end of the function signature without requiring a : or a ->.
Having to always use a colon before the type is better than having to sometimes write "typename" before the type. Not to mention that it makes the code easier to read.
Looks pretty cool! What happens if a program attempts a use-after-free? If this is "memory safe" (aside from leaks) then I think it sits in a pretty interesting space!
Nice! My initial take: love Python-inspired languages but I think manual memory management is distinctly anti-Python so not sure how well that works together.
What's wrong with compiling to C? By using C as an intermediate language LLVM can be a backend through Clang, but so can GCC, MSVC, Intel C, etc. It's actually a pretty common choice (see Nim, Chicken Scheme, etc.).
This is totally unrelated to the language itself, but...
You have my greatest appreciation for building proper responsive websites in all those links, with proper CSS styles and sizing (rem units)!
I use a 40" 4K screen (no HiDPI) and almost any other website, including the most popular ones (I just checked github, google, bing) do not really follow responsible principles, use px units, and end up using just a tiny column of the screen... and they are not even consistent: bing and google use the left 1/3rd of the screen, github the central 1/3rd.
I had to scale down the design to 50% scale to get it to fit on my screen without everything looking huge and wrapping, but after that everything looked usable.
My experience is that tiny text is the style. I'm much more likely to have to scale something up than down. I can't remember the last time I scaled something down, but I scale things up every day. (I also liked the size choices of the OP... honestly wouldn't have minded slightly bigger).
You don't even need a setup like that to feel that pain. That pretty accurately describes my experience with those websites - and many others - with just a 24" 1920x1200 monitor.
The weird silver lining is that most sites are also using fonts a bit too far on the small side for me, and don't respond too well if you jack them up much. But that unused 2/3s of the screen ends up allowing most websites to take a fair bit of zoom without any changes in layout.
----------------------------------
Tech stack: Code is written in C++ for the compiler
carpntr - which acts as the builder is built using Yaksha itself. (I use a python script to bootstrap and carpntr to build carpntr as a second step)
hammer - cross compiler for C/C++ projects written in Yaksha (I'm building Linux version of Yaksha compiler on Windows box leveraging `zig c++`)
Yaksha comes with zig to use zig cc.
Runtime: this is written in C. (There are no .dlls involved, things get built statically, only subset will be built and linked)
Standard library: written in Yaksha.
YakshaIntelliJ - written in Java
Various scripts - Python.
Its surprising how fun programming can be when you eschew unneeded syntactical complexity! Though personally I prefer having memory management and lifetimes handled automatically by default, but with the option for manual management when desired.
Since you mentioned wasm, I think it would be great to have a REPL on the website in the future.
REPL I have been thinking for a while, I'm not sure how I would do it unless there is a way to run zig cc in browser.
Would be harder without having a backend at the moment as it needs to run a C compiler to generate the final executable. (Not an interpreter)
For context on where I'm coming from, about two weeks ago I picked up Crafting Interpreters [1] for fun. I'm finding your clear-yet-concise Compiler internals [2] to be particularly compelling reading, and jumping back and forth between those "how this all works" docs and the live example of this language you actually built do a WASM-compiled tree-blowing-in-the-wind animation is just... just wow. So freaking cool!
I also enjoyed reading the comment thread that inspired you to start on Yaksha and seeing how this project has a wholesome start as inspiration-by-programming-hero. I hope you recognize that a few years later you've now ascended from inspiree to inspirer. I also hope you're still having tons of fun building out Yaksha!
[1] https://www.craftinginterpreters.com/
[2] https://yakshalang.github.io/documentation.html#compiler-int...
I use Nim at work (I'm lucky) so I'd love to see that comparison in particular, it also being a transpiled-to-C language. I also use it to build static binaries with musl-libc and it's quite easy and clean.
I wanted to see following:
1) Does manual memory management become easier when you use python-esque syntax? 2) OpenCL with @device like syntax so you can mix kernel code and client code in same .yaka file. - Not even started (Not sure if achievable with my time constraints)
Why make a new instrument that sounds the same as another instrument? You would expect new instruments to make different sounds, not just have a different control scheme.
https://www.reddit.com/r/ProgrammingLanguages/comments/11vnm...
[1]: https://en.wikipedia.org/wiki/Yakshagana
I think the readability argument is pretty subjective. Personally I find declarations in for instance Rust a lot easier to quickly scan than C++. For one thing the names of functions are all at the same offset, which to me is actually the most important thing. I can see at a glance whether it's a function or variable being declared. I've never found the fact that the return type is at the end to be a problem - why would it be?
fn first_function(...) -> i32 { ... }
fn second_function(...) -> Vec<i32> { ... }
const X: i32 = 0;
vs
int first_function(...) { ... }
vector<int> second_function(...) { ... }
int X = 0;
If I'd had to guess, the syntax might be inspired by math notation such as x ∈ ℝ
C type/variable declarations are an expression that transforms the type/variable into a primitive type, which is then annotated on the left of the expression. Why not on the right?
IMHO the existence of "cdecl" is evidence that it might not have been the right choice.
It probably helped that I just parse to an AST that’s generated so experiments like this are trivial.
Also, some people say that it makes for easier (less ambiguous?) parsing.
But the -> part is a bit weird. It "shouldn't" be
but it "should" be Maybe it's that way because of Python?The arrow syntax meshes better with the idea that there's a difference between the types of values, and the meaning of a function signature. "foo: t" declares a name "foo" as having a type "t", but functions are abstractions — what is the "type" of factorial()? It's not "int".
The type of factorial() could be written:
or just: If you look at the ML family as well as Haskell, that's exactly how they express it.They do that for other reasons, too; those languages follow lambda calculus, which only has single-argument functions, so all functions are simply mappings between a single value to another value.
Why do you care about the return type before the name?
The structure 'term: definition' is pretty common in many natural languages and has a lot of advantages: all terms are aligned, you can sort them, you can grep the term you're looking for, etc.
I even think it should be extended to functions, too. That 'def' ruins the harmony. Instead of
it should be You trade a keyword ('def') for another ('fn') but open the way to lambdas (just the part after the colon).I agree that the -> serves no purpose, it could be made optional. Alternatively one could require the -> and dismiss the 'fn' keyword, like this:
It's slightly harder for the parser who has to wait until the -> to understand what it's reading, but it's doable.About putting the return type after the parameters, that absolutely reflects how I reason about functions: I will want to first examine its input, and then its output. Even the man pages for common functions and commands explain the parameters first, and leave the return value last.
1) Easy to parse (less ambiguous) 2) We like Python
zig wraps things up to a nicer package, so I thought might as well use zig cc.
It has a C#-like syntax.
Logo is based on traditional Sri Lankan Yaka/Yaksha/Raksha mask.
You have my greatest appreciation for building proper responsive websites in all those links, with proper CSS styles and sizing (rem units)!
I use a 40" 4K screen (no HiDPI) and almost any other website, including the most popular ones (I just checked github, google, bing) do not really follow responsible principles, use px units, and end up using just a tiny column of the screen... and they are not even consistent: bing and google use the left 1/3rd of the screen, github the central 1/3rd.
[1] Full size: https://i.imgur.com/R0I6Vxs.png
[2] Half size: https://i.imgur.com/tQ6KpR4.png
Not sure if huge text is just the style these days, though. Probably looks great on a huge screen.
Other CSS are probably just luck ;)
The weird silver lining is that most sites are also using fonts a bit too far on the small side for me, and don't respond too well if you jack them up much. But that unused 2/3s of the screen ends up allowing most websites to take a fair bit of zoom without any changes in layout.
I really don't get modern website design.