Hacker Newsnew | past | comments | ask | show | jobs | submit | jcranmer's commentslogin

VLCCs are too large to fit through the Suez Canal. I don't know how much of Saudi export is using VLCCs versus Suezmax or smaller tankers, but I've heard that much of the Red Sea oil export is currently going through Bab al-Mandab, not that I have a source on hand.

Newspapers are not above printing rumors.

See, e.g., Barak Ravid regularly reporting in Axios the impending ceasefire negotiation progress in the Iran War, which largely have failed to come to pass.


As a point of evidence in favor of this viewpoint:

Multi-dozen car pileups aren't particularly rare, with the common cause for a lot of these being "one car hits an icy patch, hits another car, car behind them tries but fails to stop in time due to the ice, rinse and repeat a few dozen times". And the root cause of that is every single driver in that collision driving too fast for conditions and unable to make the requisite emergency stop in time.


In my callow youth I was responsible for a couple of fender benders and the cause was always a highly imperfect understanding of the appropriate stopping distance of my car. This obviously gets worse, the worse the conditions are. My Tesla never makes this kind of mistake.

Yes, it does. The lambda still needs to follow the C++ object model in case someone might use it like a regular C++ object. It's possible to change the ABI with escape analysis that proves you know all of the uses of the lambda to change the ABI, but a) that escape analysis is surprisingly easily defeated [1] and b) ABI-changing optimizations tend to be much more common in research papers than production compilers because getting them right on real code is a lot more difficult than it looks.

[1] The lambda function probably has the same linkage as the function the lambda is contained in, which likely isn't "the only copy of this function is in this TU" but rather "this function may appear in several TUs, but all of these copies are equivalent and you can pick whichever one you like as the actual body." Very different opportunities there!


No, there is an amount of legal reality built into it. With copyright and patents, once you obtain the intellectual property, you keep it for the rest of the term no matter what you do. But with trademarks, your actions (or inaction) can cause you to lose the trademark.

The legal purpose of the trademark is to protect identifying marks for the purposes of conducting business (trade)--literally its name. The subsidiary public interest of attaching trust to that mark isn't directly protected, but failing to police the use of trademark is sufficient grounds to lose the trademark, which is why companies tend to be overly aggressive in suing people for violating the trademark.


> Failing to police the use of trademark is sufficient grounds to lose the trademark, which is why companies tend to be overly aggressive in suing people for violating the trademark.

Not quite. There is no litigation requirement to renew a trademark registration. Trademarks are in fact the only type of intellectual property that can be preserved in perpetuity.

Litigation is an attempt to prevent genericide, and might fail at that.

Trademarks can be preserved even in the absence of litigation. Cancellation cases in US law typically require evidence of abandonment and lack of evidence for intended re-uptake. Litigation is not necessary to refute abandonment.


Nothing you've written above contradicts my argument. which is that there's no liability attached to a trademark as opposed to what something made to protect the consumer would require.

> Generally this is a bit nicer than having explicit lambdas, but I thought the 'best-case' scenario would be if GCC saw into the stack layout of the calling function and could manipulate the calling functions stored stack variables (and saved registers).

A modern compiler IR is probably going to be an SSA-based infinite virtual register set model. In such a model, any variable without its address taken ends up being a register (which may happen to be spilled to the stack). Referencing the variable via a nested function means its a local variable whose address escapes, which kills a lot of optimization potential. It's probably possible to adjust SSA to handle this, but it's a lot of work for little benefit, especially since closure models (closures being regular objects with an unnameable type and an overloaded call operator) have taken over nested functions in language design and thus it isn't really applicable for modern languages.

> After all, a debugger can track what variable goes where at every line of code, so this can be done.

Variable value tracking breaks down pretty much the moment any optimization happens.


I think you should read my article ;-) ... because the point is that nested functions in C are basically implemented in a very similar way as C++'s lambdas with "unnameable types" a frontend detail.

The idea that "closures ... have taken over nested functions in language design and thus it isn't really applicable for modern languages." is true only if you think C++ as basically the only modern language and everything else with nested functions is not modern, which is ... an interesting take.


C++, C#, Java, JavaScript, Rust, Go, Julia, Nim, Zig.

I'm shocked that you didn't even pick up Rust, given how frequently I mention it on the WG14 reflector.


I am confused why you cite these languages as an example to your claim that closures are preferred over nested functions in language design (which is already a confusing statement), as many of them do have nested functions, e.g. Go, Julia, C#, Javascript, Nim. Rust has at least limited "non-capturing" nested functions as far as I know.

>> After all, a debugger can track what variable goes where at every line of code, so this can be done.

> Variable value tracking breaks down pretty much the moment any optimization happens.

I think for nested functions it's not [only] a question of performance/optimizations but of correctness. Even if you properly unwind the stack like a debugger trying to find the parent frame, you may actually find multiple due to recursion. It's impossible to know which one is "yours" unless at least some information about the parent frame was passed to the nested function at invocation time. It can't be a truly static function.


This is where I retort about what you wrote not being exactly right, and then you reveal that you have 20 years of professional experience writing compilers, including the one most of the software I run was built with.

The author has been trying to push for the inclusion of nested functions into the C standard, and a lot of the resistance comes from the existence of trampolines and all of the issues that causes. His response to those issues is... to basically go "nested functions, Objective-C blocks, and C++ lambdas are all the same thing if you squint at them hard enough" and ignore all of the very real semantic differences between all of them.

For my part, I'll point out that there is one rather important difference between nested functions and C++ lambdas that the author completely ignores, as exhibited by this godbolt example: https://godbolt.org/z/35beWrrTe (note the differences in the generated assembly, especially that which cannot be explained merely by -O0 code generation).


> note the differences in the generated assembly, especially that which cannot be explained merely by -O0 code generation

Do you mind elaborating for those of us who aren't familiar with what to expect from the compiler?


In the nested function, the variable x is passed in edi, and the pointer to the nested stack frame is passed in r10. In the lambda, the variable x is passed in esi, and the 'this' pointer for the lambda is passed in rdi. The function-level ABIs end up being quite different.

Thanks, but now you should explain why you think this slight (and well understood) difference in calling convention is a rather important difference.

I can write the signature of the generated function of a C++ lambda as a C function. I cannot write the signature of a generated GCC nested function as a C function.

If your argument is that ABI doesn't matter, then by all means, propose a patch to GCC to change the ABI and see if it gets accepted.


I can not write the signature of a function that requires a static chain (which exist in many languages) in C, because we have not added such a feature to the language. But we could. And we should, because we now need a (type-unsafe) extension (__builtin_call_with_static_chain) to invoke such functions.

I do not want to change the ABI for nested functions as it is a useful ABI and a cross-language standard. ABI obviously matters, but it is not a fundamental difference in implementation that makes nested functions fundamentally different to C++ lambdas. If your point is merely that a compiler translating nested functions to lambdas would need to adapt the ABI in this case, I agree. This is not difficult though. And this question is relevant only if one allows taking the address of a nested function, because as long as it is called only locally, the compiler can use whatever ABI it wants.


Okay, so you accept that nested functions have a different ABI than C++ lambdas. And it looks like you accept that neither ABI is going to change. So long as the two features have different ABIs, they cannot be compatible with one another.

> And this question is relevant only if one allows taking the address of a nested function

And that question is very relevant since taking the address of such functions (to pass to other functions, e.g., qsort) is one of the main use cases for their existence.


The ABI does not need to be compatible, because there is no way to call a C++ lambda directly from C.

If you take the address of a lambda function you get a pointer to an object of anonymous type, so you can not pass it to qsort, and qsort would also not know how to call this.

But if we added a feature similar to std::function_ref to C (i.e. a wide function pointer type), then such a type could be used to call both, nested functions and C++'s lambdas, and - in fact - many callable entities from other languages too. But for C++'s lambdas this would always involve a compiler generated thunk that adapts the ABI. This is also exactly what happens in C++ if you use std::function, because even in C++ you can not pass the address of lambda to a function without first erasing the type and creating the thunk.

So there is no compatibility problem.


An example showing this equivalency is this:

https://godbolt.org/z/vEP5G9Pfr

Similar to how std::function_ref creates a thunk in C++ that calls the lambda so that it has a generic type-erased API that can be passed to non-templates, a conversion to a wide pointer would create a thunk that adapts the call from the nested function pointer ABI (that already exits for other languages also in LLVM whether we standardize the C feature or not) to whatever the lambda needs.

Edit: slightly updated example.


An example showing nonequivalency is this: https://godbolt.org/z/PxP4vrfM1

Showing things that are optimized by fully inlining into one function don't actually demonstrate equivalency, because you end up omitting anything that might actually evidence a difference in the semantics. And I get that, for your use cases, those differences might not matter. But as a compiler engineer, I can't say that only those use cases matter and therefore they're equivalent for all practical purposes.

It is also very unhelpful when you insist that this is "compatible" with other languages, where "compatible" actually means "compatible, if you put in a bunch of work in both languages to make something that makes them compatible, none of which I'm actually describing." Especially when there are competing proposals that do have compatibility in the sense of "I don't have to modify the C++ compiler to let it use this thing."


Equivalency does not mean that the everything has to be identical or even that the code has to be exactly identical for different implementations.

My point is that the implementation is structurally very similar: You synthesize a structure and put it on the stack and then pass a pointer to it around. It is so similar that you can certainly reuse your implementation of the lambda feature to implement this.

The wide pointer ABI question is also entirely orthogonal to other aspects, so we could decouple this discussion. The advantage of being compatible to other languages is because if we would use a common ABI that many other languages also use: Ada, Go, D, etc. In this case, no additional work has to be done for any of these languages. LLVM also supports this already.

The issue with C++ is that it does not use this common ABI and the closet thing it has even as a suitable API is std::function_ref. Where lambdas are not called locally, C++ already needs to create thunks anyway by going to some kind of these adaptors, so there is also no additional burden on the C++ side. One would simply have to implement this thunk in a slightly different way to adapt the calling convention.

I am not even sure that you need to do less adaption for other proposals, as many things the C++ semantics rely on do not exist in C (callable objects, templates), so you also need to adapt anyway at least in how you expose them in the language and in what other features you may need to make it work. In particular, JeanHeyds proposal does not even include the wide pointer part yet, which will also then be required at some point. The proposal also exposes far more features (different ways to capture), which makes it more work.

But I fully realize that the opposition for everything that looks different to C++ from the clang side comes from the perception that it is more work on your side. I can sympathize, but note that in GCC or other compiler that do not have a shared FE, we would essentially have to implement everything from scratch. So let's discuss this more if you want.


> The advantage of being compatible to other languages is because if we would use a common ABI that many other languages also use: Ada, Go, D, etc.

I have looked it up and I can already tell you that Go is not using the ABI you would be proposing. I cannot speak for the other languages.

> But I fully realize that the opposition for everything that looks different to C++ from the clang side comes from the perception that it is more work on your side.

That is not where the opposition comes from, and for as long as you continue to believe that, you will fail to understand the opposition at all.


Here seems to be the ABI, but I am not sure it is the right one and I am not sure if there are not different ABIs around. https://go.googlesource.com/go/+/refs/heads/dev.regabi/src/c...

"Closure calls follow the same conventions as static function and method calls, with one addition. Each architecture specifies a closure context pointer register and calls to closures store the address of the closure object in the closure context pointer register prior to the call."

In any case, the documented use of __builtin_call_with_static_chain in GCC and Clang is to be able to call closures of other languages, and for GCC Go is explicitly mentioned.

GCC: https://gcc.gnu.org/onlinedocs/gcc/Constructing-Calls.html

"This built-in can be used to call Go closures from C, .."

https://clang.llvm.org/docs/LanguageExtensions.html

"... as used by some language to implement closures or nested functions."

Yes, it is true that I completely fail to understand the opposition to this.


Doesn't this imply that the two functions have different semantics for capturing the environment?

No, why? It simply means that the arguments are in different registers.

I am not the only one who wants nested functions and function literals (lambdas) in C (as in basically any other modern language) and I explained every time that trampolines are not needed for this. It is frankly quite tiring that every time this topic comes up, still someone incorrectly claims that we can not have nested functions because of trampolines, or makes some other incorrect claim on how GCC implements nested functions.

BTW: I also very carefully analyzed all the semantic differences, which led me to the conclusion that putting C++ lambda semantics into C would be a bad idea. one can read this here: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3654.pdf

I also do not understand why you think the generated assembly needs to be identical, or why this is a "rather important difference".


I have yet to find a graph that shows the market share all the way back to the 1980s, but the market share isn't stagnant--Pepsi's market share has dramatically fallen (about half since 2000), while Coke's share has been pretty stable, although declining somewhat. Pepsi is no longer the second largest soft drink--it was very recently eclipsed by Dr. Pepper.

Microsoft did attempt the EEE strategy against Java with Visual J++, but Sun slapped that attempt down and Visual J++ was always a pretty minor footnote. The end result of this effort was C#. I should note that the much more successful EEE strategy against Java was Google's Android.

MS was successful at killing Netscape largely because paid software is difficult to compete against free software. The ActiveX controls weren't a feature with a lot of use--I can probably count all the sites I usedwith ActiveX controls on one hand. More common were the four big plugins: Java (for applets), Flash (counting Shockwave as part of Flash), Adobe Acrobot Reader, and Silverlight.

Netscape famously rewrote its codebase to try to implement the new web standards (like CSS2) more quickly, which contributed greatly to its ultimate collapse. After Netscape collapsed, MS laid off most of its browser development team, which let IE6 languish for years without improvements, going from the most standards-compliant browser on the market to the least standards-compliant. The rise of Firefox caused MS to pay attention again to web browsers, eventually restarting development and leading to IE7 being finally released. Only subsequent to that (and Firefox taking a large chunk of the browser market) did Google Chrome come out.


Private equity gets a bad rap in large part because the stories they're most famous for are the "PE buys a failing company, and the company subsequently finally fails," with the "failing" word conspicuously absent in most retellings. I'm not sure I've heard one of those stories where the company failed after being acquired by PE where it wasn't already failing before the PE takeover...

For me, private equity gets a bad rep because they've bought up all of the local mom and pop shops for just about any service I need thats face to face. All of the plumbers, electricians, general contractors, vets, grocery chains, coffee shops, and other shit were bought and had every ounce of revenue squeezed out of them. The result? All of the things I need locally cost 3-5x they did and the service is far worse.

And as a quick edit: none of these examples I have were of failing businesses. Each of the owners had their reasons, but none was due to it being necessary for survival. PE on hackernews tends to focus on software/bigger purchases, but so much of the damage in my opinion is on the local and smaller scale.


Concur. Private equity is synonymous with the concept of maximum extraction in my experience.

What PE loves to do (and where I think a lot of the vibe comes from) is buying companies from owners who care about the craft and turning them into companies that care about nothing but money.

Let's say you make an app for first responders. Being a former first responder, you know exactly what your users need and what the workflows should be like. Your app becomes a brand name in the community. You charge enough to survive (if that), because your app is a labour of love more than anything else.

Eventually, family and other responsibilities get in the way, and you just no longer have the time or motivation to maintain the app any more. You sell to "we so swear we are not private equity" Applause.

As soon as you do that, the app gets taken over by financiers and developers who are experts at "revenue optimization", with little domain knowledge about what first responders need. They calculate (probably correctly) that they can milk their customers for a lot more if they move to a subscription plan, gate some features behind expensive premium packages, stuff the app full of upsell pop-ups and fill it with analytics SDKs that tell them which features are worth spending development time on, and which can safely be removed.


Ooh, who could this be... so many contenders... Aladtect, PSTrax, Lexipol...

I didn't have any specific app in mind (I have stories but not with this specific industry); I brought it up as an illustrative but hypothetical example of the broader phenomenon.

The Applause thing is absolutely real though.


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

Search: