The Heck Programming Language
Mashpoe (13)

The Heck Programming Language

I think the best way to demonstrate what's cool about heck is to just show some working code:

func factorial(num) {

    if (num == 1) {
        return 1
    }

    return num * factorial(num - 1)
}

print("5! is:")
print(factorial(5)) // prints 120

I assume you're probably wondering what's so special about that code. It just looks like a standard scripting language; a python clone!

It's not!

Heck is an attempt to use type inference as well as other extremely smart compile-time checks to make simple code fast. Heck is a statically-typed, compiled programming language, with a one-liner hello world:

print("hello world")

The main design philosophy behind Heck is that if a human can understand your code, a computer should be able to as well. After all, the point of a programming language is to allow humans to communicate with computers more easily.

Many language features make code harder to read for humans, and others make it more tough on computers.

For example, many people believe dynamic typing is easier for humans to understand and harder for computers, because computers cannot determine data types when reading code for a dynamically-typed language, while humans can.

We believe this to be completely false. A program is only a good program if you can look through the code and quickly understand it. Most of the time, Python code is very easy to understand, and any programmer with a good amount of experience should be able to tell you the types of every variable, even though the data types aren't explicitly defined.

The only reason a computer can't tell what the types will be
is because of a few rare edge cases, such as reassigning variable types:

a = 6

if randomCondition():
    a = "hello"

# now you don't know what type "a" is, and neither does the computer :(

Heck simply removes these weird edge cases and reads through your code in two passes in order to fully understand everything that's going on:

// during the first pass,
// nothing about the function "add" is not known
print(add(5, 6))

func add(a, b) {
    return a + b
}

Many languages avoid interpreting code in two passes at all cost, but they only ever miss out because of this.

Looking through code in this manner allows other kinds of compile-time checks as well:

let A: int

func printA() {
    print(A)
}

// ERROR: use of uninitialized variable "A"
printA()

A = 6

// OK
printA()

In the future, Heck will have reference types, and this functionality will be used to automatically do lifetime checks, ensuring that your code is completely safe.

Heck also compiles extremely fast. In fact, since the challenge asked for "wild and exciting" ideas, our team thought this would be a perfect opportunity to target one of the most underappreciated modern web technologies: WebAssembly. The Heck compiler was written from scratch in C in order to be extremely lightweight, and this allows it to be packaged into a JavaScript library.

heck.js

Heck.js is an experimental JS library that allows programmers to quickly run Heck code on the web. Heck.js has a very simple JavaScript API that allows it to quickly make calls in the browser:

example.html

<html>
    <head>
        <script src="heck.js"></script>
        <script>
        heck.addImports({
            getRandomNumber: function() {
                return Math.random();
            }
        });
        </script>
    </head>
    <body>
        <script type="heck">
        // import a function from JavaScript
        import func getRandomNumber() -> float
    
        // prints a random number to the console
        print(getRandomNumber())
        </script>
    </body>
</html>

Heck supports most common programming constructs. You can try heck in the main repl. There is a folder titled "examples" that you can look through in order to get an idea of the language.

You can also check out the docs and heck.js.

Our team name is @HeckLanguage and the members are @Deadly_Ore and @Mashpoe!

(Edit: I fixed up the submission, before the repl wasn't included properly)

You are viewing a single comment. View All
Mashpoe (13)

@AkshantLanjewar Hello! Thank you for checking out my language! I am actually not using LLVM, but I plan on making a port in the future to make things more cross platform. Right now it directly outputs WebAssembly, which is important because Heck is supposed to be able to quickly compile in the browser (see Heck.js) and LLVM has too much overhead for that.

I don't think a null type would work for Heck since it's statically typed. As shown in the Python code snippet, changing variable types causes confusion for humans and computers, so if null had it's own type, initializing variables to null would mean that they are permanently null in a statically-typed language like Heck. Heck works more like Rust, where the compiler can tell if a variable has been initialized. There are still some edge cases where Heck can't detect uninitialized variables, but those will be fixed very soon.

The compiler does do something similar to a null check for each operation. In the second pass it keeps track of which global and local variables are initialized, so you get the same result as runtime null checks, but with zero overhead. Rust is one of Heck's biggest inspirations, and it doesn't initialize variables to null because of the overhead. The only difference is that Heck keeps track of this for each function call so things like mutable globals aren't unsafe (thread safety will be handled differently than Rust so this is ok).

Like I said, there are still some issues with this. For example, there are no initialization checks for array elements.

This issue is currently bypassed by taking advantage of the way WebAssembly handles memory addresses and the way arrays and strings are stored in memory. Each array or string is stored alongside a 32-bit integer that indicates it's size, which is much better than a null terminator IMO. I decided to put a 32-bit integer with the value "0" at the memory address "0," which acts as a "dummy" empty array or string, and then I initialized all array elements to zero by default.

If you try to access an uninitialized element of an array, there will be no issues because uninitialized strings will point to the address "0" which has a fake empty string. Access to child arrays has the same result, and integers and floats will just have the value "0."

This is not a long term solution because on most architectures null is an invalid memory address, but it enforces safety for the time being.

Also, the reason Heck has what appears to be an inconsistency with the imports is because it can't do type inference if it can't read the function body. Imported functions are implemented outside of the language and the compiler can't see what they return, so, as mentioned in the docs, the return type must either be explicitly declared or it is assumed to be void.

I hope that clears some things up. I should have specified that Heck is supposed to have the same speed as C or Rust, and that everything has to be determined at compile time. Heck is still far from perfect, but I hope it eventually becomes a language with one of the most intelligent compilers :)