Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I agree totally, my top level comment in this thread has my version of what a great C replacement would be. I'm slowly working on it.


Looks like a decent start, but not enough there to really judge it yet. Best of luck, I'll keep an eye on it! If you'd like feedback (ignore this post if not):

Caseless switch is a great idea, especially no-fallthrough by default. Consider extending it with substituion, eg "case > 7:", "case >= 13 && < 16:", or "switch longvariablename as N { case N > 13 && N < 16:". Return types after function parameters are nice, consider saying "function foo(params) returns type" instead.

Tuples always feel important but in practice I tend to not like them. Variable definitions are a bit clunky, and inconsistent with struct variable definitions. Consider ctors/dtors and/or inline member initialization. I would recommend not to compress keywords: func -> function, const -> constant, etc. "type name struct" would feel better and more consistent as "class name". The C. prefix feels like it'd be great if you only use a very small number of C APIs, and very annoying if you used a lot of them.

The boldest and coolest part is building this directly on LLVM. My thought was always to transform the IL into C (trying my best to preserve line numbers and variable names), and then let GCC or Clang build that.

My ideas were unified function call syntax (never any functions inside classes), subclasses (declare a class inside another class, but the child class has direct access to the parent class' scope), namespace-aware multi-line macros (trailing \ is grotesque), and if implementing a backend instead of a translator, zero undefined behaviors in the language (do what people expect on eg signed integer overflow instead of GCC doing whatever is fastest yet obviously wrong. Aim for hardware that is actually used today instead of worrying about hypothetical PDP-11 programs, so no 9-bit chars.)


If you're extending switch/case syntax it probably makes sense to incorporate gcc's existing ranged case extension:

https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html


I want to consider most gcc C extensions in one form or another to see if they match and don't overlap with the Go heritage.


tuples + destructuring may or may not be the way I decide to implement multiple return. Structs overlap in functionality a fair bit.

I think if you emit C code, it is much harder to get good debug information, which is important.

I am also thinking hard how to approach macros/preprocessor. For now there is none, but a powerful system could make all the difference.


I've put some thought into macros into my various cross-assemblers. One thing that's important is to have different types of macros, and different types of argument values (some that are evaluated for you, some that are intentionally not evaluated.)

    macro function square(integer value) {
      return value * value;
    }
    integer x = square(foo() + bar());  //foo() and bar() each only called once
    //square(integer) will exist as an exported function symbol
    
    macro inline twice(statement operation) {
      operation;
      operation;
    }
    twice(foo());  //invokes foo() two times
    //twice() will not generate an actual function
    
    macro class vector(type T) {
      T* pool;
      integer capacity;
      integer size;
      function append(type U) { ... }
      ...
    }
    vector(integer) powersOfTwo{2, 4, 8, 16, 32, 64};
    //any vector(type) will generate all the class functions for it


> I think if you emit C code, it is much harder to get good debug information, which is important.

I think you can annotate the generated code with certain preprocessor instructions to tell the compiler about the real source lines in order to get proper debug information. I think lex/yacc or flex/bison use that. Don't know if it's a gcc extension.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: