Skip to content

Comment on Ask HN: What features would your ideal programming language have?

Comments

I think that different kind of programming languages can be suitable for different purposes, although I do have many ideas, anyways.

Some of them are:

- Macros (both hygienic and unhygienic)

- Bitwise manipulations

- Less confusing syntax for types than C has

- ASCII based (not Unicode, although you can write programs to work with data in any character set, including Unicode)

- Meta-programming

- Low-level features

- You have enough ropes to hang yourself, and also a few more just in case

- GOTO and GOSUB

- Direct dealing with the stack

- GADTs (without runtime support)

- Control over optimizations in different parts of the file

- Better namespacing

- Binary include files

I am sorry I did not write more elaboration of this. Also, I have more ideas too, but did not write them on here right now.

So a couple of questions.

In terms of control flow, why do you need GOTO, why GOSUB instead of a normal function call, and what do you mean by "direct dealing with the stack?"

This sounds a lot like a version of C++ without the cruft and C backwards compatibility. Which is a fantastic idea, and I know it's been attempted many times. Which languages out there today do you think fit your criteria the closest?

I don't want GOSUB instead of a normal function call, but in a few cases it is helpful to have it in addition to having normal function calls. In BASIC, a subroutine called by using GOSUB can RETURN either to where it was called from or to a different label (but, unfortunately, RETURN to a label is not allowed inside of a subroutine with SUB or FUNCTION). Also, subroutines called using GOSUB are in the same scope as the caller. (Usually, normal function calls would be used. But sometimes, GOSUB is helpful.)

GOTO is sometimes the best and clearest way to make something, although usually it will not be needed. Ideally, other flow controls such as FOR, WHILE, etc would be defined in terms of GOTO by use of hygienic macros, rather than being built-in features. You can then define your own flow controls too if you use some pattern a lot that giving that pattern its own name and macro is useful.

Direct dealing with the stack can be used to do some stuff normally done only in assembly language (although GNU C has some stuff, such as reading the stack pointer). But assembly language is specific to the target computer, and many libraries are not designed to be used with assembly language programs. However, some direct dealing with the stack might also depend on the target computer. Macros producing inline assembly code may be used if needed.

I do not know which other programming languages do such thing.

The concept of implementing high level control flow on top of a lower level control flow primitive via macro expansion is how most LISPs work. But instead of GOTO it's something more structured, like a match statement and recursion. It's also how compiler tend to lower for/while loops into IR before hitting the assembler. And it sucks to implement naively, since you need additional passes in your macro expansion/compiler to fold loop bodies and get decent vectorization without requiring a user to write it manually.

I don't really see the usefulness of GOSUB over normal function calls. Same with goto exposed to a user, it's not any more useful than typical control flow and is a giant footgun both in terms of logical errors made by a programmer and performance impact since arbitrary control flow tanks the ability of a compiler to reason about the program.

Still not sure what you need to do with the stack in assembly that can't be implemented in higher level constructs. There's good reason you can't mess with it too much even in low level languages, you can't always reason about stack frames in a given program or when integrating with programs compiled in other languages.

Well, I like "footgun" since it enables more possibilities. I don't like it to try to stop the programmer from writing a program.

But for the ability of a compiler to reason about the program, can't it first be converted to basic blocks anyways? Then it is irrelevant if you use goto or not, since the result will be same either way.

Footguns don't enable more possibilities other than the possibility to shoot yourself in the foot. Arbitrary control flow is pretty much the textbook example of that. It doesn't allow more expression or make it easier to express the same concepts, it makes it more difficult for the author, future readers, and tooling to understand what is being expressed in the first place. Not to say it isn't necessary for the implementation of languages on the hardware, just that the additional complexity of such a construct is better served by being generated from higher level syntax through automation like compilers or virtual machines.

As for the question of conversion to basic blocks, the question to me is at what point does your macro expansion turn into a compiler plugin or extension? I think the idea of hooking into the compiler at different points in the pipeline and expanding it on a per-project basis is really cool, and it's an old idea that's present in many LISPs. Racket and Scheme have extremely expressive macro systems that allow you to basically write a compiler. It'd be really interesting to have a language where the compiler/virtual machine had great hooks for extensions written by the author of a program being compiled, so they could do crazy things at progressive levels of granularity and unsafety. I think MLIR has some support for that, but it's more a target like LLVM than a language in its own right.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.