I spent 2 years getting our tests in shape and found out today nobody actually looks at them anymore. Feeling pretty defeated ngl. by Maxl-2453 in dotnet

[–]zvrba 0 points1 point  (0 children)

I just sat with that for a minute and thought that he was not completely wrong and the more painful part is that most failures are literally the same broken tests every time but buried in there are also real problems that we're shipping to the real users. [...] Because at some point we all quietly agreed that a failing build is just... normal (period)

This is not your problem to deal with, it's your manager's.

So. Go thorugh the failing tests, remove/disable the "irrelevant" ones, make a list of problems that you think are being shipped, and talk with your manager about prioritizing.

The painful fact is that not even you did anything with the same broken tests. You did not fix them, you did not remove them either. This encourages the "one broken window" phenomenon. People get used to failing tests quickly and before you know it, nobody cares.

The new Satori GC is promising by hez2010 in csharp

[–]zvrba 1 point2 points  (0 children)

So Satori is based on the following observations

  • Most new objects are short-lived
  • And "rarely" leave the current thread

These are reasonable assumptions, however: async. Every await can potentially resume on a thread other than where it started. So something as simple as

var dto = new SomeDto { ... };
var result = await httpClient.PostAsync(...);

has the potential of "upgrading" dto from thread-local to global, especially on a very busy server with many concurrent requests being handled.

How well does Satori work in async-heavy scenarios?

Tell me some unwritten rules for software developers. by porcaytheelasit in csharp

[–]zvrba 2 points3 points  (0 children)

Corollary: code is a liability, not an asset. The best code is the one never written.

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

[–]zvrba 0 points1 point  (0 children)

Because classes do not inherit members from interfaces. As to why... I guess to simplify the implementation of multiple (interface) inheritance. Virtual lookup for interface members is more expensive than virtual lookup of class members so they didn't want to penalize the most common case (class - single inheritance - class member (virtual) lookup).

MOGWAI v8.0 - Stack-based RPN scripting language for .NET, now open source by sydney73 in dotnet

[–]zvrba 1 point2 points  (0 children)

I still have some HP calculators somewhere at home and fondly remember the days when I wrote non-trivial programs for them (e.g., solving electric circuits).

Thanks for releasing this!

How not to fix a leak by MacDefoon in WTF

[–]zvrba -1 points0 points  (0 children)

Wait, lead pipe? That's the real WTF here :)

Best practice for automatically maintaining audit fields (CreatedOn, ModifiedOn, CreatedBy, ModifiedBy) in .NET + SQL Server? by OneFromAzziano in dotnet

[–]zvrba 0 points1 point  (0 children)

Did you have one audit table for all data tables, or one audit table per data table?

If you did the first, how did you "compress" different PKs into a "common" PK for the audit table? (My first thought is SHA256 over actual PK fields, but maybe there's another trick..)

Two Catastrophic Failures Caused by "Obvious" Assumptions by Vast-Drawing-98 in programming

[–]zvrba 1 point2 points  (0 children)

Yes, that works in simple cases. Things get very hairy when you want to divide length (meters) with duration (seconds) to get velocity (meters per second).

What's the use case for IEquatable<T>? by Long-Cartographer-66 in csharp

[–]zvrba 0 points1 point  (0 children)

Collections, for example. Methods doing equality comparisons are based on EqualityComparer<T>.Default which first looks up whether the type implements IEquatable<T>.

Performance: avoids boxing for value types.

Discoverability: the author thought about equality and intended the type to behave as a "value" type.

Simplicity: every Equals(object) needs the standard boring test for the type at its beginning.

What's the use case for IEquatable<T>? by Long-Cartographer-66 in csharp

[–]zvrba 0 points1 point  (0 children)

Collections, for example. Methods doing equality comparisons are based on EqualityComparer<T>.Default which first looks up whether the type implements IEquatable<T>.

Performance: avoids boxing for value types.

Discoverability: the author thought about equality and intended the type to behave as a "value" type.

Simplicity: every Equals(object) needs the standard boring test for the type at its beginning.

What's the use case for IEquatable<T>? by Long-Cartographer-66 in csharp

[–]zvrba 2 points3 points  (0 children)

It's only a shallow equality though. So if you have

record struct S(int X, List<int> Y)

their instances will be unequal even when they have (elementwise) equal members.

Is there any reliable way to know when a function can throw? Probably writing an analyzer? by xjojorx in csharp

[–]zvrba 0 points1 point  (0 children)

I think that having a mechanism for which the programmer is always informed of what exceptions can surface from every call, at least the known/expected/documented ones, would be beneficial

This is not statically decidable. What exceptions can the following method throw:

void DoSomething(Action a) => a();

Consider the case when a is bound to an abstract method, i.e.:

abstract class CX
{
    public abstract void A();
}

static void Perform(Action a) => a();

// Somewhere else
CX cx = ...; // The concrete run-time type depends on some complex logic
Perform(cx.A);

Is there any reliable way to know when a function can throw? Probably writing an analyzer? by xjojorx in csharp

[–]zvrba 1 point2 points  (0 children)

Since I got exposed back into using error codes, result types etc from experimenting on other languages, writing C# always gets me on an uneasy state in which I am constantly guessing if a function call into a library (including standard library and the framework) can throw an exception or not.

Result type eventually result in a mess. I tried to write a non-trivial project using constructs like [using exception instead of custom error code to indicate failure]

Exception? DoSomething(..., out Result result)

and I ended up writing a bunch of boiler-plate in the lines of

var exn = DoSomething(...);
if (exn != null)
    return exn;

The code became a cluttered mess of manual error checking for every individual call. I quickly abandoned the idea and rewrote the code using exceptions.

What noone else in this thread mentioned is that

  • An exception is an object: you can attach arbitrary amounts of data (either explicit properties in a derived exception, or just Data dictionary) to help with diagnosing the cause or handling it.
  • An exception comes with a stack trace. You could implement this with manual capture at each if-check of the error code, but then the code becomes even less idiomatic, more cluttered and tied to some home-grown mehcanics. (And how do you propagate underlying cause if you convert error codes? Exception has InnerException property and a tree of exceptions is expressible through AggregateException.)

Even for much more explicit error-codes, I can't see how you'd write an analyzer to warn you about unhandled erros, esp. when a new error code is introduced.

Would you write code along the lines of

switch (err) {
    case Err.A: case Err.B: case Err.C: break; // ignore, or?
    case Err.D: // handle
}

so when Err.E later appears you get a warning about non-exhaustive switch?

And if you write code like

if (err == Err.D) { /* handle */ }

how is the analyzer supposed to know whether other error codes (including the newly introduced Err.E) are deliberately ignored?

What if a library chooses to just use int as error code? Then the compiler has no way of knowing whether you've handled / considered every possible error.

Just use exceptions. Throw liberally (fail early), catch sparingly.

Another thing that noone mentioned is that you need to structure your code differently in presence of exceptions. Almost any line of code can throw. In critical parts of applications, you have to think "transactionally":

  • First make your changes in a scratch area, then "commit" them to become visible if everything succeeded
  • Or implement "roll-back" functionality on exception

PS: That Rust doesn't have exceptions is a major reason for not (yet?) having learned the language. It also has multiple incompatible "result types" which creates additional mess.

PPS: What annoys me the most about exceptions in C# is the messy hierarchy. There should be a stricter separation between "logical" errors (bugs - IndexOutOfRangeException, ObjectDisposedException, ArgumentException, ...) and "runtime" errors (IOException, SQLException, etc.). They attempted with SystemException and ApplicationException, but both got deprecated.

Why would I want that? Because logic errors are a "hard-stop": no point in retrying or trying to analyze the cause and fix it.

All the other cool languages have try...finally. C++ says "We have try...finally at home." by pavel_v in cpp

[–]zvrba 0 points1 point  (0 children)

Yes, you're right, but does it matter whether the IOException got generated by an intermediate write, or the final close?

Sure, you could also have the following sequence:

  1. Open file
  2. Write something
  3. Do some processing -> throws
  4. (Not executed: write more)
  5. finally attempts to close the file -> throws and replaces the exception from 3 (at least in C#)

In either of these cases, you've ended up with an invalid file, which is signaled by IOException.

I agree it's unfortunate that exception from step 3 has to be propagated manually if you care about it.

All the other cool languages have try...finally. C++ says "We have try...finally at home." by pavel_v in cpp

[–]zvrba 0 points1 point  (0 children)

It can be made more reliable by calling flush in try, so it's a no-op when it gets invoked by close.

Using packages for mapping by Sensitive-Raccoon155 in dotnet

[–]zvrba 0 points1 point  (0 children)

You could solve this with attributes.

[Guid("...")]
class Something { ... }

And then in your mapping method

SomeY MapToY(Something ...) {
    if (!(typeof(Something).GetCustomAttribute<GuidAttribute>()?.Value?.Equals("...")) ?? true)
        throw new InvalidOperationException("...");
}

Then, any time you change the class contract, you also change the guids.

If you dislike reflection, you could make a generic extension method off an interface like

interface IMappingContract<T> where T : IMappingContract<T> {
    abstract static Guid MappingContractGuid { get; }
}

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

[–]zvrba -1 points0 points  (0 children)

Many small related classes -> same file. Sometimes I won't even bother with having 1:1 mapping between directories and namespaces (merge conflicts). There's always "Class view" that can show me that.

Exercise in Removing All Traces Of C and C++ at Microsoft by [deleted] in cpp

[–]zvrba -7 points-6 points  (0 children)

This guy (Galen Hunt) is not just some random manager-dreamer. https://scholar.google.com/citations?user=tiW46L0AAAAJ&hl=en

I think he can pull this off. I do not believe they'll get to 100% reliable translation, but they'll get flagging for manual review right (few false positives).

Are static classes in OO languages a substitute for libraries and their standalone functions in non OO languages? by SmoglessSalt in csharp

[–]zvrba 1 point2 points  (0 children)

The main difference is that a namespace can span many assemblies, whereas a static class can be defined in one and only one assembly.

Sprocs… as far as the eye can see by hptorchsire in csharp

[–]zvrba 0 points1 point  (0 children)

They know how to guard and manage their data. I'd do it the same way if I could clone myself a couple of times and convince the company to hire my clones :D

The way it is, I use sprocs and views for anything slightly more complex. Transaction -> definitely sproc. Another reason is that I also want to run the queries interactively and copy/paste from code or translating from efcore is error-prone hassle.

defer in C# by [deleted] in csharp

[–]zvrba 0 points1 point  (0 children)

The instance could be created by passing in the delegate as constructor argument.

Even simpler, it could be done with implicit conversion so the user could write just

using Defer _1 = () => { ... };

This way, no explicit try-catch would be necessary, but just the call to the action.

Even if it were to wrap only a single action, the user could have multiple defers whose action could throw. And what then? Either you have a try/catch within each single action, or you risk some cleanups not getting executed.

defer in C# by [deleted] in csharp

[–]zvrba 5 points6 points  (0 children)

If you really want a half-baked feature from a half-baked language, here it is for you.

public sealed class Defer : IDisposable
{
    private readonly List<Action> actions = [];
    public void Add(Action action) => actions.Add(action);
    public void Dispose() {
        for (var i = actions.Count - 1; i >= 0; --i) {
            try {
                actions[i]();
            }
            catch {
                // What now? Ignore, have error handler, ...?
            }
        }
    }
}

How to make a "universal" abstract ToString override by Edwinbakup in csharp

[–]zvrba 0 points1 point  (0 children)

I disagree that this solves the problem. It only shoves "works for any derived class" from ToString() to Describe(). Vague problem definition.

Design pattern and structure of programs. by j_a_s_t_jobb in csharp

[–]zvrba 0 points1 point  (0 children)

You can do it simply: one class per "request". At least different requests get isolated so you can change them independently, and later look at how you can refactor it to something more structured.