Ask HN: What would be your “perfect” programming language?

41 points by hyperswine ↗ HN
Looking for opinions on what you think are the actual issues with languages. Ive heard toolchains and documentation are a pretty big part. If say, there was a language like rust + go + scala, with an exceptional package manager and documentation, would you feel compelled to try it out?

181 comments

[ 4.0 ms ] story [ 225 ms ] thread
Go without the garbage collector.
Add a better type system and you've got Rust!
Rust has quite a few additional features though.
I couldn't agree more
From a golang mentality, I think perhaps he should have said: Rust has quite a few additional anti-features though.

  import "C"
  import "Unsafe"
is all you need for manual memory management and pointer arithmetic with Go.

Since the GC is fairly light and snappy, I find it's best of both world to only resort to Unsafe for the performance critical parts, and leave the GC deal with the rest.

For more serious performance requirements, consider using jemalloc: https://dgraph.io/blog/post/manual-memory-management-golang-...

Python syntax and libraries with nim’s packaging and distribution
AKA Nim but with more libraries.
Yeah this really sounds like just Nim. Nim is great! (Though not popular enough yet)
I've actually been having a lot of fun building stuff using OpenAI Codex. I suppose something where I could write the specs and the AI spits out something resembling HTML/JS/CSS so that I can verify that I communicated correctly.

  - create a dark mode palette for the page based on this image: {file path}

  - make a form with a single name (not first and last), email, country code, phone
  -- this form should allow a document upload when clicking
  -- allow drag and drap to upload documents
  -- add a tick box that says "I agree with terms and conditions"

  - this form should have input validation
  -- all fields should be secure from injection
  -- name can be anything except number
  -- file type is documents (not images but including PDF)
  -- absolutely ban exe files

  - upon valid input, send this form to {URL}
  - if the response from {URL} is valid, redirect to {success page}
  -- else show the error message if it's type 200
Rust with Lisp syntax so I could actually write unhygienic macros without learning a bunch of arcane stuff about compiler internals.
Came here to say this. Rust is so great already, but with lisp syntax that would do it for me

By the way this already kind of exists. https://github.com/JunSuzukiJapan/macro-lisp Lisp syntax that translates to real rust at compile time. I love rust!

Ruby with python style type hints
What is your thoughts on Crystal?
Looks awesome. Haven’t had an opportunity to work with it yet but plan to.

I wish they had considered Ruby interop from inception. I am sure it's a really, really hard problem, but it would have/could have done wonders for Crystal's adoption to be able to tap into the wealth of Ruby's existing ecosystem while layering types directly in the language.

I had written two implementations of the same program in both Ruby in Crystal that need parallel (not threads!) jobs to be run. It did some more or less heavy computation on large data sets. Almost no difference in terms time execution. Crystal is nice, but if Ruby is the same, what's the point? Only thing I don't like about Ruby now is how they implemented types (in separate files... no, thank you).

But generally speaking, after 14 years of Ruby... and also trying many more languages - I do know what I want. It's not speed. It's not memory safety. It's not paradigms. It's not static or dynamic typing. It's not the packages and the community. Nope.

I want easy code navigation. I only currently know of one language, that hasn't even been fully released yet, that achieves this task to a degree. But even then, it's only 30% there.

> Crystal is nice, but if Ruby is the same, what's the point? Only thing I don't like about Ruby now is how they implemented types (in separate files... no, thank you).

You answered your own question ><

> I want easy code navigation.

Static types makes this a much, much more solvable problem. But I'm curious about what you mean here, because modern code navigation tools are pretty good - even for Ruby - but perhaps I am not fully understanding what it is that you are after.

Is sorbet too far off?
Always felt too tacked on. My opinion is that type systems can’t really work after the fact, need to be 1st class within the language.
A C++ dialect that dropped exceptions, headers and backwards compatibility (especially backwards compatibility with plain C). Everything that can be is statically linked, so no fussing about ABI. Explicitly no support for dynamically linking the std lib, or passing std lib objects across ABI barriers. One big build in a compiler that runs as a daemon, no messing about with recompiling the world in each translation unit. One implementation that works the same everywhere because it's the same code. No committee, no standard. The implementation is the standard and there can be only one.

Have thought about this a lot, I really want it. I even started messing around with implementing it, but it's just a toy (an abandoned toy, even) for now.

Very abstract question, but the code is compiling, I'll bite right in.

I think the 'ingredients' for my ideal language are more or less the following, in decreasing order of importance:

- Quality of the ecosystem. You can't buy or engineer this, it kind of has to happen naturally. Good FFI and trying not to be a "let's rewrite the world" language help immensely. It's controversial to put this as the most important bullet point, but the world we have to program in is much more complicated than it was even just 20 years ago. Programs live in an environment and have to interact with databases, networks, etc. I just don't see myself programming in a language where I have to rewrite my own data structures or network code or postgres integration, it's way too much work for way too little gain.

- Tooling. Just look at Java and Go (also Python and JS, albeit to a lesser extent). It's a massive, massive productivity gain to have modern, effective tooling that supports modern workflows.

- Language features. I'm partial to the ML family, but I'm not a radical in this respect, I'll program in almost anything as long as it's sufficiently expressive and doesn't have insane semantics.

A few _very wild_ ideas:

- A configurable type system. I'm sold that stronger and more articulate type systems are the future, but sometimes, especially in smaller projects, it's incredibly annoying to have to prove to the compiler that the code you wrote is actually allowed. There's an inherent expressivity vs. correctness tradeoff that it would be interesting to have "different settings" for.

- A dependency system based on functional semantics rather than names. Imagine to reduce each function to a canonical representation (for example: its De Brujin encoding). Now you can design a dependency system where you can import a function based on its representation rather than its name.

- First-class algebras. Imagine being able to program user-defined structured sets. Strings as monoids, Vec3 as vector spaces, calendar as affine spaces, etc.

Standard ML, but unfrozen and most of the "successorML" proposals integrated into the standard. And it has somehow sprung a large healthy library ecosystem. And the MLton toolchain has gained a REPL.
Typescript without the CJS/ESM/tooling BS. Plus a JIT compiler for performance.
TypeScript free from the historical baggage of JavaScript. With some runtime type checking, autogenerated typeguards from types, allowing things like checked de/serialization.

A TypeScript where (for example) string methods make sense, with all the number types and not just floats, with only null or only undefined and a lot of other things I can't think of right now.

Maybe add some pattern matching on top.

TypeScript's type system is so nice and ergonomic to use, it's a shame the basic objects of JavaScript (Object & co) are so "fickle" to work with.

To answer OP's question, I don't think there could be a "perfect" programming language.

This would be nice. I'd also like more traits/protocols/interfaces. I think deno is going in this direction but there is a lot more to do to get there.
Since I'm not doing lowlevel stuff, for me it would be a statically typed language that has a typesystem so powerful that it never gets in my way and lets me express all constraints in types that I need for my domain (so it must be a value-dependent typesystem or similiar). In addition, the syntax must be terse so that it's easy to define (business) datatypes and mappings easily, so that someone can come in and read those definitions quickly and understand the domain.

And then one feature that I like which few languages support are some kind of contexts. Scala does this really well for example, but even in Scala it could be improved.

What I mean is that code that looks the same can mean different things in different contexts. The typesystem then ensures that it cannot be used wrongly though.

An example would be how "5 ± 3" can mean different things depending on the context, such as "1 or 8" or "mean of 5 with variance of 3" (in statistics).

Without such a feature it's hard to translate thoughts into code as easy in certain domains.

Having the "same syntax but in multiple different contexts" is a good idea in general I feel
Rust with lisp syntax.

Like what this macro does https://github.com/JunSuzukiJapan/macro-lisp

Wait maybe what I want already exists

I personally hate lisp syntax, maybe im just no used to it or something but the (brackets (and (stuff))) feels a bit weird. Is there a reason why you want lisp syntax specifically?
Syntax like F# but with the ability to get performance like C++. Linear types seem to offer some hope of being able to have manual / non GC memory management in a functional programming language but I haven't really seen this done in a mature functional language.

To really get good performance you probably need the ability to drop down and write more procedural style code in hot code paths and expose it with a functional interface. The details of what exactly that would look like in a way that integrated nicely would be important. I'd also want to be able to easily move code to the GPU or incrementally vectorize it.

I'd also like to see the one language / runtime support everything from C++ constexpr style compile time programming through native compilation, JIT runtime and an interpreted mode for scripting with it being easy to interoperate between levels and reuse the same code across contexts.

A good ecosystem of tools and libraries with a sane package manager and build system would also be important. F# is decent there but could still use improvement.

I'd also like to see less impedance mismatch between serialization and runtime data structures and with database / relational data. Hoon is pretty interesting in how there is no real distinction between runtime and serialized data in many contexts but its harder to see how to do something like that and meet the other goals above.

Much of the above is driven by the needs of games and VR. I'm interested to see what comes out of Simon Peyton Jones working at Epic as it seems it may lead to something along these lines.

Have you tried Rust? It checks a great deal of your boxes, don't be misled by the reputation of a "systems programming language"! I made a video explaining why rust is different here, if you're interested https://youtu.be/4YU_r70yGjQ
I haven't yet, I've read a bit about it and it's on my list to try and learn it properly at some point but I haven't yet prioritized it as being pretty experienced with C++ (and liking it more than a lot of people seem to) I haven't seen a really compelling reason to pick Rust over C++ for my use cases.
Loved this series of videos!
* Strongly, statically typed.

* Good package management.

* Good, easy to reason about build system.

* Popular enough to find jobs with it.

Probably a lot more, but I don't really remember my annoyances unless they're in front of me.

I know this is not pertinent to your question, but i would like to see DLang gain more traction.
I want to write a program that has no mention of concurrency and runs efficiently on clusters anyway. So no threads, fibres, processes, actors, atomic, mutex, channels, queues, coroutines. Not in the language nor in a library.

Push the concurrency and distribution machinery into the language runtime. Developer can neither see nor influence it. Program just runs faster when put on more parallel hardware.

The price appears to be dropping mutation, severely limiting I/O and coming up with a domain independent scheduler for the runtime. So it's expensive but not impossible.

NodeJS sounds pretty close to that. Just ‘await’ anything in parallel and your code appears synchronous. Parallel code would need to be a new node process, so it’s not quite so amazing, but pretty close.
Lots of things claim to be implicitly parallel where they mean 'annotate the parallel parts yourself'. Parallel for, await, callbacks, futures and so forth. I don't want any of that annotation.
> Push the concurrency and distribution machinery into the language runtime. Developer can neither see nor influence it.

This is completely unworkable. It's based on the assumption that nodes have zero failure rate and networks have zero latency and packet loss and infinite bandwidth.

Distributed system programming is hard because you want to control the failure modes of your system as closely as possible. The opposite of hiding it.

It's based on the assumption that node and network failures can be detected (with a performance cost) and unobservably healed around.

It's also assuming that the runtime can make a good enough guess at when the ratio of data size to compute time for a task makes distribution profitable.

Distributed systems programming is indeed hard. That's why I want it pushed out of my applications.

> It's based on the assumption that node and network failures can be detected (with a performance cost) and unobservably healed around.

...which is false, especially on large scale systems. Unmanaged cascading failures are the kind of thing that caused big downtimes in various FAANGs many times.

> Distributed systems programming is indeed hard. That's why I want it pushed out of my applications.

Companies hire good software and system engineers to do this stuff.

Wasn't that the way OOP was supposed to work, back before people who didn't get it got their hands on it ? Isolated objects, messaging only, no notion of where the object resided. Just add idempotency guarantees and implicit parallelism for loops, and off you go. I can't think of any language that's actually like this though, so maybe it's harder than it looks.
TypeScript without the BC shit (and a native JIT compiler). Basically I wish for a TypeScript that’s maintained like Swift where the primary goal of the latest version of the language is for it to be the best possible language ever.
And trailing lambdas?
Aside from what's mentioned already: Longevity. Nothing is more frustrating than being forced to go through already working code just because some version update changed the syntax/semantic.
There will never be a Rust 2.0 for this reason. Perfect backwards compatibility is guaranteed forever. (New code can use new features using the "editions" system)
A universally perfect language can't exist.

There are general purpose languages (say, java, go, rust, ts, and c -- one is better than another for specific tasks), and then there are HDLs, DSLs, constraint and SAT solvers, and many more I don't even know about.

TypeScript, but the only supported module system is ESM (including extension being required like it is in the browser), there is no interface and enum (types and type unions are used instead), there are nameof and typeof operators in the language and there is syntax for getting a runtime value representing a type (for example string union into a string array) or even straight up option/syntax to selectively (up until absolutely) enforce type shapes at runtime.
To me what matters the most isn't the language but the ecosystem:

- versatility: create desktop apps, mobile apps, websites, CLI

- quality of IDE / tooling

- lots of libraries to deal with all sort of corner problems

- lots of knowledge I can google

- if used professionally: lots of talents available

For the language itself, I only really care about one thing: statically typed, just because it eliminates all sort of silly bugs and makes refactoring and navigating the code so much easier. But I am not dealing with hard computer science problems.

But the most important thing is muscle memory: not having to even think of how to solve something, just do it. We can probably adapt to any major language, but you aren't productive until you develop muscle memory. That's why I am not looking to switch to any shiny new thing unless I have a really compelling reason to do so.

- good quality standard library

- good developer tooling, e.g. a language server

- This is not yet possible, but a good optimiser which can turn an abstract representation of the code into optimal code for a given hardware (CPU or GPU). Currently we are far from this, there is probably a 10x improvement that current compilers can't achieve. See for example a FizzBuzz implementation achieving ~10x throughput improvement after months of optimisation work:

https://codegolf.stackexchange.com/questions/215216/high-thr...

More complex code is likely much more improvable.

An actual functional lang server that doesnt randomly die on you and tries its best to infer your intent would be nice.

I like that last point too, as copilot I think is going in the right direction with "step 1" of full optimisation. Maybe step 2 would be some AI based optimiser scheme to transform IR into optimal cpu/gpu ISA. Though maybe stability would be a problem

My perfect language is also C#!
Ha ha, spot on. Could be java too.
why google if the docs are great and the lang server/IDE actually shows good docs + examples on hover
Strongly typed Elixir would be it. Even better if it can be gradually typed like Typescript.

Jose announced that they are working on it but I can’t wait :p

I think you mean statically-typed, I'd like that too so I picked F#.

Elixir is already strongly typed (e.g. I think you can't use a number where a string is needed and doesn't automatically coerce).

I'd also like higher performance numerics in Elixir.

TIL the difference between strongly typed and statically typed. I’ve been using them interchangeably. Thanks for letting me know!

I’ve tried F# briefly and quite liked it too. I would like to get into it more later.

// comments would be my perfect language, write good documentation And leave the coding mostly over to CoPilot, or another AI. Although one needs to understand coding, we should work at a higher level. If you cannot write a good CoPilot prompt, i wouldn't accept you as colleague, if you cannot describe code your unable to properly write your own thoughts, makes you a team disaster. The language itself thus becomes less relevant these days, and the years to come.
I feel like this is written by a bot...
Some middle way between F#/Kotlin and Rust. Sum types, generics etc are completely non-negotiable. Something where I can use a GC for 90% and build regions of high perf or low level when needed. I want to say “in this region I want zero allocations” and the compiler will warn if an iterator or closure or something ergonomic-but-expensive allocates in that region. This is where CLR/Jvm lands often fail. I even want to be able to get rid of virtual dispatch and all pointer chasing but only for select regions. In some high level languages I can’t tell whether an abstraction comes at a cost.

In the bulk of the code I want the syntax to be as terse as possible so the business logic is as clear as possible even if it comes at a perf cost. This is where Rust often fails. The logic of something where I don’t care about perf is obscured by token salad for Box’es and similar.