To be fair, that is a downstream effect of C's worst mistake (NUL terminated strings). Also, if every allocation you'd get is ptr+size you could just derive it by also copying the size.
Basically, the issue is C having unsized allocations and related not tracking string length.
This one is up to date and it's definitely inconsistent, but I could not use ':' in place of '->' without creating an ambiguous grammar. Same for parenthesis in the return type since you can have a comma separated list:
It is not possible since you can create new integer types by sub-classing the primitive ones:
class UserId: Int64
...
end
var user = UserId: 42
I also plan to replace predefined Int64, Int32, ... by generic types Int(64), Int(32), ... LLVM allows any integer size and Copper allows this kind of generic types.
The parallel assignment just work mostly like it does in ruby so that doesn't look weird to me (except the need for 'var' in the first place).
Agreed on the rest, though I don't understand what the problem would be with recursion. Is it using reference passing also for primitives like integers?
> Is it using reference passing also for primitives like integers?
That's what I assumed, but honestly I might have misunderstood the docs. This passage is not very clear:
> Copper manipulates only references to objects. Simple data types such as integers must be seen as references to stateless objects (i.e. objects that have no state in memory).
Sounds like they store the integer in the reference itself in that case. Which also is how Ruby does things (though Ruby has to decide what is what at runtime and thus steal a couple of bits off every integer).
You seem to reason in terms of trying at all costs to block the other players, not to maximize your gain. I agree the ultimate goal is to do better than all the others, but the tactics to get there may involve temporarily favoring other players in win-win exchanges to grow quicker, or to block a third player already far ahead, etc.
What surprises me is that the original VLC filter does not use SIMD. Sometimes I wonder why I spent my money on a "modern" CPU with a lot of new features that stay completely ignored by most software I run every day.
It's also a basic implementation, doing a divide per sample to renormalize and not taking advantage of the symmetry of the kernel.
Even on a GPU, you wouldn't use an algorithm this simple in production. For small radii, leveraging bilinear filtering halves the number of samples. For larger radii, hierarchical pyramid approximations are popular.
Probably a reflection of the age of that code along with the usefulness of the feature. If no one actually needs the video blurry, then it doesn't matter how efficient the filter is.
It's possible it's a deliberate project decision to support very old CPUs. But it could be multi-targetting different CPUs and using SIMD whenever available.
Are large gaussian blurs not used for modern glass effects? Worth pointing out that doing so really requires use of FFT convolutions -- an optimization that has not been implemented in the benchmarks.
Not really the question that this study is addressing though.
That's like saying Valve just released the first ever standalone VR headset because the standalones that came before had advertising and trackers (or worse). Or that TVs aren't produced anymore because they all come with similar software. Or cars.
Saying RTX Spark is the first laptop with 128 GB of unified memory just because you don't agree with the previous laptops with 128 GB of unified memory is just incorrect. You could easily make it true with qualifiers but there were none here!
Also did nobody ever release a 128GB Strix Halo laptop? I remember that being a thing around when the Framework Desktop came out? And feels like that'd have even better Linux support than Nvidia? What's the ideological objection to that?
To be fair, TFA lists more reasons to avoid Windows:
> Mine include the privacy concessions during setup, the years spent waiting for Microsoft to let people put the taskbar on the side of the screen again, and the advertising.
Of course you don't have to agree on all of them, but please don't assume everyone acts only because they can't find a tutorial on the net!
> Cheaper, faster, smoother, quieter, wake up every day to a full "tank", less things to go wrong
I agree to everything except waking up every day to a full "tank". That's only if you have your own house. If not, you'll depend on public chargers, so you'll buy "fuel" at premium prices, possibly higher than petrol, and you'll have to move your car at the end of the recharge in the middle of the night to avoid the parking fee.
Doing non-trivial preprocessing is a mistake. You get slow compilation, hard to debug code, opaque and fragile code, and incredible complexity. If you want metaprogramming, you're better off with C++ it you need C header compatibility, or zig if you don't.
Otherwise, it's probably a good idea to pretend that the only preprocessing directive is #include. With constexpr, even #define is obsolescent.
Doing non-trivial anything you slow down compilation, make debugging harder and increase fragility and complexity. Sometimes that's a mistake, sometimes not.
Getting rid of something because someone sometimes abuses it, is short-sighted.
Yes and no. If you want to make something like a generic dynamic array, you can do it with type erasure (`void*`), but then your code is no longer typesafe. I would find that more fragile. The preprocessor allows you to add constructs that make it behave like any other modern language.
As an aside, clangd can dereference a macro in place to make debugging easy.
I am not sure. I agree one should minimize macros in C, but for some things a small macro layer still beats the complexity of C++ and is not inferior in my opinion.
C++ templates are far cleaner, easier to debug, and produce more comprehensible errors than C macros. And C++ templates are rightly famous for being terrible at all of the above.
Hey, I agree about your second sentence but I do not really see the first. Alone that I can directly inspect the result of the preprocessor makes macros easier to debug than templates in my experience.
What you're saying is like saying "C can be expanded to assembly, and that makes it easier to debug". If you need to do that, the entire process has failed.
> I can directly inspect the result of the preprocessor makes macros easier to debug
Tangential note but: why does this require a separate re-invocation of the compiler with the '-E' flag? Say I have this silly example with a comma instead of the semicolon inside W() macro:
#define W(a, b) b, int a
#define X(a, b) W(b, a)
int kekw(int x) {
int z = X(23, k) = x;
return z + k;
}
When I shove it into GCC without -E, it says
: In function 'int kekw(int)':
:1:21: error: expected unqualified-id before 'int'
1 | #define W(a, b) b, int a
| ^~~
:2:18: note: in expansion of macro 'W'
2 | #define X(a, b) W(b, a)
| ^
:5:13: note: in expansion of macro 'X'
5 | int z = X(23, k) = x;
| ^
:6:16: error: 'k' was not declared in this scope
6 | return z + k;
|
instead of, you know, showing me the expanded text so that I could see what's actually wrong with the generated variable declarations? Something like
: In function 'int kekw(int)':
:1:21: error: expected unqualified-id before 'int'
1 | #define W(a, b) b, int a
| ^~~
:2:18: note: in expansion of macro 'W'
2 | #define X(a, b) W(b, a)
| ^
:5:13: note: in expansion of macro 'X'
5 | int z = X(23, k) = x;
| ^
:5:-: note: the expanded source text is
| int z = 23, int k = x;
| ^~~
:6:16: error: 'k' was not declared in this scope
6 | return z + k;
|
perhaps? I understand that tracking the lines/columns inside the expanded text is highly non-trivial (although collapsing them all onto the position of the top-level macro is already just as non-trivial), but still. Show me what the source that you actually can't compile, not the three-steps removed precursor to it — I sure as hell can't expand macros in my head.
Also, what is this first error message about in the first place? Why the hell does it expect unqualified-id before "int"? If you put "int" after the unqualified-id, it still would be illegal; and an unqualified-id is not the only thing that can follow the comma in this context anyway.
During translation of source text to a C program, the source text goes through several phases. It turns raw bytes into preprocessor tokens, then preprocessor tokens get expanded into more preprocessor tokens and then preprocessor tokens get translated into C tokens, which are fed into the C parser. There is no “expanded text”, only expanded tokens. Generally this is implemented as a state machine that produces tokens on demand, so there is no expanded text. When GCC shows you that error message, it uses the recorded source location and looks it up in the original source file. This is trivial to do. Expanding just one line of the source file would either require re-invoking the preprocessor from the beginning or storing already consumed preprocessor tokens.
Obviously this is possible, but no one has gotten around to implementing this feature and it’s not clear you would want either solution: buffering preprocessor tokens in case you need to expand a line for an error message greatly increases memory usage and the vast majority of compilations are successful ones with no errors, slowing down the normal case. And re-invoking the preprocessor to show you one line on every error message makes error reporting slow.
> There is no “expanded text”, only expanded tokens.
If the compiler supports "-E", there absolutely is some equivalent of the expanded text, with (somewhat limited) whitespace info available: if you insert whitespace into between "b" and the comma in "b,", then "-E" invocation will dutifully show it. Yes, multiple spaces are collapsed into one, but their presence/absence is tracked already.
> Expanding just one line of the source file would either require re-invoking the preprocessor from the beginning or storing already consumed preprocessor tokens.
Yeah, keep the whole expansion of the latest top-level (not nested) macro. I believe some bytecode-like compression scheme (a replay of that state machine you mentioned) à la LZ would work fairly well, with minor additional memory necessary. Hell, scratch that: since #define/#undef are impossible inside a macro, you don't even need to remember the expansion of the macro, you simply need to keep the current macro definitions and remember what was the last macro you tried to expand — if your error happened inside its expansion, just re-expand again. Zero additional memory needed, since this information is already stored for the current way of error reporting — you can see in the current output that it remembers what macros it expanded and where, the whole path down to the offending token: at 1:21 "in expansion of macro 'W'" which was at 2:18 "in expansion of macro 'X'" which was at 5:13.
> And re-invoking the preprocessor to show you one line on every error message makes error reporting slow.
Eh, it's on the whole faster than making the programmer re-run with "-E" option manually.
> If the compiler supports "-E", there absolutely is some equivalent of the expanded text, with (somewhat limited) whitespace info available: if you insert whitespace into between "b" and the comma in "b,", then "-E" invocation will dutifully show it. Yes, multiple spaces are collapsed into one, but their presence/absence is tracked already.
Whitespace is significant in the preprocessor so of course it tracks whitespace. Whitespace isn’t dropped until phase 7 when pp-tokens are converted to C tokens.
As I said it’s not impossible, write the patch and see if GCC accepts it.
Also the position in the original source code is tracked.
In fact, this enhancement should be doable. Please file a bug. But the answer why something is not done in a C compiler is usually: Nobody did substantial investments on it in the last two decades. So if you want to see improvements, usually one has to submit a patch.
It'll work in reality, but I don't think C makes any guarantees about how the pointer p is represented in (uintptr_t)p, only that a roundtrip pointer -> uintptr_t -> pointer will give back p. So (as far as I know) you can't assume that the offset needed to make (uintptr_t)p a multiple of `align` is the same as the offset needed to align p to `align`.
A string created by strdup().
reply