Readit News logoReadit News
imglorp · 2 years ago
Flashbacks to TA'ing freshman programming 101 in Pascal: every student got hung up on when to use a period or semicolon or end. And from Austral's fib example (snipped)

    module body Fib is
        function fib(n: Nat64): Nat64 is
            if n < 2 then
            else
            end if;
        end;
    end module body.
We here all understand BNF, Ada, Modula, etc and parsing but imagine explaining to the first day student: Why is there no "end function" like for the other contexts? When do I use a semicolon vs a period to close a context? You shouldn't need the "railroad diagram" to understand the syntax.

zetalyrae · 2 years ago
Declarations don't need `end function` because it's always clear what you're closing.

Statements need an `end if`, `end for` etc. because it lets you find your way in nested code. The rationale for the syntax explains it a bit: https://austral-lang.org/spec/spec.html#rationale-syntax

FWIW I will probably get rid of the `module is ... end module.` bit because it adds unnecessary nesting.

imglorp · 2 years ago
I appreciate the explicit nest around module. I was just suggesting a symmetric and consistent syntax that can be stated simply, to align with the stated goal.

Dare I say, the (important) bit of Lisp syntax fits in a sentence! Yeah they hide the complexity in the library instead...

lelanthran · 2 years ago
> Statements need an `end if`, `end for` etc. because it lets you find your way in nested code. The rationale for the syntax explains it a bit: https://austral-lang.org/spec/spec.html#rationale-syntax

From the link:

>> }

>> }

>> }

>> }

>> }

>> Which one of these corresponds to the second for loop? Unless we have an editor with folding support, we have to find the column where the second for loop begins, scroll down to the closing curly brace at that column position, and insert the code there. This is manual and error-prone.

I'm not fully convinced of that argument. Here's a devil's advocate take...

The keywords do indeed help when the corresponding nested control structures are off-screen, but if the code you are reading is not refactored to move the control structures into their own function so that the indentation doesn't get that much out of hand, you likely have bigger problems with the code than determining which `end` corresponds to which control structure.

IOW, having this sort of identification is moot: if it is needed, then the code itself is in such poor condition that it's likely not very readable anyway. In many cases it won't make a difference anyway (nested 'if's, for example - seeing multiple `end if` doesn't help) and the developer is still going to place a comment specifying which particular `if ()` is being ended.

Having the unadorned closing braces (`}`) leaves the developer one of three options:

1. Refactor that code just to be able to read it, or

2. As you point out, add in comments like `// end if`, etc, or

3. Leave it as it is.

If it's left as is, there's bigger problems in the code anyway.

Deleted Comment

webkike · 2 years ago
Why? No ability to nest functions? Why do you need a semicolon at the end of "end"?
mrkeen · 2 years ago
This language looks super promising. With the exceptions of 'no type inference' and 'no arithmetic precedence', I really like its anti-features list.

With regard to 'no arithmetic precedence', I tried

    printLn((1 + 2) + 3);
and

    printLn(1 + 2 + 3);
Sure enough, the first one compiles, but the second doesn't.

Also, (n-1) is a parse error unless you put a space after the minus.

I got curious if recursion was properly handled, given it wasn't in the anti-features list, but no luck:

    module body Foo is

        function go(acc: Nat64, n: Nat64): Nat64 is
            if n = 0 then
                return acc;
            else
                return go(acc + n, n - 1);
            end if;
        end;

        function main(): ExitCode is
            printLn(go(0, 135000));
            return ExitSuccess();
        end;

    end module body.
yields

    Segmentation fault (core dumped)

colanderman · 2 years ago
I prefer the rule in my own languages of "no arithmetic expressions whose meaning can be changed by adding parentheses". So `x + y - z` is allowed but `x - y + z` is not.
gpm · 2 years ago
If operators are over-loadable, you support floats (in a non ffast-math mode), or you treat overflow in most non-modular-arithmetic ways, (x + y) - z and x + (y - z) are different.

Maybe it's worth saying "they're close enough to the same that parentheses should be optional", but I can definitely see the argument for just requiring them regardless.

danaugrs · 2 years ago
This is a cool idea that I hadn't heard or thought of before.
zetalyrae · 2 years ago
I wouldn't rely on TCO being available, the bootstrapping compiler right now just emits very simple C (though GCC/LLVM might eliminate the recursion if they can).

Ideally I'd like stack overflow to be a clean abort rather than a stack overflow (just to make the error message more explicit) but I haven't got around to adding that.

joshmarlow · 2 years ago
That's curious - one of the example programs computes the fibonacci sequence. The language is clearly still a work in progress. I wonder what the difference is in your recursion and what's listed?

https://austral-lang.org/examples/fib

mrkeen · 2 years ago
> I wonder what the difference is in your recursion and what's listed?

How deep you recurse :D

olodus · 2 years ago
I disagree with you about 'no type inference'. I understand why some swear by type inference, but personally I prefer the complete clarity it provides to avoid it. If writing those characters annoys you, have tooling help you with avoiding that.
saghm · 2 years ago
For a language that seems to market itself based on being secure, this is pretty troubling
verdagon · 2 years ago
Austral is still alpha, so this kind of thing is expected. It's heading in a good direction, give it some time.
Scarbutt · 2 years ago
I would add 'no macros' being a no no too.
jll29 · 2 years ago
For me, this is of interest:

  Austral’s module system is inspired by those of Ada, Modula-2, and Standard ML, 
  with the restriction that there are no generic modules (as in Ada or Modula-3) 
  or functors (as in Standard ML or OCaml), that is: all modules are first-order.

  Modules are given explicit names and are not tied to any particular file system 
  structure. Modules are split in two textual parts (effectively two files), a 
  module interface and a module body, with strict separation between the two. The 
  declarations in the module interface file are accessible from without, and the 
  declarations in the module body file are private.

  Crucially, a module A that depends on a module B can be typechecked when the 
  compiler only has access to the interface file of module B. That is: modules 
  can be typechecked against each other before being implemented. This allows 
  system interfaces to be designed up-front, and implemented in parallel.
It was a mistake how C++, Java and other languages forgot to split interface declaration from implementation definition, IMHO. Good to see that Austral learned from Modula-2.

Before I can form an opinion regarding Austral, though, I would need to see some larger programs implemented in it, for instance some low-level systems code, a generic data structure, some high-level business logic.

meindnoch · 2 years ago
>It was a mistake how C++, Java and other languages forgot to split interface declaration from implementation definition

Huh? C++ is split into header files (interface) and cpp files (implementation)...

sk0g · 2 years ago
I guess there is no "strict separation" in C++, since that mechanism is, I believe, optional. Adding implementations to your header files might never pass PRs, but still.

It does enable header-only libraries though.

creata · 2 years ago
But there's no .cpp file for many (most?) uses of templates.
gcoakes · 2 years ago
Is no one going to talk about their capabilities system? That shit looks cool. A compile time permissions system for which resources can be used. I wonder how fool proof that can be made. Are there escape hatches in the form of arbitrary assembly/linking? Could a leftpad module security issue be deterred with this?
andyferris · 2 years ago
Yes, any leftpad-like security issue could be mitigated by the fact that you’d need to inject strange capabilities like network access to the leftpad function.

It is assumed this would raise eyebrows from the user of this function. Furthermore if you were to take a “safe” function and replace it with a dodgy one in a later version, the function signature would change and users would need to update their code. So nothing quite so brazen would get past.

Of course if you are mixing in arbitrary assembly/machine code in your binary via linking that might make a syscall and that could potentially be unsafe.

seagreen · 2 years ago
Did not expect docs to be this exciting...

    On July 3, 1940, as part of Operation Catapult, Royal Air Force pilots bombed the ships of the French Navy stationed off Mers-el-Kébir to prevent them falling into the hands of the Third Reich.
    This is Austral’s approach to error handling: scuttle the ship without delay.

KRAKRISMOTT · 2 years ago
The British would probably be happy to do that even without the Third Reich. There are still British people today pissed about the French surrendering too quickly.
jonathankoren · 2 years ago
Given how controversial the British attack was on their allies even after the French assured them that ships would not be captured, I guess this passage is, as the kids say, "shots fired". :)

https://en.wikipedia.org/wiki/Attack_on_Mers-el-Kébir

radioknight · 2 years ago
The creator of Austral writes good fiction https://borretti.me/fiction/
crabmusket · 2 years ago
I really love the Design Goals and Rationale sections of the specification[1]. I have an interest in the landscape of new low-level languages like Odin[2], Vale[3] etc. Austral has the clearest "statement of intent" about how it is designed and where it is going.

[1]: https://austral-lang.org/spec/spec.html

[2]: https://odin-lang.org/

[3]: https://vale.dev/

pbarnes_1 · 2 years ago
This is cool but everything is too verbose.

`austral compile hello.aum --entrypoint=Hello:main --output=hello`

vs

`go build`

Etc etc.

TOGoS · 2 years ago
On the contrary, I like it when the interface to my tools err on the side of precision at the cost of verbosity. I can always write a shell script or Makefile that does all the boring stuff once I've learned what the inputs mean, but if a tool only provides an overly simplified interface, it is much less obvious what it's doing, or what the other options might be, if any.

What does `go build` do? What files does it implicitly rely on? I have no idea. But I have a pretty good idea of what that `austral` command is going to do without having read any documentation about it.

badrequest · 2 years ago
You might, but I don't. In the argument `--entrypoint=Hello:main`, where does `Hello` come from? Is it some root module? What about `main`, is that some default, or the name of a file without an extension? This strikes me as just enough verbosity to be confusing, and not enough to be explicit.
ithkuil · 2 years ago
Feel free to invoke "go tool compile" manually. "go build" is just a frontend
zetalyrae · 2 years ago
The idea is the compiler has a bunch of explicit flags, but the build system (which doesn't exist yet) will have the `foo build`, `foo run` etc. commands and find the files using a package manifest.

Essentially like `cargo` vs. `rustc`. I have a little prototype of the build system in Python but haven't pushed it up yet.

adamrezich · 2 years ago
what's encouraging you to conceive of the build system and the language as separate things? I never understood why most people making new languages seem to want to have each of these be distinct—why not just define the build using the same language?
angiosperm · 2 years ago
I appreciated that it listed "no destructors" immediately after the top-line "no garbage collection", so I didn't need to read any further. What it means is it offers no ability to encapsulate resource management, so not useful for me. That doesn't mean it is not useful to others.
zetalyrae · 2 years ago
No, on the contrary, Austral is entirely built around resource management. The central concept is linear types, which is about ensuring 1) resources are disposed of and 2) resourced are used according to their protocol, e.g. no use-after-free.

There's "no garbage collection" because Austral lets you have manual memory management without the danger, like Rust.

There are no destructors in the sense of special destructor functions which are called implicity at the end of scope, or when the stack unwinds. Rather, you have to call the destructors yourself, explicitly, and if you forget the compiler will complain.

This sounds verbose until you start paying attention to all the mistakes you make all the time that involve, in some way, forgetting to use a value. The language makes it impossible to forget to do something.

olodus · 2 years ago
People might feel like it is too verbose, but I think it is good to have the clarity. I write C at my day job and I have no problem with the 'verbosity' if it provides clarity of what happens. What I want is the compiler to help if I ever forget who owns a particular data value and miss to clean it up. For that linear types are perfect. I also prefer their simpleness over Rust's affine types which easily gets very complicated (see the difference between theirs and your borrow checker). Linear types gives me an easy way to define basic "state machines" for how to handle the data using types and then verifies that I implemented them correctly. That is kinda all I need. Feels like a good "get shit done" language.
rprospero · 2 years ago
From my reading of it, it does have what you're looking for. Specifically, while there are "no destructors", you are required to call a function to consume the value. Failing to consume the value is a compile time error. You can roughly approximate thinking about this as having destructors, but you're required to explicitly call them and the compiler won't let you write code that doesn't call the destructor.
lelanthran · 2 years ago
This is nice. It does seem mutually exclusive with any early return though, like exceptions.

On the phone now so I only read the page on linear types, but will look at this closer when back at my desk.

In my own language I am considering destructors purely so that early returns are viable. I'd like to see if there is any alternative to destructors that aren't 'defer' or similar.

adamrezich · 2 years ago
the page "What are linear types?" seems to address "resources" and the management thereof. not my cup of tea (but then, neither are destructors and garbage collection), but it's an interesting idea.
epage · 2 years ago
At least linear types means you'll never forget it. It also solves the problem of what to do when your destructor needs to error (e.g. closing a file).

The big downside is the verbosity of covering every branch of your code with your explicit close calls unless another mechanism is provided.

And it doesn't seem like succinctness is a top priority for this language.

adastra22 · 2 years ago
You missed a chance to learn something.
lionkor · 2 years ago
didn't read it yet, but that are other ways, specifically something like `defer` in go or zig

Dead Comment