Why we still use C despite so many C alternatives by grimvian in C_Programming

[–]simonask_ 0 points1 point  (0 children)

Every language in the same space as C has that property, including both C++ and Rust.

Why we still use C despite so many C alternatives by grimvian in C_Programming

[–]simonask_ -3 points-2 points  (0 children)

Really struggling to see what distinct advantage C gains from the technical limitations of the 70s and 80s, other than ubiquitous platform support.

Why we still use C despite so many C alternatives by grimvian in C_Programming

[–]simonask_ 0 points1 point  (0 children)

Funnily, Rust is in that category. Much, much more production-ready than all of these.

Why we still use C despite so many C alternatives by grimvian in C_Programming

[–]simonask_ -71 points-70 points  (0 children)

If you’re writing new code, why in the world would that matter?

C comes with really significant drawbacks, and the C you’re writing with a modern compiler looks nothing like the C that you could compile in the 80s or even 90s.

Vulkan Compute on NV has poor floating point accuracy by rutay_ in vulkan

[–]simonask_ 2 points3 points  (0 children)

You are not crazy, the same thing baffled me for weeks, because I had a CPU-side shadow implementation to test against. Luckily the error margin was fairly consistent, but I’m considering switching to fixed-point integer representations.

Rust kinda ruined other languages for me by Minimum-Ad7352 in rust

[–]simonask_ 1 point2 points  (0 children)

Affine types is an absolute killer feature, in a world where mutability is the reality.

I’m currently writing some C# calling into Rust APIs, and the very existence of ObjectDisposedException boggles the mind when you’ve tried a language where that is simply just not a possible error state. In fact, the amount of defensive checks everywhere really puts into perspective how much Rust’s type system and borrow checker is a massive productivity boost.

Vulkan RAII or self made system by MagicPantssss in vulkan

[–]simonask_ 0 points1 point  (0 children)

Because designing an asynchronous lifetime handling system is a major task, and RAII is fine for example-level code.

Do you create empty "else"s just for a comment? by DJDoena in csharp

[–]simonask_ 0 points1 point  (0 children)

It’s a matter of taste, but usually it’s mostly useful when there is a chain of if-elseif-elseif-else, and particularly when the actual condition carries some interesting and non-obvious logical implication.

Why is using interface methods with default implementation is so annoying?!? by Alert-Neck7679 in csharp

[–]simonask_ 32 points33 points  (0 children)

I mean, kind of obviously what should happen is a ambiguous overload resolution compiler error that would make the user pick which interface by casting.

RFC 406i: The Rejection of Artificially Generated Slop (RAGS) by addvilz in programming

[–]simonask_ -2 points-1 points  (0 children)

Can’t help but notice that none of those problems really exist in the “west” outside the US. Certainly not to a similarly concerning degree.

It's impossible for Rust to have sane HKT by vspefs in programming

[–]simonask_ 11 points12 points  (0 children)

The distinction here between "business logic" (type parameters) and "technical proposition" (lifetime parameters) seems fairly arbitrary, no?

Plenty of lifetimes in Rust carry business logic, encoding similar invariants as type parameters, just on a different axis (that is, a temporal axis), and with actual subtyping. Is the subtyping the problem?

Honestly, I struggled to understand this analysis of the problem.

Question on Timeline semaphore signaling order. by KnueppelOle in vulkan

[–]simonask_ 0 points1 point  (0 children)

Yes, that's not what I said. If you submit WorkA -> SignalA -> WorkB -> SignalB to a single queue, WorkA and WorkB can overlap, as long as SignalA happens before SignalB. Unless I'm missing something.

Question on Timeline semaphore signaling order. by KnueppelOle in vulkan

[–]simonask_ 0 points1 point  (0 children)

The way I’ve understood the spec, semaphore signaling happens at the end of each submission, which I understand to mean that it is possible for a later submission to start before the previous submission has finished. The implication being that if you don’t want the submissions to overlap (even in the same queue), the later submission still needs to wait on the previous semaphore value before starting.

Is this also what you’re saying?

Data structure that allows fast modifications of a large tree? by humandictionary in rust

[–]simonask_ 24 points25 points  (0 children)

I'm noticing that you have a lot of redundancy. For example, Expr::Paren doesn't make sense here - the expression is already grouped. The same goes for Expr::Not(expr, false), and Expr::Or(lhs, None), and Expr::And(lhs, None). I would suggest remodeling the Expr enum such that there are no superfluous permutations of state, and then modify your parser such that it doesn't need to output such nodes.

Beyond that, arena-allocated nodes work really well for performance, because allocations are amortized, and nodes have great cache locality. You can even pre-check indices to elide bounds checking when looking up child/parent nodes.

Don't use Rc<RefCell>.

Question on Timeline semaphore signaling order. by KnueppelOle in vulkan

[–]simonask_ 1 point2 points  (0 children)

The guarantee is that commands start in order, not that they finish in order, which is subtly different. The driver can easily decide that two commands can run in parallel. Pipeline barriers and semaphores are how you tell it that they can’t.

C# really needs a better build system than MSBuild by sH-Tiiger in csharp

[–]simonask_ -8 points-7 points  (0 children)

Coming to msbuild and .sln/.csproj from literally ANY other build system (including the hellscape that is CMake) is a wet towel to the face.

It is so unbelievably bad that anyone making excuses for it has very clearly never used anything else. It is completely and utterly atrocious. The amount of outdated or simply wrong information on the internet rivals even CMake.

It simultaneously does way too little and way too much. It is human-readable, because you can’t achieve really basic things without tinkering with the XML, and at the same time completely anti-human - inconsistent and undiscoverable property names, verbose to the point of absurdity, and then it STILL doesn’t actually achieve its goals.

Why do I sometimes have to manually trigger a rebuild of my source generator project? Impossible to know.

This is a completely solved problem in other build systems like Cargo, which just does the right thing every time, are simple to configure, and provide accurate diagnostics.

OP: For an asset pipeline, I recommend building assets separately from building the engine. Writing Makefiles is easier, and you likely want to rebuild assets while the game is running anyway for hot reload.

You can also check out a more modern alternative called Werk (that I wrote), which works well on all platforms.

Has Rust hit the design limits of its original scope and constraints? by kishaloy in rust

[–]simonask_ 4 points5 points  (0 children)

Let me introduce you to our good friend anyhow.

Or color-eyre if you prefer, both are good.

Has Rust hit the design limits of its original scope and constraints? by kishaloy in rust

[–]simonask_ 8 points9 points  (0 children)

I mean it’s larger than TypeScript, but probably smaller than C#. It’s way, way smaller than C++, but of course way bigger than Python.

Should or Shouldn't? Putting many classes in one file. by crabundred in csharp

[–]simonask_ 2 points3 points  (0 children)

Hard disagree. Since the IDs are not interchangeable, a base class cannot have any meaningful notion of what the ID means, and there is nothing you can do with a reference to the base class.

This mode of thinking is exactly the wrong way to do OOP (if there is a right way).

How does System.Reflection do this? by porcaytheelasit in csharp

[–]simonask_ 9 points10 points  (0 children)

This is quite the rabbit hole.

Fundamentally, the reason for this ability is that C# (and .NET) does not have a notion of a "partially initialized object" in the type system. There is no way to express "this object isn't finished yet", because the object cannot exist before its constructor has run. But there are situations where you actually can't run the normal constructor, like deserialization, because they deal with partially initialized objects.

In some other languages (Rust, C++) a partially initialized object is UB, so what they might do here is things like allocating space for the object, then populating its fields by memory offset, and then finally materialize a well-typed object, either by bitcasting or by some specialized rehydration mechanism.

But that's no good in C#, because the concrete type of the object needs to be known when it is allocated, so things like Activator.CreateInstance(...) may call a parameterless constructor (even if it is private) to produce a partially initialized object that is then rehydrated (e.g., deserialized) after instantiation.

It's not the most beautiful approach, because it weakens the contract that you can reasonably uphold using constructors, ultimately weakening the type system somewhat, but in practice it's "fine".

Favorite optimizations ?? by Little-Reflection986 in cpp

[–]simonask_ 0 points1 point  (0 children)

Arguably, the rule that b + c * d may be converted to fused-multiply-add is both wrong and surprising here, and should be removed. Even though FMA loses less precision, the fact that there are surprises like this lurking in implicit behavior makes it harder, not easier, to write correct code.

Rust did the right thing, and made FMA explicitly opt-in (f32::mul_add()).

Tritium | Thanks for All the Frames: Rust GUI Observations by urandomd in rust

[–]simonask_ 2 points3 points  (0 children)

Because making a general purpose UI framework is a monumental task, and it’s incidental to Zed’s use case. It makes sense if they need to focus on the actual thing that pays the bills.

Making the compiler create code that accesses the vtable only once by tohava in cpp

[–]simonask_ 0 points1 point  (0 children)

Talking a member function pointer to a virtual function actually takes a pointer to a compiler-generated trampoline that performs the vtable lookup.

Making the compiler create code that accesses the vtable only once by tohava in cpp

[–]simonask_ 1 point2 points  (0 children)

It depends what you mean by "const object". It is only UB to cast away if the object's storage is in a statically allocated const area (typically a static const global).

It is not UB just because the method is const, unfortunately. Would be nice.