Ask HN: What features would your ideal programming language have? - msvan
======
unlinked_dll
I'm really intrigued by Jai because it has many of the ideas I want to see in
more languages and has pretty killer syntax. The concept of a meta program
that Jonathon Blow talked about on the "On the Metal" podcast is wild.

A macro syntax that was both expressive/hygienic, but allowed for better
integration with tooling (frequently tools have no introspection into expanded
macro code, and debugging macros almost always sucks). I'm not sure how to
solve this problem however, but I think procedural macros in Rust are a decent
enough start (debugging them sucks right now, but I see no reason why that has
to be the case).

Along the same lines of the previous paragraphs (programming things around the
program itself, like meta programming) is that the build process in most
languages sucks, and requires using outside tools in different languages (be
it a config file, make script, python/shell scripting, etc). I'd really like
it if I could write my entire build process in the language I'm building,
including pre/post build steps, specifying a dependency tree, etc.

An idea I love to work with is a purely declarative syntax, similar to
configuration languages like TOML or JSON. But inside declarations you can
write imperative code that synthesizes your declarative code programmatically.
Now you can do this in JS today with some discipline, and make it kinda typed
in Typescript. But if you have a fairly strict and limited type system and
good error messaging/debugging workflow it's actually a fairly powerful
concept. It helps deal with the oscillation in the industry between
"configuration is code" and "configuration is actually a bitch to write for
complex systems." You can start with a pure configuration for your system, but
then as complexity grows write imperative code that synthesizes the
configuration.

~~~
AnimalMuppet
I'd like to suggest one refinement to your idea. Being able to write the
entire build process in your language is great. _Having_ to write it in your
language may be not so great. Allow the option of using alternate build
systems without the build process being crippled.

~~~
unlinked_dll
The way I'd implement it is exposing the compiler/build tooling as a library
and then a command line front end on top of it. So any tooling that can exec a
CLI would be able to build for the language, but you could also compose a
script that imports the tools as a library. The hairy ness is that you
probably don't want arbitrary code execution in the build scripts themselves,
I know there was the idea of executing the pre build scripts for rust projects
by compiling to WASM and executing in wasmer or another sandboxed runtime to
deal with that problem.

But in my ideal language you'd probably have a repl or virtual machine that
could be sandboxed and used to execute the build scripts, including invoking
the compiler as a library.

------
photon_off
I would like to be able to delineate strings with any character(s) of my
choosing. The default could be single or double or triple quotes, but don't
force me. I am sick of escaping characters in literals, I'd rather define a
delineator that I know isn't in the string. Same for templating.

    
    
       let name = "Jane";
       let str = s{}:John said "Don't do that, {name}!":s
    

I would also like a JSON-like shorthand for declaring nested structures,
without having to define each individual component separately. Eg:

    
    
       struct Person {
          user: {string name, int age},
          address: {string street, ...}
       }
       let p = new Person(<json>);
       print(p.user.age);
    

Convenience with arrays (python slicing is nice), maps, and primitive types
pay huge dividends.

    
    
       arr.first();
       arr.last();
       arr[5,-5];  //5th to 5th to last
    

Built-in arbitrary length/precision numbers would be neat.

Besides that, tons and tons of useful libraries: IO, Date, JSON, DB Bindings,
etc.

------
matijash
As some already mentioned below, in my opinion it would depend on the purpose
of the language. In the case of the general language, these are some of my
personal favourites:

\- expressive type system

\- easy & intuitive to start with, but also powerful if needed (low floor,
high ceiling)

\- has a relatively small set of core concepts which are then composed
together to build things further

\- rich set of libraries (although pretty obvious and not really a feature)

I think our search for the "grail" general language will continue, probably
forever. Languages such as Haskell, Rust & Go (and probably a lot of others I
haven't heard of) are breaking the boundaries and introducing new concepts
which then slowly spill over to more "mainstream" languages (e.g. the advent
of functional programming constructs we are witnessing in Java, JS etc.).

Other than that, I also believe that more and more DSLs will start appearing,
which is basically languages specialised for a specific purpose - which will
make them extra convenient in their domain but not usable in the general case.
Also, I expect the tooling (IDEs, build systems) to become more tightly
integrated with the language, especially for the DSLs - creating the end
product which at the end will be usable not only by the programming experts.

I have actually, together with my brother, been working on such an idea for
the past year. We made a DSL for the domain of web apps - it is basically a
declarative language that compiles to the stack of choice implemented in the
general language (e.g. React/Node). This makes it possible to express some
web-app specific concepts with much less code, but is also constrained to that
specific domain.

If anybody wants to take a look it is here: [https://github.com/wasp-
lang/wasp](https://github.com/wasp-lang/wasp)

Would be interesting to see the results of your research and what majority
thinks are the ideal language features.

------
zzo38computer
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.

~~~
unlinked_dll
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?

~~~
zzo38computer
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.

~~~
unlinked_dll
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.

~~~
zzo38computer
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.

~~~
unlinked_dll
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.

------
billconan
I want something like literate programming, documentation is enforced somehow.
Or diagram can be translated into code and vice versa.

------
Hackbraten
First-class support for a version manager so that 20 years from now, I will be
able to check out my project and build it immediately using the locked
platform version.

A build system that makes it super easy to do the right thing with regard to
locking dependency versions.

A compiler backend that generates reasonably small binaries.

------
marto1
Most probably features that, in the end, contradict each other.

For example have all the nitty-gritty cool features for a low level
programming language BUT also maintain Python-tier readability.

------
gshdg
Basically Python with better anonymous functions, no GIL, and a sane consensus
solution to package management and running multiple versions of the language
on one system.

------
partisan
Nim, but with a sane naming convention, less dependency on the underlying C
language, and stability across versions.

