deft/notes/programming_langage_ideas.org
Yann Esposito (Yogsototh) 0110eee062
save
2024-02-01 15:16:14 +01:00

7 KiB

Programming Langage Ideas

tags
programming
source

Ideas

This is about a few nice ideas I had about what would be my ultimate programming language. I am not sure they all make perfect sense. But we'll see.

First, most of them are kind of inspired by practice, idea about LISP. I think most of these ideas aren't new at all. But their combination might be useful.

Syntax Agnostic

The programming world uses text editors and not AST editor. That's a fact and anyway, I don't want a programming language that would force tooling on its users. Typically this is what made DrRacket not enjoyable. I like my vim or emacs system. I don't want to use a strange IDE.

Also, people are generally used to a specific syntax. And let's be clear. This TOTALLY SUCKS. Yep, this adds an obfuscation layer to the semantic. Here, I am in the camp of LISPers that makes it a lost easier to internalize the AST of your program. But, even LISPs are not perfectly syntax agnostic.

Here is my proposed solution:

  1. Have an internal AST representation.
  2. From this representation ability to generate Text in different syntaxes, mainly LISP or C/C++/C#/Python/Java/Javascript one. Perhaps even Haskell/F#/OCaml-like. Maybe for masochists a Bash/Perl one :) etc…
  3. Have a builder that take the last modified date and sync every representations. If you change the LISP file, it will update the internal AST and the C-like. If you change the C-like, update the LISP and internal AST. If you directly modify the AST, then update all declared representations. Mainly this jobs should be run a bit like a background make.

What should this solve:

  1. If you join a new project, you can expose multiple syntaxes. So you can read the code via Github for example by looking at your preferred syntax.
  2. If you want to be 1337 dev, you can code a direct AST editor and this will still make the change visible as Text for other editors. git diff might kind of suck, but I think with minimal tooling this makes this acceptable.
  3. Having a way to be agnostic about the syntax to prevent people saying: I couldn't use that language due to its syntax. Which is really too bad. It takes some time to get use to a new syntax, but once you've done the effort to learn new programming languages a few times, it becomes a habit to switch between different kind of syntaxes and you start to appreciate a language for its semantic and put syntax concern in their right place, behind the semantic of a language.

Compile-Time Meta-constraints

Add a "mods" mechanism (a bit like in games like Factorio if you like) that add "features" to your specific project (or even sub-part of your projects).

Typically I want to be able to express either for the whole project or specific parts of the project:

  • every new namespace must be tested.
  • every new function must be unit-tested
  • Every namespace must have docstring
  • Every function must have a docstring
  • The project must have a sync'ed documentation
  • Force generative testing on pure functions
  • Every variable must have declared types for a specific type-system.
  • This sub-part of the project must be checked via a specific type-system (hindly-milner, dependent typing with a specific base, linear typing, etc…)

More importantly, the important part is that this must be explicit. One function wouldn't add a unit-test. No problem, but you MUST explicitly say so.

How could we do this. Mainly by creating "Macros", mainly ability to add code that will be run on your code at compile time to check that your code obey some specific rules. This would make a lot clearer that some code will be run at compile time. This will also make possible to add different type-system depending on what your project is focused on. For example, you can build specific type system to control the complexity of a function. But for that, you will need a mechanism that will take the AST and analyze it. And for that to work, you will need a system that will "only" add metas (so AST-level annotation) for a few core functions in the language. And if you use an "external", the module should ask you to manually annotate these unknown functions.

But mainly we want a mechanism like the clojure metas, that could be used to run compile-time checks.

Note, it would still be helpful to keep this metas at runtime depending on your need. But I am not sure how to correctly choose between compile-time only vs compile+run-time. Because if we allow run-time AST evaluation then, this will make the language a lot more powerful at the risk of making it a lot more difficult to check at compile-time and reduce a lot of compile-time advantages.

Service-compatible in the Language

The Service-Pattern is probably universal but there are many choices here. Perhaps, the best place to put this would be to put this structure in the mods and not directly in the language. But it would be very nice to have a well-designed service-dependency system.

More precisely, we want to be able to write programs with:

  • Run main with this LogService, and DBService and, intialized with this ConfigService

Have great "defaults"

I feel that if you take the time to look at Programming language evolution and history, what really makes the big differences between two programming language (at least for me) is their choice of "default".

Building the greatest programming language is about providing the ability to choose, but more importantly, providing the ability to give the best default behaviour so using the "non-default" more difficult to use and thus be somehow punished by complexity.

A good example is about old PHP SQL libs vs modern Haskell SQL libs. Mainly the main thing that changed is that before it was insecure by default, and the security concern was put as a burden to the developer to take care of. Of course, due to time-pressure and/or lazyness and/or incompetence, it was pretty natural to see a big number of security bug flourish everywhere. While if you use a modern lib, now, it is secure by default.

So:

  • immutable data structures by default (this has become a norm for great new languages, Haskell, Clojure, Rust, etc…)
  • statically checked by default (statically checked is more generic than typed by default) I think, it is important
  • documentable by default (Clojure already provides internal docstring and this is important, I think we should forbid text-only comments and replace them by contextual-aware comments)
  • debuggable, traceable by default (this one is probably a bit more difficult to be precise about. But you want your language to help his developer in not only detecting an error or a problem in its code, but give hints about how to help solve them. Elm did an incredible job at this). Mainly, log should be treated seriously and as 1st class in the language and also, not text-only but using structured logs that could be put in a DB for search in the future.