74 comments

[ 7.1 ms ] story [ 143 ms ] thread
When Java came out, before it stabilized, it was often jokingly called C--.
Before Java, Bill Joy proposed "C++++-=":

https://donhopkins.medium.com/bill-joys-law-2-year-1984-mill...

>Bill Joy’s Law: 2^(Year-1984) Million Instructions per Second

>The peak computer speed doubles each year and thus is given by a simple function of time. Specifically, S = 2^(Year-1984), in which S is the peak computer speed attained during each year, expressed in MIPS. -Wikipedia, Joy’s law (computing)

https://en.wikipedia.org/wiki/Joy%27s_law_(computing)

>C++++-=

>“C++++-= is the new language that is a little more than C++ and a lot less.” -Bill Joy

>In this talk from 1991, Bill Joy predicts a new hypothetical language that he calls “C++++-=”, which adds some things to C++, and takes away some other things.

>[...] The MIRVing of the Alto user interface into multiple new metaphors means that we are moving into very unfamiliar ground. Everybody should get a Macintosh and understand what’s special about it. We still have a long way to go.

My coworkers used to joke that we used C++ but wrote C--. I never knew the Java joke or that someone made it into an actual standalone language.
I'm familiar with a different C-- developed by Peter Cellik which appeared before the language in the article (1997). But the article has no mention of it. The discussion page of the article does mention there used to be many languages called C-- with similar ideas and the article only talks about a specific one
Related:

Welcome to C-- (2008) - https://news.ycombinator.com/item?id=30006215 - Jan 2022 (23 comments)

The C-- Language Specification (2005) [pdf] - https://news.ycombinator.com/item?id=19429522 - March 2019 (27 comments)

C--: A Portable Assembly Language - https://news.ycombinator.com/item?id=17966114 - Sept 2018 (1 comment)

C-- - https://news.ycombinator.com/item?id=6621679 - Oct 2013 (72 comments)

Pretty sure there have been other threads. Anyone?

The problem with things like this is that "compile to C" isn't really just done for ease of implementation, but for sheer portability - individual C compilers are widespread, and the totality of them are basically ubiquitous. The Quick C-- compiler mentioned in the article only supported x86.

So the only way I would see something like this work, is as a frontend for an existing compiler. LLVM itself makes this kinda superfluous there, so that leaves gcc?

(comment deleted)
https://takenobu-hs.github.io/downloads/haskell_ghc_illustra... shows how it (well, the Cmm fork) is used to compile Haskell code with GHC
GHCs Cmm is an interesting beast. It changed a bit from C-- and it doesn't seem to be "sold" outside of the Haskell market, but it does feature basically the best of all worlds: A native generator targeting most current platforms, a LLVM backend (resulting in basically the same platforms, but maybe with different performance characteristics), and even a compile-to-C option.
One of the criticisms I have heard of C-- is that it doesn't distinguish between integer and floating-point data in the type system. There are some architectures where that wouldn't be a problem, but most modern CPUs have completely separate integer and floating-point data paths, with a performance penalty for shuffling data between them. Generating good code on these systems from C-- source requires more effort than it should.
Modern architectures have different register banks for the two, but that's irrelevant, C-- is not register-centric.
Isn't the point of C-- to be an IR, easily compileable to assembly on the target?
No the other way around - easily emittable, letting the backend in turn do the heavy lifting to lower it.
The backend can of course try to guess what type of register data should live in, but it's not always going to make the right decisions if it doesn't have type information to work with.
Type information is not what conveys that information, it's the operations used on the data that matters.
They have a reason for doing things that way, which they state in the specification (in the PDF at https://www.cs.tufts.edu/~nr/c--/extern/man2.pdf it's in figure 2 on page 10). I'm not knowledgeable enough in compilers and computer architecture to decide if it's a good reason.

As far as I understand it, their reasoning is that implementations can easily enough figure out how the data is used to decide in which registers to put the data; distinguishing between integers and floats in the type system would be too restrictive, since they want to support architectures with more types of registers than the classic two.

Slightly related to this, this article made me check Simon Peyton Jones's wiki page [1], where I saw this:

> Jones has played a vital role in the development of new Microsoft Excel features since 2003, when he published a paper on user-defined functions.[19] In 2021, anonymous functions and let expressions were made available in the Office 365 version of Excel as a beta feature.[20]

Truly, there were (possibly still are) a lot of smart people working on Excel, as the years go by I'm starting to think of it as one of the most interesting pieces of software ever written.

[1] https://en.wikipedia.org/wiki/Simon_Peyton_Jones

He semi-joked that Excel is the world's most popular functional programming language.
Excel is probably the world's most popular programming language period.
80% of SaaS business out there are just excel files with a better UI and a more scalable database.
Well not ALWAYS a more scalable DB ;)
> Excel is the world's most popular functional programming language.

It's not?

LET has been a huge game changer, and when used it can greatly improve the readability of excel functions. Ranged based functions and LAMBDA are also great additions, but to a bit of a lesser extent as they're more complex and thus less popular.
So now any wikipedia page is now worthy of a hackernews post?
To see how silly that comment is, compare to: "So now any web page is now worthy of a hacker news post?" The answer to both comments is the same, and is in the HN guidelines.
"Ah, it'll be a joke programming language. Someone probably made a joke about C++ and then someone with too much time on their hands actually wrote an implementation of the language."

(Reads the page.)

"Oooh. Interesting."

From an engineering point of view, it’s interesting they chose to implement their own intermediate language, as opposed to just sticking to LLVM IR and “outsourcing” the problem of code generation.

I actually researched this some time ago, and was a bit surprised to learn that modern GHC’s intermediate representation seems to differ from what the C-- paper describes quite substantially, in ways that are only described in the source code. They’re still using the same name though.

One observation is that GHC has been somewhat slow to adopt new CPU targets (M1, WebAssembly). I wonder if the reliance on C-- played a role in that.

LLVM - Initial release: 2003

C-- - Initial release: 1997

That by itself only explains the initial decision. It’s still interesting that they’ve stuck to it for 20 years after LLVM’s release. Lots of technical details of GHC changed during that time, it’s not like the architecture is set in stone.
The point I was replying to was:

> it’s interesting they chose to implement their own intermediate language, as opposed to just sticking to LLVM IR and “outsourcing” the problem of code generation

I was not replying to:

> It’s still interesting that they’ve stuck to it for 20 years after LLVM’s release.

Changing the backend from their own IL to LLVM IR several years later is not exactly a "just sticking to LLVM IR" story. Knowing that C-- predates LLVM explains why they chose to implement their own IL.

The API cut ended up being in a different place with LLVM and WebAssembly. But the core idea still stands, and has been a hot potato for many years. In some ways, things are better now since there are fewer architectures than in the 90'es, so you don't have to support that many backends. On the other, things are worse because the amount of work you have to sink into a backend is non-trivial and ever growing.

One particular key aspect is that languages which have strong functional features tend to mismatch with typical imperative backends. This has been true for LLVM. It is unfortunate, because in reality, most IRs are essentially best described as small functional languages: they make state passing explicit, as it exposes better optimization analysis. SSA-form is functional programming in disguise.

Yeah, not too many people write a back end these days.
what's SSA-form?
An IR form where each variable is assigned to exactly once. It makes reasoning about a lot of local properties cleaner since you know that the value of a register is set by its single def site.

The idea has also been expanded to modeling heaps for aiding reasoning about field loads and stores.

I asked this on Ask HN sometime back but did not get a lot of responses. So asking it here because it might be of interest to people reading and commenting on this artile here.

Which programming language other than C is available for most platforms?

It is well known that some C compiler implementation is available for almost every computable platform. I am looking for another programming language that has compiler implementations available on a large number of platforms. It must compile source code into native machine code. It doesn't have to match C in ubiquity. It can be less popular than C. But are there any programming languages out there that are available on a large number of platforms?

This is not a direct answer for compiled languages, but Greenspun's tenth rule feels relevant here:

>Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp

> Which programming language other than C is available for most platforms?

Wouldn't any language frontend for gcc count? Last I checked that includes Ada, Fortran, and others.

Are all languages supported by gcc compiled to the same intermediate code?
Yes, but GCC has several internal representations, Gimple and RTL.
Last time I looked, GCC had pretty poor support for 16-bit x86 compared to older compilers.
Well, not really a systems language (and strongly dependant on C), but Lua is usually a good choice and it runs virtually everywhere.
Two very different answers for you.

1: Forth. I've seen Forth on things that I didn't even realize were computers. Since an interpreter can run in a few hundred bytes of ROM, that's not too surprising.

2: Rust. Rust can run on 8/16 bit micros, client side web (WASM), and on iOS, along with all of the more conventional and easier targets. Probably the only popular universal language for 2022 targets, although there are Rust competitors like Zig that may falsify that statement.

And in a nice coincidence, both languages are fun.

> Which programming language other than C is available for most platforms?

There is almost no platform java can't run on. Rust is a bit esoteric, but it can run anywhere you have a working libc.

> Rust is a bit esoteric, but it can run anywhere you have a working libc.

I don’t think that’s true. Doesn’t Rust only run on platforms that LLVM supports?

I'm wrong, but you're also incorrect. Turns out, that rust can in theory run anywhere you have a libc, but if the target isn't known to the compiler yet, it's on you to connect libc to the rust STD.
How can rust run somewhere that LLVM doesn't support?
Java requires a certain amount of memory and CPU power (if nothing else because it's a garbage collected language).

I doubt Java is available on some of the smallest computers C can run on, like many microcontrollers or legacy platforms.

There is https://en.wikipedia.org/wiki/Java_Platform,_Micro_Edition

But of course, a 32KB RAM minimum would be too much for some legacy systems. Still, Java is actually far more flexible than most people would think.

(Also, at its heart the JVM is just a Forth-like stack based interpreter, and I would guess that loading and parsing a .class file is more complicated than the interpreter itself!)

Smart Cards?

Full C is also not available everywhere, specially 8 bit and 16 bit computers where it is mostly a pseudo macro assembler.

If you are looking for a language that is portable across platforms and widespread/long-lived enough to make learning it deep worth it, i think C is unmatched and will probably stay like this for a while.
Forth is available for more platforms than C, and like C, it is usually but not always a compiled language. Because Forth always has an interpreter, and a powerful one, it's more obvious that Forth doesn't have to compile to run, but again, true of C as well: https://gitlab.com/zsaleeba/picoc exists, and it isn't the only one.

Edit: an important difference between them is that C implementers take the standard very seriously, while Forth is culturally resistant to standardization, Chuck Moore being on record as having considered it a bad idea, and disliking the resulting ANSI Forth language.

If the goal is to compile "the same code everywhere", well, good luck doing that with C, but with enough #ifdefs it can be done. The Forth approach is to have a personal base layer of words, which one either adapts or implements for a given system, and target the rest of one's code at that dictionary.

Free Pascal[0] supports a wide range of platforms and architectures. From the site:

> Free Pascal is a mature, versatile, open source Pascal compiler. It can target many processor architectures: Intel x86 (16 and 32 bit), AMD64/x86-64, PowerPC, PowerPC64, SPARC, SPARC64, ARM, AArch64, MIPS, Motorola 68k, AVR, and the JVM. Supported operating systems include Windows (16/32/64 bit, CE, and native NT), Linux, Mac OS X/iOS/iPhoneSimulator/Darwin, FreeBSD and other BSD flavors, DOS (16 bit, or 32 bit DPMI), OS/2, AIX, Android, Haiku, Nintendo GBA/DS/Wii, AmigaOS, MorphOS, AROS, Atari TOS, and various embedded platforms. Additionally, support for RISC-V (32/64), Xtensa, and Z80 architectures, and for the LLVM compiler infrastructure is available in the development version. Additionally, the Free Pascal team maintains a transpiler for pascal to Javascript called pas2js.

[0] https://www.freepascal.org/

Good post. Too many people act like there is C or C++, then nothing else. As Pascal shows and along with others, there are various options, if one chooses to see them.
> As Pascal shows and along with others, there are various options

The number of platforms Pascal is available looks impressive! Can you mention some of the others like that? You say there are various options. What are those?

Ada is up there with Pascal (which there are various dialects aimed specifically at embedding) as an alternative. Some people will take issue, but Java and Go can be viable alternatives as well.

Lots of activity and talk to try to push Rust into being a stronger alternative too. There are also the other newer C alternative languages and languages that compile to C (Nim, Vlang...), that can be directed towards this purpose. Speaking of Vlang, there is now a project for it to compile to Pascal, as one of its backends (in addition to C and WASM).

So... Pascal, Ada, Java, Go (including TinyGo), Rust (future), and others mentioned (future/transpile to C)...

Don't get me wrong, C dominates. But, depending on what is being done, its not the only language that has to be used or it can be written in something else that transpiles to it.

Besides all other replies, C++.
this version of c-- does not address some of the bloat and shortcomings of the C syntax:

should have no integer promotion, no implicit casts (except for literals like rust? and void* ofc namely), have runtime/compile-time casts, idem for "constants", no horrible typedef/enum/_generic/etc, only sized type (my heart is split between uw/u16,sdw s32, etc), variable arguments of preprocessor macros definitively defined, only one loop statement loop{}, no switch...

It's not really meant as a competitor to C, and AFAIU, it's meant as a target for a compiler front/middle end, not as a language to write code in manually. Unless you're hacking GHC itself, you're rather unlikely to touch it.
C does not have implicit casts
C most certainly does have implicit casts, and they are everywhere.

Simple example:

    // malloc returns *void, but C casts it to *char
    char *p = malloc(10);
There are tons of implicit casts when working with integers of different sizes, another example:

    // subtraction of ints of different signedness
    // C casts signed int 10 to an unsigned int
    assert(2U - 10 == 4294967288);
Arrays decay into pointers which is another implicit cast, I don't think an example is needed though.

Anyways these are just a few common examples, there are tons more and many of them are pretty subtle and error prone.

https://en.cppreference.com/w/c/language/conversion

(comment deleted)
There’s a parallel universe where c minus minus occupied the same role that llvm rose to take.

That said, it might be that it was trying to be a standard rather than a single blessed implementation that accounts for that difference.

C—- was the joking name for the subset of C we had to implement for my Compilers course in college (1990s, UCSC). I’ve assumed that other courses at other colleges did this, too.

When I clicked on the link this is what I expected the article to be about.

Yeah same. There was a basic prerequisite that everyone know the basics of C, but there was no expectation of assembly knowledge. So we'd write a compiler to compile the code down to reduced form of C that basically mimics assembly, and then use gcc to compile that.
my compiler course called it mini-C