Hacker News new | ask | show | jobs
Ask HN: Is there a simple and minimal language like C but without its footguns?
15 points by apoorvagk 1700 days ago
I want to pick a new programming language that is simple and minimal like C but does not have the type of footguns C has (segmentation faults, double-free issues, etc.)

C++, Java, Rust are far from minimal. Go feels minimal but it too has a lot of features compared to C and it has a garbage collector too.

Here are some things I am looking for:

* Compiles down to machine code.

* Does not have the footguns of C.

* Simple like C.

* Implementations available for all major OSes, at least, Linux, Mac, Windows, *BSDs.

After extensive search I got the feeling that it is difficult to find such a language. If I am willing to let go "simple like C", then it provides a lot of options like Rust, Nim, and all. Just asking here to see if I missed something during my search.

24 comments

Take a look at Zig (ziglang.org). Not sure it meets all of your requirements, but looks like it might. I haven't worked with it yet, but it's on my radar, as is FORTH, for the simplicity aspect you mention. And I should mention Tcl, but that's a scripting language so not what you asked for, but just in case, no, Tcl isn't 'dead', it's in most of the Cisco and other IT infrastructure equipment that's getting this website to you, it runs most of Flightaware's infrastructure, and is in all sorts of places quietly doing its job; it's how SQLite was started (as a Tcl extension, and Tcl is still a first class citizen w/r to SQLite). The creator of Redis wrote a good article on Tcl (which Redis was started in). Oops. This became a Tcl sales comment. Sorry! :)

http://antirez.com/articoli/tclmisunderstood.html

Zig is the only lang that meets the description. Very few languages can be used to write system etc code. As OP pointed, Rust and C++ aren't minimal or simple. In such a narrow field, this leaves Zig. Maybe Ada.
> Does not have the footguns of C.

> Simple like C.

You have to pick one, or give in on both and find a happy medium between the two. The way you get safety in a language is by abstracting over the simplicity.

I personally would suggest biting the bullet and going with C++, you can stick to a reasonably sane subset of the language but it definitely won't be C.

> You have to pick one, or give in on both and find a happy medium between the two.

I'd say Pascal is simple, and has fewer foot guns than C. It might be too simple - but one can do a lot with freepascal/Lazarus.

Or go with Ada. Also somewhat simple, I'd say.

Though a lot of the footguns in C are not due to its lack of safety but rather due to the decades of historical baggage it carries.
> You have to pick one. The way you get safety in a language is by abstracting over the simplicity.

It should be noted that there are languages developed as safe dialects of C, such as Cyclone[1], whose design goal was to have it both ways and enhance C's safety while preserving its simplicity.

[1] https://en.wikipedia.org/wiki/Cyclone_(programming_language)

Seems like Go might be able to fit your bill. AFAICT the designers of Go has gone out of their way to avoid adding cruft to the language.

Yes it has GC. What is it that you want to build though? Will GC be in the way? If so, I would consider Rust instead.

C is simple, true – but in many cases it seems like that fact pushes the complexity up to higher layers instead.

C still has it’s place in embedded. And our best kernels are currently written in C. Outside of those domains I don’t see much reasons to start a greenfield project in C.

OP:

  > C++, Java, Rust are far from minimal. Go feels minimal but it too has a lot of features compared to C and it has a garbage collector too.
You:

  > Seems like Go might be able to fit your bill.
  > I would consider Rust instead.
That's exactly what OP did not want...
True! But if OP wants a dialogue about language choices then IMHO it could be good to motivate the reasons. E.g. they didn’t explain why they didn’t want GC.

As others have pointed out in this thread, there are good reasons why Rust is designed the way it is.

With that said, I hope the OP will find a language that they like and can be productive in. Hopefully they input from this thread can be of guidance.

Pascal, modula, zig?

Zig sounds mostly like what you want, though: https://ziglang.org/

Possibly a subset of D could work, too:

https://dlang.org/blog/2018/06/11/dasbetterc-converting-make...

But likely the D language will be too big?

Nim took some inspiration from the Pascal/Modula/Oberon family, notably for its type system. It had an original goal of having a small and simple core, with a powerful macro system allowing extensions where needed, but the language core definitely grew over the years. It's still way smaller that C#/Java/C++. Might interest OP.
There are two publicly available contenders: Odin and Zig.

Each one has its own way in which it deviates from C in a way that some people might not like. Odin is probably a lot closer to C than Zig. Zig tries to bring some of the more recent ideas into the low level programming space (compile time null checking, builtin "T or error" types, etc.

https://odin-lang.org/

https://ziglang.org/

Of course there are some other contenders, but having looked at them, either they are not even serious enough, or they deviate from C way too much, with GC, closures, etc.

Pascal, Zig, V and possibly Crystal. Or Das C although arguably that is a subset of D.

V isn't anywhere near finish. The closest thing should be Zig. But that is far from finish as well.

Crystal is more like Go than C. But I mean someone wrote a OS [1] using Crystal in her spare time.

Or just plan old Pascal.

I mean if you are looking for simplicity like C and compiled to machine code you virtually ruled out 95% of all programming languages. Other languages like Lua is simple. But certainly dont fit the bill.

[1] https://github.com/ffwff/lilith

You don't seem to like garbage collectors, or manual memory management (with which you'll get segfaults and double-free issues) or complexity (where the intermediate ground between manual and automatic memory management comes in, with compiler hints, etc.)

This doesn't seem like a satisfiable set of constraints. I'd recommend removing "not garbage collected" from the constraints, as automatic memory management mostly got introduced to reduce footguns.

That set is easily satisfied by giving up dynamic memory allocation. Barring compiler bugs or hardware errors, COBOL and Fortran in their original versions never ran out of memory (applications might report that a data set was too large to handle, but the OS knew how much memory the application needed and gave it to them), didn’t segfault, nor had double-free issues.

With 64-bit CPUs and virtual memory, that might even be a viable approach for some applications. You would have to decide up-front how many Foo’s, Bar’s, etc. to support, but you can set those limits very high (the old solution to that was to replace a card dimensioning some arrays and recompile)

Weird? Yes, for current thinking, but you would get a simple language.

Free Pascal is more elegant, and has runtimes everywhere. Normally you can avoid pointers, however if you need to use them, the syntax makes it easy to see what you're doing.

Strings are memory managed for you, and can even include nulls.

See the Free Pascal project[1], and the Lazarus IDE[2]

1 - https://www.freepascal.org/

2 - https://www.lazarus-ide.org/

No one has mentioned it here, but maybe Pony?
Love the suggestion but I don't think it's as simple with reference capabilities. It's easier and safer in the long run, but not simpler.
Nim is what you are looking for.
Yes, it is called C with Experience. Write code like a fantasy scientist: track what you're doing, document what works and what does not, and maintain that reference-sheet across multiple projects. Like a scientist is supposed to work. Your foot guns will vanish.
GNU's GCC has added Ada and NetBSD has that in a package. Space Technology uses Ada and Forth.
I’m not sure if Ada counts as “simple” as C (maybe so, maybe not depending on where you find complexity, but I find it funny at at this point the Ada spec is smaller than the C++ spec.
Ada is definitely more complex than C, but not as complex as C++. If you can draw the parallel between .h/.c and .ads/.adb files, you're halfway to using Ada-as-C. If you then learn the basic procedural syntax and just enough about packages to be dangerous, you can use Ada as a moderately safer C.

You have to learn the type system, task and protected types, and a few other things to really get the advantages of Ada, though. While those aren't hard, they aren't "simple" in the same way that C is simple. But you can learn them piecewise, which is good, as it permits incremental learning of the language.

Yeah I guess part of my line of thinking was the the undefined behavior of C is a sort of complexity you may not get in Ada.

I actually love the language, and am kinda sad it doesn’t see much use anymore. I saw a job some weeks back that involved porting a bunch of Ada code on VAX to C#/Windows and I just didn’t have the heart to apply lmao.

"Java is far from minimal"

My web servers run with like 300MB of RAM and work fine on t2.nano serving thousands of users??

And also Java gives you full access to primitive types if you don't like OOP

I think he means that Java is not a small language, rather than it doesn't take up much space in RAM.

Personally, I still think that C is a very good compromise between size (both of the language and of its RAM usage) and it's level of abstraction.

The size of a language can be judged by the size of a definitive text on learning the language. Compare how small the K&R book "The C Programming Language" is [230 pages] compared with (say) the O'Reilly book "Learning Python" [1200 pages].

I respect this argument but I'm curious as to how the smallness of a language would be beneficial to a developer, if the goal is to be able to rapidly build applications which are still quite performant.

C, when run on the same exact machine as Java, is only a few x faster in the best case scenario to my understanding. And as complexity of the application grows, there is a chance that you don't manage your memory properly, something which a garbage collected language usually does well enough.

Couple in the rich libraries for both languages, I think I would still choose java unless I was writing an embedded system.

With a WM, and a rather complex language.

And of course if you had written that in C it would probably have taken up a lot less.

Just use C and be careful when you use pointers or arrays.
Nim!
I encourage you to reconsider the idea that C has footguns. Having written quite a lot of C, I no longer fear the rougher edges of C. Avoiding them takes time to get used to, but they're the price you pay for the ultimate simplicity of C.
When a comment like this[1] with a complete historical account of the origins of C has to be written in order to explain a weird behavior, you know you have footguns.

[1] https://news.ycombinator.com/item?id=28954260

C with valgrind can be relatively safe. Sort of enforcing the safety outside of the language and into the surrounding tooling.

And sticking to some common heuristics goes a long way towards safety. Some people think it's impossible to write safe C, but you can.

So the answer is C.

Depending on your definition of machine code, Lua may fit the bill.
What about just picking a subset of C++?

C + smart pointers and container types?

I personally love nim and zig for these reason
red-lang isn't bad. Golang. Terra. Nim. Forth. Pascal. Zig. Rust.
Forth?
Footguns!? LOL