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

It might actually be a better environmental decision, if instead of buying a new second phone, it is instead about keeping an existing phone in use and not adding to the burning heaps of e-waste. Given the rising popularity of refurbished phones, not to mention the lower costs, it might actually be the opposite of what you claim, at least on those grounds.

And for the rest, well, "just works" for what? With a little time and effort, it may even get to the case of the "just works" part is a siloed unit like a SIM card that is just installed to the device, making it opt-in and user owned...


> on top of C.

If we're referring to the "C is a subset of C++" / "C++ is a superset of C" idea, then this just hasn't been the case for some time now, and the two continue to diverge. It came up recently, so I'll link to a previous comment on it (https://news.ycombinator.com/item?id=45268696). I did reply to that with a few of the other current/future ways C is proposing/going to diverge even further from C++, since it's increasingly relevant to the discussion about what C2y (and beyond) will do, and how C code and C++ code will become ever more incompatible - at least at the syntactic level, presuming the C ABI contains to preserve its stability and the working groups remain cordial, as they have done, then the future is more "C & C++" rather than "C / C++", with the two still walking side-by-side... but clearly taking different steps.

If we're just talking about features C++ has that C doesn't, well, sure. RAII is the big one underpinning a lot of other C++ stuff. But C++ still can't be used in many places that C is, and part of why is baggage that features like RAII require (particularly function overloading and name mangling, even just for destructors alone)... which was carefully considered by the `defer` proposals, such as in N3488 (recently revised to N3687[0]) under section 4, or in other write-ups (including those by that proposal's author) like "Why Not Just Do Simple C++ RAII in C?"[1] and under the "But… What About C++?" section in [2]). In [0] they even directly point to "The Ideal World" (section 4.3) where both `defer` and RAII are available, since as they explain in 4.2, there are benefits to `defer` that RAII misses, and generally both have their uses that the other does not cleanly (if at all) represent! Of course, C++ does still have plenty of nice features that are sorely missing in C (personally longing for the day C gets proper namespaces), so I'm happy we always have it as an option and alternative... but, in turn, I feel the same about C. Sadly isn't as simple to "just use C++" in several domains I care about, let alone dealing with the "what dialect of C++" problem; exceptions or not, etc, etc...

[0]: https://www.open-std.org/JTC1/SC22/WG14/www/docs/n3687.htm [1]: https://thephd.dev/just-put-raii-in-c-bro-please-bro-just-on... [2]: https://thephd.dev/c2y-the-defer-technical-specification-its...


> this just hasn't been the case for some time now

Which I find sad actually. The idea of C++ as a superset of C is really powerful, especially when mixing C and C++. A while ago I had a C project (firmware for a microcontroller) and wanted to bake the version and the compilation time into the firmware. I didn't find a way to do this in plain C, but in C++ you can initialize a global struct and it gets statically linked into the output. This didn't even use constexpr, just preprocessor trickery. Then it was just a matter of renaming the c file to cpp and recompiling. I guess you could also do that with C, but there are things like RAII or constexpr or consuming a C++ library that you can't do without.


> wanted to bake the version and the compilation time into the firmware. I didn't find a way to do this in plain C, but in C++ you can initialize a global struct and it gets statically linked into the output. This didn't even use constexpr, just preprocessor trickery.

I might be misunderstanding here, but if you are okay with preprocessor trickery, then it's doable.

I do this routinely in the Makefile, which (very tediously) generates a build_info module (header and implementation) that is linked into the final binary: https://github.com/lelanthran/skeleton-c/blob/8e04bed2654dac...


> I didn't find a way to do this in plain C

Not sure what you were running into. I routinely do this just fine.

> This didn't even use constexpr, just preprocessor trickery.

Isn't the preprocessor shared between C and C++?

> in C++ you can initialize a global struct and it gets statically linked into the output

That sounds to be doable just the same in C?


> But C++ still can't be used in many places that C is

Unless we are speaking about PICs or similar old school 8 and 16 bit CPUs, with compilers like those from MIKROE, there is hardly a platform left were the vendor compiler isn't C and C++ (even if it doesn't go beyond C++11).

And if it must be deployed as freestanding, there are still enough improvements to take advantage of.

In the end it boils down to human factor in most cases, however as Dan Saks puts "If you're arguing, you're losing.", taken from

CppCon 2016: “extern c: Talking to C Programmers about C++”

https://www.youtube.com/watch?v=D7Sd8A6_fYU


> personally longing for the day C gets proper namespaces

I think in the spirit of C, this should go into the linker, not in the compiler.


Or you can use objcopy --prefix-symbols=Namespace .


among the people that refuse C++ and stick to C, very few are willing to look at C23.


Well, each `defer` proposal for C agreed that it shouldn't be done the way Go does it, and should just be "run this at the end of lexical scope", so it'll certainly be less surprising than the alternative... and far easier to implement correctly on the compiler side... and easier to read and write than the corresponding goto cleanup some rely on instead. Honestly, I feel like it becomes about as surprising as the `i++` expression in a `for` loop, since that conceptually is also moved to the end of the loop's lexical scope, to run before the next conditional check. Of course, a better way of representing and visualising the code, even if optionally, would help show where and when these statements run, but a standard feature (especially with some of the proposed safety mechanisms around jumps and other ways it could fail in surprising ways) it would hardly seem exotic, and inversely is quite likely to expose things currently fail in surprising ways precisely because we don't have a simple `defer` feature and so wrote something much more complicated and error-prone instead.

So, I completely understand the sentiment, but feel that `defer` is a feature that should hopefully move in the opposite direction, allowing us to rely on less exotic code and expose & resolve some of the surprising failure paths instead!


Jen's macro that this was based on was an implementation of his own proposal (N3434) for `defer`, which was one of a few preceding what finally became TS25755! So, yes, C2y is lined up to have "defer: the feature", but until then, we can explore "defer: the macro" (at least on GCC builds, as formulated).


Testing with Jen's macro this was based on, and found that the always_inline was redundant under even -O1 (https://godbolt.org/z/qoh861Gch via the examples from N3488 as became the baseline for the TS for C2y, which has recently a new revision under N3687), so there's an interesting trade-off between visibly seeing the `defer` by not not-inlining within the macro under an -O0 or similar unoptimised build, since with the inlining they are unmarked in the disassembly. But, there's an interesting twist here, as "defer: the feature" is likely not going to be implemented as "defer: the macro", since compilers will have the keyword (just `defer` in TS25755, or something else that uses a header for sugared `defer`) and may see the obvious optimised rewrite as the straightforward way of implementing it in the first place (as some already have), meaning we can have the benefit of the optimised inline with the opportunity to also keep it clearly identifiable, even in unoptimised and debug builds, which would certainly be nice to have!


The two will also continue to diverge over time, after all, C2y should have the defer feature, which C++ will likely never add. Even if we used polyfills to let C++ compilers support it, the performance characteristics could be quite different; if we compare a polyfill (as suggested in either N3488 or N3434) to a defer feature, C++ would be in for a nasty shock as the "zero cost abstractions" language, compared to how GCC does the trivial re-ordering and inlining even at -O1, as quickly tested here: https://godbolt.org/z/qoh861Gch

I used the [[gnu::cleanup]] attribute macro (as in N3434) since it was simple and worked with the current default GCC on CE, but based on TS 25755 the implementation of defer and its optimisation should be almost trivial, and some compilers have already added it. Oh, and the polyfills don't support the braceless `defer free(p);` syntax for simple defer statements, so there goes the full compatibility story...

While there are existing areas where C diverged, as other features such as case ranges (N3370, and maybe N3601) are added that C++ does not have parity with, C++ will continue to drift further away from the "superset of C" claim some of the 'adherents' have clung to for so long. Of course, C has adopted features and syntax from C++ (C2y finally getting if-declarations via N3356 comes to mind), and some features are still likely to get C++ versions (labelled breaks come to mind, via N3355, and maybe N3474 or N3377, with C++ following via P3568), so the (in)compatibility story is simply going to continue getting more nuanced and complicated over time, and we should probably get this illusion of compatibility out of our collective culture sooner rather than later.


The blog entry is short and simple, perhaps consider reading it before knee-jerk reacting to the title, and then you might understand why "should" and "unnecessary" are operative in said title.


You've jumped to a fascinatingly false conclusion here. Is this the so-called death of media literacy? I replied to the ideas underlying the post rather than the words in it, and you think that means I didn't read it?

To go through the details: The post explicitly complained about a linter enforcing style rules. It did not object to the presence of mechanically-enforced style rules. In fact, it glorified them implicitly by saying how great it would be if everything was formatted at presentation-time. This glorification is the exact thing I was criticizing.

I think machine-enforced rules are bad because they destroy a communication channel that importantly has point 4 that I listed - when well-formatted code breaks its conventions, there must be a reason for it. That is important information that enforced presentation rules force to be put into another channel.

And it's certainly true that other channels do convey this other information, but I find more value in having it conveyed in the presentation channel than I do in having that channel replaced by mechanistic formatting.

This is the premise underlying the article that I object to. It is present so heavily in the subtext that if you pretend it's not, the post becomes incoherent.

And FWIW, HN rules say not to accuse people of not having read the article. I think that rule is mostly there because someone can read the article and notice something you missed, and it's wiser to not post than it is to assume you absorbed 100% of the context of the post.


The blog post, in its opening section, directly points out:

> Everyone had their own pretty-printing settings for viewing it however they wanted

This is an example of how treating storage and presentation as two separate concerns obviates a large swathe of low-value yet high-friction concerns with current "draw it as you store it" plain text code.

>> It did not object to the presence of mechanically-enforced style rules

Quite the opposite, by my reckoning! I won't belabour the dissonance about "linter enforced" somehow not being "mechanically enforced", since I think that merely belies a different interpretation of those words to have a subtle difference I feel adds nothing to the conversation. Instead, note the prior quote, which is quite literally from the leading section, as pointing out how you don't have "mechanically enforced" rules in such a scheme as the blog suggests. In particular, by letting someone views code "however they wanted", in other words, we're not merely talking indentation or casing, we're talking about using code to present the code, potentially in a contextually relevant manner.

This is, in my mind, quite the opposite of mechanically enforcing a set of style rules, since that would result in a fixed, static presentation, akin to merely "what flavour of indentation do you like"... here, we see the idea of contextually presenting the code as per your current needs and wants, for example, to directly craft the "one-off" not as an exception to the norm, i.e. "please turn off for these lines so you don't disrupt the formatting or trip on a bunch of special cases", but rather as a "here's how you should present this specific thing" in a way that is at the heart of this entire endeavour in the first place: programming the logic to get the intended results, now simply reflected back upon the task of programming itself (and for arguably the most important part, reading the code). By establishing these "rules" and patterns, it focuses the task on how to make the code more readable as a direct consequence of considering how to present and format it, with the ability to handle the special cases in that "one-off" manner with simple hard-coded patterns (i.e. "when the code is like this, present it exactly like that"), but of course also accumulating and generalising to handle even more cases, only now able to perform the delicate, "hand-crafted" formatting on code you're only just looking at for the first time, finding that it is now already formatted exactly how you needed it, or can be switched to another contextual mode easily with a quick addition to a set of such places to activate it, or a direct command to present it in such a way regardless.

Likewise, nowhere did the article state that this could not be shared, as people are often wont to do. The blog doesn't even talk about what people are currently getting up to with similar ideas now, with a little more rendering capability than the 1980s could reasonably provide. So, this hardly seems like glorification, even when it discusses not having to waste time debating linter/autoformat settings with one another. Indeed, it holds back from mentioning what can be done with some of the ideas it so casually includes, such as live environments (think about it, the presentation reflecting the current meaning, semantics, values, or state of the code as it runs, or while testing/debugging! that's something we currently either lack in most editors/IDEs, or are relegated to perhaps some basic syntax highlighting changes) or some of the interesting ways some "refactors" are actually entirely superficial and can be reframed as presentational changes since they do not alter the underlying semantics (or literal IR), such as "what order should these variables be declared in?" and other similarly banal or indeed perhaps more serious and useful presentational shifts we could explore with better tools (such as exploring "order-of-operations" sequencing in the "business logic" for edge-cases or to improve clarity, finding equivalent but more intelligible database queries without impacting optimisation, etc) without the need for worrying how entirely superficial changes might need a meeting to decide how to handle merges because two people renamed the same function or its arguments or similar clashes that are completely brittle right now.

The current tooling, particularly the use of linters and similar static analysis for auto-formatting, is based on a compromise with the underlying conceit that the storage medium and the presentation must be mechanically connected with little room for alteration (I still see people claiming syntax highlighting is tantamount to sin, unironically, so the extreme positions here are alive and well, thankfully barring calls to magnetised needles) and that the form is given primacy over the function, syntax over semantics, which continues to bring in pointless discrepancies over what that form/syntax should be, precisely because we can and should disagree since our own needs and tastes are individual, yet are forced to come to some compromise purely for the sake of having some consistent, canonical form that will be presented identically on everyone's screen baring only editor/IDE level differences such as syntax highlighting, themes, fonts, or indentation. Those are perhaps the most superficial changes to presentation and formatting that could be made, yet they are the only one most code and editors "allows" the user to have control over so they can customise it to their own needs, perhaps even going so far as to quickly switch them up with shortcuts or commands.

Now, with that in mind, we reflect on the blog, and on the use of some canonical storage of code (minified code, IR, or simply language-specific canonical formatting) with the explicitly non-canonical presentation, alleviating the concerns about people disagreeing over how to format a 2D array or something similarly innocuous, since they are all free to format it exactly however they please, either with a more manual "pushing syntax around" approach akin to moving characters/symbols in an editor, or programmatically extending from "pretty printing" into a rich, contextual and dynamic approach, which you as the programmer are free to configure to meet your exact needs.

Does that sound like a glorification of "mechanically enforced" style rules? Like it's destroying the signal rather than trying to expose and even amplify it? Like there is no room for us humans to craft and refine how something is presented to make it more intelligible and understandable? I hope not. Because, by my reckoning, this blog and the ideas it's discussing are perhaps one of the few directions we could reasonably and understandably start down to resolve the issues you, I, and the blogger are all agreeing on here, and with clear historical precedent to show it's not only achievable, but that it was achievable with only a fraction of the hardware and understanding widely available today. The "subtext" here feels quite contrary to how you are presenting it, though assuming such a "subtext" would indeed make the blog less coherent due to the continued cognitive dissonance of assuming the blog is suggesting "take away autoformatting/linting and then add it back in by a different name", instead of the really quite significant change it's actually suggesting we can do... and, indeed, wouldn't even have to change much these days to achieve it, with canonical or even somewhat minified code being perfectly acceptable for a line-oriented VCS to handle, without needing to figure out a suitable textual representation for the IR or otherwise needing to handle a dedicated binary/wire format.

Oh, and FWIW, to your FWIW, I felt it was the correct way to approach the comment, given that the substance of the blog post was not reflected in a comment that focused entirely on "formatting code" as in the title, in such a way that could be composed wholesale by riffing solely on the title. No direct reference or allusions to specific points in the blog were made, nor anything about what the blog actually suggests that directly supports your comment. Because, FWIW to my own FWIW, I actually agreed with the bulk of your comment, but I also felt the underlying position of said comment was only being presented in this way because you had not read through the blog post, and instead jumped straight in off the title alone, since, again, I felt nothing in the comment connected to the post beyond its title. Formatting is critical, which is why we should not rely on a static, mechanically fixed view of the world/code, and certainly not one decreed by "senior leads of sprints past" (or whatever the authority or popularity we are deferring to is on a given project or Tuesday). "Formatting" as a direct, mechanical act enforced either by a human at a keyboard pushing characters around, or by a linter following a style guide, is something that indeed "should" be "unnecessary", to elevate "formatting" (presentation) and make it a clear and important part of how we prepare code and make it more amenable to reading and understanding for our wetware, rather than convenient for fragile and lazy software. Why would we compromise on this now, when it could already be done in the 80s, and rely on static, linter enforced style rules at a time when we have so many cycles to spare on rendering code that we often render it in a web browser for the sake of "portability" (a huge irony given the origins of linters), and need not waste our time arguing over presentation when we could be making the presentations more useful to ourselves without concern for making it less useful for others, and then getting on with the actual task at hand? To me, this blog is all about elevating and prioritising formatting, without stamping on anyone's toes.

Still, to each their own. Oh, but that was kinda the point of the blog...


AlphaZero may have the rules built in, but MuZero and the other follow-ups didn't. MuZero not only matched or surpassed AlphaZero, but it did so with less training, especially in the EfficientZero variant; notably also on the Atari playground.


This is "The Bitter Lesson" of AI, no? "More compute beats clever algorithm."


Quite the opposite, a clever algorithm needs less compute, and can leverage extra compute even more.


Apologies, "clever" is a poor paraphrase of "domain-specific", or "methods that leveraged human understanding."[0]

0. http://www.incompleteideas.net/IncIdeas/BitterLesson.html


> MuZero not only matched or surpassed AlphaZero, but it did so with less training

Seems the opposite?


Thanks for pointing that out.

To be fair, MuZero only learns a model of the rules for navigating its search tree. To make actual moves, it gets a list of valid actions from the game engine, so at that level it does not learn the rules of the game.

(HRM possibly does the same, and could be in the same realm as MuZero. It probably makes a lot of illegal moves.)


Any high-enough dimensional space means the distance between any two vectors tends towards 1, so given a "good" concept all other related "good" concepts and all "evil" concepts are approximately equidistant from it, so this is inescapable; and therefore the Waluigi effect is too.

Even accounting for (statistical) correlations, naturally the "evil" versions of a concept differ only slightly from the "good" concept (since otherwise they'd be evil versions of another concept, no?) meaning that so long as there is some expressible "evilness", well, the classic notion of vector arithmetic from word2vec will carry over, even as some ineffable "evil vibes" that may apply in any number of directions and thus be applicable to a vast sway of concepts, since you can take an average of a bunch of "evil" vectors and end up with a vector that's now statistically correlated to this "evil vibe", so including this with a "good" concept that is otherwise uncorrelated allows you to create an "evil negative" of even the most "good" concept possible... and by dimensionality, it was already close in distance and similarity to begin with, so the artifact of this "vibe" was inherently embedded within the space to begin with, but emphasising this "vibe" or doing any such further statistical correlation (such as 'finetuning') increases correlation to this "evilness", and suddenly "corrupts the incorruptible", flipping a "good" concept into an "evil" negative version of that concept (hence, Waluigi).

Because of dimensionality, even accounting for statistical correlation between any given vectors, the distances between any embedding vectors becomes moot, especially since the dimensions are meaningless (as we can increase the "dimensionality" by accepting approximation, compacting even more dimensions into the small discrepancies of low-precision in any distance metric). So, for all intents and purposes, "evil" concepts aren't just similar to each other, but similar to their corresponding "good" counterparts, and to all other vectors as well, making misalignment (and, indeed, the aforementioned Waluigi effect) an inevitable emergent property by construction.

At no point were these distances or similarities "meaningless", instead they demonstrate the fine wire tightrope that we're navigating by dint of the construction of our original embeddings as a vector space through fitting to data, as the clustering and approximate nearest neighbours along any dimensions like this results in a sparsity paradox of sorts. We hope to take the next "step" towards something meaningfully adjacent and thus refine our concepts, but any time we "misstep" we end up imperceptibly stepping onto a nearby but different (perhaps "evil") tightrope, so we're at little risk of "falling" into the void between points (though auto-regression means we must end up at some attractor state instead, which we might think of as some infinite plummet through negative space, potentially an implicit with no direct vector representation) but instead we may end up switching between "good" and "evil" versions of a concept with such missteps... and by the argument around approximate values effectively placing additional dimensions around any basis vector, well, this quickly begins to resemble a fractal space like flipping a coin or rolling a die, where the precision with which you measure the results may change the output (meaning even just rounding to the nearest 0.001 instead of 0.01 may go from "good" to "evil", etc) in such a way that we can't even meaningfully predict where the "good" and "evil" vectors (and thus outputs) are going to arise, even if we started with human-constructed basis dimensions (i.e. predefined dimensions for 'innate' concepts as basis vectors) because by approximation the construction will always "smuggle" in additional vectors that diverge from our intent — the tightropes crisscross around where we "want" to step (near basis vectors) because that's where we're already likely to step, meaning any statistical correlation must go in the vicinity and by dimensionality so must unrelated concepts because it's "as good a place as any" based on the distance metric, and if they're in that vicinity too, then they're likely to co-occur, and now we get a survivorship bias that ensures these negatives and "evil vibes" (and thus any Waluigi) will remain nestled "close by" since those are the areas we were sampling from anyway (so act as a sort of attractor that pulls vectors towards them), and unavoidably so because by going at it from the other direction, those are the points from which we initially started constructing vectors and statistical correlations from in the first place, in other words, it's not a bug, it's literally the only feature "working as intended".


> Any high-enough dimensional space means the distance between any two vectors tends towards 1

Yes, but, you forget the impact that the attention mechanisms have. While high-dimensional embeddings suffer from concentration of distance, attention mechanisms mitigate this by adaptively weighting relationships between tokens, allowing for task-specific structure to emerge that isn’t purely reliant on geometric distance. If we can effectively "Zero" many of the dimensions in a context sensitive way, suddenly much of this curse of dimensionality stuff simply stops applying. It's obviously not perfect, transformers still struggle with over-smoothing among other issues but I hope the general intent and sentiment of my comment is clear.


That's not the uvx way? Dependencies at the top of a script was outlined in PEP 723, which uv/uvx added support for. Not everything is a "project", some files are just one-and-done scripts which should not have to carry the burden of project/environment management, but absolutely should still be able to make use of dependencies. The "uvx way" of doing it just means that it doesn't have to pollute the global/user install, and can even be isolated into a separate instance.

Besides, not everyone uses conda, and it would be quite a stretch to say it "might as well" be a built-in compared to, well, the actual built in, pip! Plus, uv works quite nicely as "just a pip replacement", which is how I started with it, so it aligns quite well to the actual built-in paradigm of the language.


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

Search: