Many languages still act like keyboards never changed and editors never evolved. They waste some of the most comfortable keys on invisible work, hide structure in whitespace, or overuse symbols that need Shift combinations on common layouts.

This project explores a different axis.

The goal is to design a syntax where:

  • most common operations use unshifted keys
  • structure is visually obvious
  • role of a name can be seen at a glance
  • machines can still parse everything with a simple grammar
  • users and projects can choose visual skins without changing semantics

This article is a snapshot of the current design experiments.


Table of Contents


Dash case for everything

Most languages split names with camelCase or snake_case. Both have drawbacks.

  • camelCase needs Shift for capitals and mixes visual role with typography
  • snake_case needs Shift for “_” and often looks noisy in dense code

This syntax uses dash case for all identifiers:

  • load-user
  • load-user-profile
  • compute-total-amount

Identifiers:

  • start with a lowercase letter
  • continue with lowercase letters, digits, and “-”
  • never collide with fixed keywords like fn, class, let, if

Dash case reads like natural language, keeps everything on the home row, and avoids Shift.

Unary operators can be enforced by spaces.


Roles: local, parameter, field, method

One of the useful ideas from old style naming conventions is the ability to see the role of a name without chasing its declaration.

Types do not belong in the name. Roles sometimes do.

This syntax treats role markers as optional but encouraged and possibly enforced per project.

  • Local variables
    • Plain identifiers
    • Example
      • subtotal
  • Parameters
    • Optional prefix with apostrophe
    • Example
      • 'amount
      • 'user-id
  • Member fields of the current object
    • Optional prefix with a single dot
    • Example
      • .balance
      • .interest-rate
  • Member methods of the current object
    • Optional prefix with two dots
    • Example
      • ..deposit
      • ..withdraw

Other objects:

  • account.balance
  • account..deposit 100

The core language only sees identifiers. The project can decide to enforce these patterns with a linter or formatter. An editor can even hide the prefixes visually while keeping them in the file on disk.


Comments: visible and line based

Comments are deliberately simple.

Single line comments:

  • Any line whose first character is “=” is a comment
  • Example
    • “= describe the next function”

There are no inline comments. Code and comments never share a line. This keeps lines visually clean and makes lexing trivial.

Multiline comments:

  • Experimental choice
    • /= starts a comment block
    • =/ ends it
  • Both markers must appear at the beginning of a line.

Example:

/=
This is a longer comment
It can span many lines
=/

Blocks and classes

Blocks use brackets on their own line. There is no argument about saving a few characters on a line at the cost of structure and visibility. If the method can’t fit on the screen, then it is too long anyway.

Example:

fn i32 add i32 'a i32 'b
[
  let result = 'a + 'b
  return result
]

Classes:

class bank-account
[
  i32 .balance
  i32 .overdraft-limit
  f32 .interest-rate

  fn vd ..deposit i32 'amount
  fn vd ..withdraw i32 'amount
]

In this example:

  • .balance, .overdraft-limit, .interest-rate are fields
  • ..deposit and ..withdraw are methods
  • 'amount is a parameter

The bracket form for class and method bodies is an experiment. It clearly separates headers from body and plays well with future pluggable block styles.


Function headers and the separator

Function headers are where humans benefit most from a stable visual rhythm.

The current experimental shape for a method with a single return type is:

fn i32 ..add i32 'a i32 'b
[
  return 'a + 'b
]

Pattern:

  • fn introduces a function
  • the first token after fn is the return specification
    • i32, str, or vd for no value
  • then the name
    • plain for free functions
    • optionally prefixed with .. for member methods
  • then parameter list
    • pairs of type and parameter name
    • types first, then the apostrophe prefixed name

Example free function:

fn i32 add-two i32 'x
[
  return 'x + 2
]

Visual separator with “/”

Function headers carry three distinct regions:

  • return information
  • name
  • parameter list

To make this clearer for humans without changing semantics, the syntax allows an optional separator / in specific positions.

All of these headers are equivalent at the AST level:

fn i32 ..add i32 'a i32 'b
fn i32 / ..add i32 'a i32 'b
fn i32 ..add / i32 'a i32 'b
fn i32 / ..add / i32 'a i32 'b

The separator:

  • is only recognized in function headers
  • can appear between return spec and name
  • can appear between name and parameter list
  • is ignored by the compiler
  • can be added or removed by project and user level formatting rules

The idea is to give the eye an extra handle without forcing a particular style. The separator choice is a work in progress.


Future multi return

Multi return is intentionally postponed until the basic syntax feels stable.

  • Tuple-like return type after fn
    • Example
      • fn i8, i8, i16 ..split-range i8 'start i8 'end

returns clauses or similar styles after parameters are discarded as they don’t play well with humans’ natural ability of noticing patterns when skimming through the code.

This fits into the current design without breaking existing code. The language can start with single return value only and grow into multi return later.


Tooling, projects, and personal taste

A central idea in this design is to keep the core syntax small and deterministic, but allow projects and users to shape how code looks in their editor.

  • The compiler understands a simple, fixed grammar
  • Projects can define:
    • whether role prefixes are required
    • whether the “/” separator is kept or removed
    • how strict operator spacing must be
  • Editors can:
    • render prefixes differently
    • show or hide separators
    • format code according to project rules on save

On disk there is one canonical form per project. In the editor there can be many views as long as they map cleanly to the same abstract syntax tree.

This balances:

  • human readability
  • low key friction
  • machine friendliness
  • and the reality that different people read code differently

This is still an experiment. The point of writing it down is to make the constraints explicit:

  • avoid overusing Shift
  • make structure obvious
  • make roles visible
  • give separators a place
  • keep the grammar boring

The rest can change as the language gets exercised by real code.


Summary

The ideal scenario is to create a truly universal language that can be used across all the domains.

I believe that such a language is not only not as hard as it might seem, but realistically achievable.

My goal is to attract people interested in developing such a language and fund it through both individual and organisational means.

It is not a fantasy, but a reality that no one has done yet, and it would be a big step towards making the world a better place.


References


Further Reading


Attributions

The following image is used under a Creative Commons license:

DIY means choosing the right tool for the purpose – a watchmaker’s nightmare

Attribution: “DIY means choosing the right tool for the purpose – a watchmaker’s nightmare” by Franz van Duns, licensed under CC BY-SA 4.0.

License: https://creativecommons.org/licenses/by-sa/4.0/