Live data from Hacker News

Carbon’s most exciting feature is its calling convention

foonathan.net

171–180 of 223 posts

Re: Carbon’s most exciting feature is its calling convention

#171
post #154
post #142

Earlier quoted context omitted.

> The C++ is absolutely ABI stable C++ ABI doesn't even exist, there are several competing standards (much fewer now than there used to be) and nothing is guaranteed even between different compiler versions, let alone different compilers. Not that long ago we used to have two implementations of std::string in gcc you had to choose from and if the library you're linking with chose another one, you were out of luck.

A thing that does not exist, still is leveraged to build whole distros, and its too high stability resulted in the creation of Carbon.

This happens to work on Linux where the two major compilers (gcc and clang) are (mostly?) compatible. Windows is a different story: C++ code build with MSCV is generally not compatible with GCC/clang and vice versa, the most notable differences being vtable layout and default 32-bit calling conventions.

Re: Carbon’s most exciting feature is its calling convention

#172
post #99

Earlier quoted context omitted.

> I also loathe their desire to listen to the BNF maximalists insistence on not having any “ambiguity” from Odd that you put ambiguity in quotes. I guess it's not real ambiguity then. Ivory tower academics, as you see them, actually care about stuff because it affects you. I've heard too many times the knee-jerk response of "it's just theory" as if that actually meant anything. Try implementing it yourself and you'd…

I put ambiguity in quotes, because the only people who claim it makes things ambiguous are theoreticians - who you appear to have decided I think of as being "ivory tower" which we'll address in a bit - who favor a theoretical definition of what a grammar should be, and disregard (1) how people understand language, programming or otherwise, (2) insist on a mathematical definition of grammars, and grammar classes, tha…

>because otherwise they would not allow infix operators, which are ambiguous according to their definition

This is not true, infix operators can be easily encoded in BNF as a series of rules, each rule recognizing expressions unique to it as well as all the expressions of higher precedence. The following for example is a grammar that parses the four arithmetic operations with the usual precedence.

Expr ::= Addition

Addition ::= Term ((PLUS | MINUS) Term)*

Term ::= Prim ((MUL | DIV) Prim)*

Prim ::= NUM | OPEN_PAREN Expr CLOSE_PAREN

>The problem is that this model of grammars is arbitrarily restricted

It is restricted, but not arbitarily so. There is a very natural constraint that explains why Parsing Theory doesn't like ad-hoc parsers in the way you hate so much : the parser shouldn't depend on the "content" of the stream. The easiest way to see what I mean by this is to demonstrate how one violation of it works : C++'s ambiguous "X Y();" is either a function prototype or a variable declaration, depending on whether Y is a valid type name. This is extremely ugly to me, a parser shouldn't accumulate type information while it's parsing, even if it's as trivial as a set of type names. This is an entirely different concern that should be left to an entirely different module of the compiler. C++'s syntax is full to the brim of such ugly corners, the standard doesn't even bother to specify a binding BNF on the implementations!

Compiler Theory settled on an interface design where the parser must be able to output a concrete syntax tree from a stream without relying on global ad-hoc state like a table of special names or whatever. You framing it as "accumulating no state beyond a stack and its current state" is being unfair, it would be like framing the point of local variables as just a limiting thing that we invented arbitarily : Yes, that's the entire point, No, it's not arbitary, it's intentionally limiting, because the resulting design is easier to understand and simply more elegant.

>lisp I think has technically already done that

There is a middle ground between lisp's austere and misguided "F*k You, Why Should Parsing Be Hard Just To Please Your Eyes?" syntactical philosophy, and between C++'s and Perl's "Lol, Grammars Are For Weaklings". Complex syntax is good, it automates the tedious tree-layout that is the text of lisp programs, you don't need to repetitively state the precedence and hierarchy of code elements, the parser infers some of them for you. However, as in all "The Machine Infers Things" situations, we have to be careful with the rules of inference. We don't want the machine to infer counter-intuitive things, or fail to infer entirely. CFGs formalism is an elegant tradeoff.

>we don't see any real research into into those aspects of PLT

It might be the other way around, that allowing arbitary ad-hoc state in the parser results in too ugly a formalism or no interesting formalism at all, therefore people settled on disallowing it. It's like how theoretical mechanics famously hates friction, it isn't arbitary or born of prejudice, it's just that friction is too ugly and hard to yield an elegant and concise theory, therefore people just pretend that it doesn't exist.

On the surface, it doesn't seem hard to try and formalize some of the real-world parser hacks into the grammar formalism. For example, C++'s "this should be parsed as X unless the name is in a certain set then it should be parsed as Y" doesn't appear too wild a constraint type to encode in a formal grammar, my suspicion is that if you try to do it you will either discover that (a) it doesn't actually change any of the implication of traditional theory, and therefore it is just a "sugar" over traditional constraints : cool, but it technically doesn't tell us anything new (b) it significantly changes the implications and guarantees of theory, to the point that it's not an elegant or beautiful theory anymore. You can introduce control flow into prolog, but why bother ? it wouldn't be prolog anymore.

I don't want to imply that Academia is all-seeing or all-wise, but it is a very powerful novelty-rewarding machine, if there is Anything theoretically interesting to be gained from formalizing parsing hacks, I find it very hard to believe it hasn't been studied in 65+ years of grinding on parser theory and formal grammars.

>I would guess most real world parsers for "real" languages are not any of these classes

I find this too strong a claim. I would bet money it's false for anything but C, C++, Perl, Ruby, and let's say PHP just to be safe. Mention any language that isn't on this blacklist, and I bet I can find BNF-like description of the grammar that tells you perfectly well how to obtain a CST from text, which means they are CFG.

Re: Carbon’s most exciting feature is its calling convention

#173
post #120

Earlier quoted context omitted.

Fragile base class problem is solved, then? When did that happen?

No, but that's also not relevant as C++ is ABI stable. I can take any C++ compiler, and I can compile any C++ library, and then I can take some other compiler and compile some other piece of C++ that calls my library, and it will Just Work. I can then go back to my library, and make a bunch of ABI safe changes, just as I would have to do in C, and compile my library again, with yet another compiler. At that point the…

> As with C APIs, the people who make C++ APIs, know how to make them robust as well.

It seems too optimistic for me. I use Gentoo, and I believe that the only reason I have no such troubles is Gentoo with all its maintainers who do a great work of testing different combinations of libraries. And of course `ebuild` that can rebuild libc.so without breaking the system. I tried it once when I just started with linux, and I failed. Never tried to do it again myself, I let `ebuild` do it. It is not so easy, you know, to change version of a library which is a dependency of every binary in the system. And it is a C library. I wouldn't even try to do it, if it was a C++ library. Though who knows, two decades ago when I started with linux I probably was dumb enough to try.

Re: Carbon’s most exciting feature is its calling convention

#174

Earlier quoted context omitted.

> If you choose to specify your language using a class of grammar which permits ambiguity, then you have to resolve that ambiguity. I added an edit after which you may not have seen: even context-free grammars have ambiguity, eg. the regexp "aa" is legal but ambiguous for sentence "aaa" So what grammar can you suggest that's even weaker than context-free (to make expressions of ambiguity impossible) and still useful?…

> So what grammar can you suggest that's even weaker than context-free (to make expressions of ambiguity impossible) and still useful? It doesn’t need to be weak. For example use a Parsing Expression Grammar.

PEGs are ambiguous, just that that's resolved by rule ordering. From the wiki page (https://en.wikipedia.org/wiki/Parsing_expression_grammar#Amb...)

"A PEG parser generator will resolve unintended ambiguities earliest-match-first, which may be arbitrary and lead to surprising parses"

Re: Carbon’s most exciting feature is its calling convention

#175

Earlier quoted context omitted.

> So what grammar can you suggest that's even weaker than context-free (to make expressions of ambiguity impossible) and still useful? It doesn’t need to be weak. For example use a Parsing Expression Grammar.

PEGs are ambiguous, just that that's resolved by rule ordering. From the wiki page ( https://en.wikipedia.org/wiki/Parsing_expression_grammar#Amb... ) "A PEG parser generator will resolve unintended ambiguities earliest-match-first, which may be arbitrary and lead to surprising parses"

> PEGs are ambiguous

You're misunderstanding the rhetoric there - they're unambiguous by construction because they deterministically resolve earliest-match-first - a well-defined rule.

It's impossible to write an ambiguous PEG. Any grammar you write in a PEG is never ambiguous. A grammar you write using a CFG can be ambiguous.

As your own link says "Unlike CFGs, PEGs cannot be ambiguous".

Or read Ford's original paper https://bford.info/pub/lang/peg.pdf - they solve "the ambiguity problem by not introducing ambiguity in the first place".

(I wrote a much-cited thesis on PEGs and issues such as ambiguity in precedence parsing - I'm not just talking off the top of my head here.)

Re: Carbon’s most exciting feature is its calling convention

#176
post #170

Earlier quoted context omitted.

The C++ standard does not define an ABI. > I can take any C++ compiler, and I can compile any C++ library, and then I can take some other compiler and compile some other piece of C++ that calls my library, and it will Just Work. This is most definitely not true. It just happens that clang and gcc are mostly compatible, but MSVC and clang/gcc is not! For example, vtables are implemented differently and therefore virtu…

[edit due to the above edit I just saw: wasn't me, I didn't see what you said as being inherently bad and so deserving of downvoting, otherwise I wouldn't have bothered replying :-/] That sounds like what you're saying is that gcc or clang fail to conform to the platform ABI, which is a compiler bug. If a compiler wishes to ignore platform ABI, it doesn't make the ABI not a thing. But if you are comparing ABI compati…

Surely if GCC's vtable layout isn't compatible with that used by MSVC then COM couldn't possibly work? Not much of the rest of the Win32 API would care though, other than DirectX and possibly a few more modern additions I'm not aware of.

Re: Carbon’s most exciting feature is its calling convention

#177
post #65

Earlier quoted context omitted.

If you consider the context of Carbon (Google having a _lot_ of C++), solving for "interop with C++ is hard" might be considered worth the price. Whether that's true in practice...? I guess we'll need a few more years to tell.

Of course, that's why they're building it. They're solving a very specific, niche, hard problem. It would make no sense for other languages, which want to solve more general problems, to tackle C++ interop over C.

I do think this is very much a google project specifically because they have a lot of C++ and recognize that there needs to be a path to a memory safe environment, and that is why this project exists.

But I don't think the goal is inherently wrong, nor do I think it's niche - there is a lot of C++ in the world, and much of it would benefit from being memory safe. A lot of the largest projects and certainly many of the most heavily used software projects are written in C++. I think you'd agree that having them no longer be be trapped in a memory unsafety tarpit would be a Good Thing.

Let's imagine someone came out with a magic C++ compiler that had 100% source and ABI compatibility and had no performance costs, but was completely memory safe - remember "magic". You'd obviously expect, if not demand, that every C++ project switch to that magic compiler. So let's imagine we're on a scale from 1 to 10, where 1 is the memory safety of current compilers and 10 is our magic clearly impossible one. Obviously every step we can go towards 10 is great, but is going to come with trade offs in adoption cost. So on another 1 to 10 scale where 1 is rewriting in some other random language (rust, etc) and 10 is your current compiler, then you want the new language to be as close to 10 as possible. One thing you could do is build all your code with ASAN or a similar mechanism, that would have low adoption cost, a dramatic improvement in runtime safety, but a huge performance cost (time for another 1 to 10 scale?).

Carbon appears to be an attempt to design a language with a reasonably high score in all of the scales - no 10s, but mostly 7s or something. I personally think that there are things we could do to C++ that would make a meaningful improvement to safety without having the solution be "rewrite in other language", but I won't fault a project saying "we'll support incremental adoption" as their adoption path in exchange for stronger safety.

Re: Carbon’s most exciting feature is its calling convention

#178
post #154

Earlier quoted context omitted.

A thing that does not exist, still is leveraged to build whole distros, and its too high stability resulted in the creation of Carbon.

This happens to work on Linux where the two major compilers (gcc and clang) are (mostly?) compatible. Windows is a different story: C++ code build with MSCV is generally not compatible with GCC/clang and vice versa, the most notable differences being vtable layout and default 32-bit calling conventions.

[edit: and I just realized I replied to you elsewhere. sigh. keeping it classy :-/]

Windows is a different platform, so comparing it to linux isn't relevant, any more than saying I can't run the code I compiled for sparc on a ppc Mac.

Re: Carbon’s most exciting feature is its calling convention

#179

Earlier quoted context omitted.

I don't want an existing object? You seem to be having a lot of trouble with this very basic idea. Objects do not necessarily need distinct addresses. "But that's how C++ works" is just a fact about how C++ works, it has no larger significance, and where it conflicts with the sensible way to do things it's actually a defect.

How would you define object identity if different objects can have the same value and the same address? To my mind, an object is a value with a unique identity. How else would you define it? And if you want a billion empty values, then yes, those could all be implemented by the same object - it's pretty easy to implement, even though it would be ncie for a compiler to do it automatically (like how Java normally gives…

> How would you define object identity

    fn main() {
         let vs = [(), (), (), (), ()];
         for v in vs {
             println!("{:?}", v);
         }
    }
This loop will five times print "()", because `v` will iterate through all five elements of `vs`. Are this values are identical or they aren't? I don't know, it doesn't matter, isn't it? But I think of them as of different values: they are different members of `vs`.

Re: Carbon’s most exciting feature is its calling convention

#180
post #30

Earlier quoted context omitted.

I think the alias analysis “pro” is overblown, it’s UB to take the address of a parameter via any mechanism other than explicitly taking the address - which a compiler obviously sees, and because it’s UB the compiler optimizes is free to assume no one is taking the address. Then for any parameters that are passed by reference the compiler has to assume there are other references so there’s no gain. Honestly the only…

> which a compiler obviously sees Not if it's in a different compilation unit, it doesn't. Or if it's just not inlining the function for some reason, then it probably also doesn't. Which is why Carbon's restriction here is so useful and practical.

Ok, I'm willing to accept be wrong here. My interpretation of what I read is that Carbon is disallowing taking the address of a parameter. Very specifically:

    void f(int i) { &i; /* disallowed */ }
I think that's a trivial case and is hopefully obviously easy to detect, and I know we're considering relevance to escaping which this doesn't do, but it seems that taking the address is explicitly disallowed regardless of use. Anyway given the many references to references, lets do

   void g(int &i) { &i; /* disallowed once more */ }
To me this seems no harder to detect, but this does seem like a case where banning taking the address /could/ impact things. But I can't see what the win is.

I'm assuming its a different TU or something else that prevents inter procedural optimization. Could you give some examples where this allows performance wins?

Post reply on HN