All asserts need to have messages attached! Explicit as possible!

FoxyBrown via Digitalmars-d digitalmars-d at puremagic.com
Fri Jul 7 20:33:56 PDT 2017


On Saturday, 8 July 2017 at 02:23:53 UTC, Jonathan M Davis wrote:
> On Saturday, July 8, 2017 12:55:46 AM MDT FoxyBrown via 
> Digitalmars-d wrote:
>> I came across some error in heap sort. Was erroring out on the 
>> wrong. A few lines below the assert existed but no error 
>> message associated, why is it so hard to not write a few extra 
>> EXTREMELY helpful error messages?
>>
>> assert(isHeap(r), "This is an ERROR AT THIS
>> LOCATION"~__FILE__~"("~__LINE__~")");
>>
>> etc?
>>
>> It should be mandatory that all asserts, throws, etc provide 
>> correct information about not only the point of the error but 
>> also the location and what caused it. These things are not 
>> irrelevant but affect all those that use it... imagine the 
>> real human man hours that could be saved if such things were 
>> done.
>>
>> It would be easy to find all the bad asserts?
>
> AssertError already provides the location of the assertion, and 
> it uses __FILE__ and __LINE__ to do it (_all_ Exception types 
> do that unless the person who wrote the class screwed up the 
> constructor), so adding them to the message it pointless and 
> redundant. If the assertion failure is printing out the wrong 
> line, then it's likely either because you're looking at the 
> wrong version of the code or because a string mixin is screwing 
> with the line numbers (which IMHO, shouldn't happen, but it at 
> least used to be a problem).
>
> In addition, the AssertError should be giving you a stack 
> trace, which _should_ have the file and line numbers in it of 
> every call in the stack (though stupidly, the line numbers 
> don't always work, depending on your OS).
>
> So, you _should_ have had that information by the simple fact 
> that an AssertError was thrown, and unless the assertion itself 
> needed additional explanation beyond the condition that failed, 
> then a message wouldn't have helped anyway.
>
> So, if the file and line number was wrong, the question is why, 
> and that should be fixed. And we really need to figure out how 
> to make it so that the issue of not having line numbers with 
> stack traces goes away and stays away. The fact that it's been 
> a problem is ridiculous, because file and line numvbers in 
> stack traces are critical for debugging.
>
> - Jonathan M Davis

But you miss the complete point, You focused on what D does 
rather than what it doesn't, which is what lead me to the problem 
in the first place. You are seeing the glass half full, rather 
than half empty, my friend.

Shall I explain it so it makes sense? I was writing a natural 
sorting routine so I could get some string array sorted. This is 
because D is missing the capabilities to do a natural sort 
correctly. It does not compare the the integer in string a with 
the matching integer in string B correctly. If they happen to be 
a different length then it assumes the shorter one was smaller. 
At least, when I tried it, that is what I remember being the 
problem, or some other weird behavior, but it was not correct. 
Therefore, I decided to write the natural sorting routine to fix 
that(This is because I am a person that wants to drink a full 
glass of water rather than an empty glass).

To implement the algorithm is rather simple in some ways and 
complicated in others.


string[] naturalSort(string[] arr) /*pure @safe*/
{
	alias myComp = (x, y) {
            return ComplexPart(x,y);
         };

	auto x = arr.sort!(myComp).release;
	return x;
}

bool ComplexPart(string x, string y)
{
		auto ml = cast(int)(min(x.length, y.length)-1);
		auto ofsX = -1; auto ofsY = -1;
		auto numX_found = -1;
		auto numY_found = -1;
		for(int i = 0; i <= ml; i++)
		{
			// If one string is left slice of the other, it wins
			if (i >= ml || ofsX >= ml || ofsY >= ml) { if (x.length < 
y.length) return true; return false; }

			ofsX++;
			ofsY++;
			
			// If characters are not a digit, use default comparer
			if (!isDigit(x[ofsX]) || !isDigit(y[ofsY]))
			{
				if (x[ofsX] != y[ofsY])
					return x[ofsX] < y[ofsY];
				continue;
			}

			// We now know that x and y are identical up to the digit 
sequence. Extract these sequences then compare, if identical *in 
value*(000 = 00000, etc) we continue the compare, else we compare 
the numbers and use that to specify the comparision quality
			while (ofsX < ml && isDigit(x[ofsX])) { ofsX++; };
			while (ofsY < ml && isDigit(y[ofsY])) { ofsY++; };

			auto numX = x[i..ofsX];
			auto numY = y[i..ofsY];

			auto res = compareStringNum(numX, numY);		
			if (res != 0)
				return (res != 1);
			
		}

		return x > y;
	};
}

(I've taken a brief time away from my life to explain the problem 
in a bit more detail that I normally would. My real code manually 
inlines the ComplexPart function. Actually, I came up with that 
function just now and specially for you.)

As you can see, there are only really two logical parts to the 
naturalSort. In fact, one can say there is only one part and that 
is `arr.sort`! Which is a function that sorts the string array 
list `arr`.

The lines of code of simple importance is:

	auto x = arr.sort!(myComp).release;
	return x;


`arr.sort` takes a special kind of string comparer (binary) 
function that informs us if a string(x in this case) is greater 
or lesser than another string(y).  That is, MyComp is a total 
order on the array of strings. It is irrelevant, only for sake of 
argument since we both have lives to attend to outside of this 
`playground` activity we have taken up as adults,  because what 
happens when I actually run my code(Actually, not right now, as 
that would be redundant, but the first time I did it(like all 
first times, it never goes quite right)) is quite a curious 
thing. Very intriguing.

Visual D provides a pretty generic and ugly assert message(Not 
the kind you want to take home to your mother).


[***ATTENTION: What follows is a textural reduction for 
visualizing what really happened, instead of making a movie, 
which would contain about 10B(at least) different pieces of 
information to show what exactly happened(which is now impossible 
due to causality), you must pretend you are watching that 
video... better yet, to really get in to it pretend you are 
having the experience... then eventually you will experience it 
for real(if you haven't already)***. For clarity, I will mark the 
action points with ******* and they are sort of like annotations 
and meta data to understand what I'm talking about with more 
clarity. You must use your brain to the upmost potential to 
understand this well.]


     //template because of @@@12410@@@
     void heapSort()(Range r)
     {
         // If true, there is nothing to do
         if (r.length < 2) return;
         // Build Heap
         buildHeap(r);
         // Sort
         for (size_t i = r.length - 1; i > 0; --i)
         {
             r.swapAt(0, i);  ****** BAM! Visual D plomps this on 
my lap. See [1]
             percolate(r, 0, i);
         }
     }

     //template because of @@@12410@@@
     void buildHeap()(Range r)
     {
         immutable n = r.length;
         for (size_t i = n / 2; i-- > 0; )
         {
             siftDown(r, i, n);
         }
         assert(isHeap(r), "Build Heap Error");
     }

     bool isHeap()(Range r)
     {
         size_t parent = 0;
         foreach (child; 1 .. r.length)
         {
             if (lessFun(r[parent], r[child])) return false;
             // Increment parent every other pass
             parent += !(child & 1);
         }
         return true;
     }


[1] This is the line that visual D highlights as the error; and 
pops up the standard exception popup window that all visual D 
users know about.

The assert gave the typical nonsense that takes far too long to 
really read and understand because it tends to be abstract 
gibberish(IP address, dll module that caused the crash, file that 
caused the crash, line number, and possibly, if you stand just 
right and balance on your nose using only a single white feather, 
you will get the almighty glorious WARNING MESSAGE!! No, the real 
thing, but the actual information that we computer programmers 
have encoded in to electrical bits(transistor states) by 
mechanical lever action operating at about 10000 Billion 
<AAIIFPP7BOITTCR>, to help they fellow other human beings out. 
It's a dangerous world out there and we must all help each other 
fill the glass up! These `Warning Messages` inform us on a more 
conceptual level allowing us to build faster conceptual devices 
so we can increase our speed. Look out fast your average human 
programmer can type, my friend, to his average closest cousin, 
the chimpanzee.. or is that ape? It doesn't matter because those 
two are both closely related too(Just like natural sort, natural 
selection has it's own total ordering(of on DNA, if you care)). 
It's all about speed! The time is running out for all of us. 
..And just like ant's, we have to build it for them to come(But 
we usually go after ants with the most deadly poisons, cause they 
wouldn't understand love... Hopefully the ones coming to us won't 
destroy us like we do the ants, or birds, or rain forest, or 
whatever. Or maybe we will attack them, what only amounts to 
bites, which case it is Kum ba yah... just, we won't be the ones 
singing it.

But back to the specifics. Lets dive a little bit more in to the 
code:


Being the patient observer I am[*I'm actually quite impatient(I 
spend all my time trying to get the glass filled, it's hard work, 
but someone has to do it), but I must then have patients for 
getting things filled, since I'm so good at it], I observed the 
warning popup[the one we talked about earlier] and saw that it 
had a line number 2230, and being of single mind and body, and 
quick witted, and having a memory like a turnip, I had a unique 
moment of genius inspiration where I realized that the actual 
line the error cursor was at in visual D, was not 2130 but 2117!! 
That was the chink in the armor. (Actually I think I just 
scrolled down a few lines looking for the assert, I'm not really 
that smart to get it by genius.)


But, not being a heap expert, after all, who's an expert on all 
things, I did not know why the error was occurring and had to 
spend time learn about heap, the heap property(hey, just a total 
ordering! What do you know!), the D implementation, and so forth. 
The exact amount of time spent learning about this area of 
knowledge could have been nanoseconds or lightyears, no body 
really knows. Regardless of time, it is safe to say that time was 
wasted.

If I am the only human that experiences such bursts of time 
wasting activities such as having to learn about where an error 
in the D code actually is, what the D error actually is telling 
me, and how to solve the said D error(and for that matter, any 
error, An error in a C program, an operating system, a society, a 
government, a specifies, abrain, any annoying bug that rots away 
the essence of our souls by draining our glasses), then be it so. 
But if there are millions, nay, billions, like me, then what a 
waste of time! Is it not the only way to solve the problem is to 
solve the problem? If so, then surely any logical being will 
conclude the if errors and computer bugs are problems(again, we 
can extend the problem set to all problem sets and our logic 
still applies:See category theory), and that they must be solved, 
then the only way to solve them is to solve them. But if these 
problems are related to all other problems(and they are), then it 
is important that we solve them correctly, to the best of our 
ability, as to not introduce more problems, else, the human race 
spends its entire existence solving the same old problem, which 
is just a problem of another `N` problem... broken in to `N` 
choose `M` smaller problems(like ants and dirt, we build our 
castles to the sky).

So, is information not one way to solve problems? Surely the 
knowing of a problem is bad information, if we didn't know about 
any problems then there couldn't be any, could there? Don't take 
me literally friend, I only mean it as an abstraction.

So, to make a long story short: Why can't we just get better damn 
error messages?

Can we not be absolutely serious for one minute?

module std.algorithm.sorting;

has 402 assert error statements and only 402 of them have 
absolutely no error messages added! Seriously, only 402! That's 
like 43%, right?!?

Actually I might have overestimated because I have no way to 
actually count D assert statements since modern search and 
destroy(seek/find) do not have the ability to parse a string of 
letters as as if it were part of some grammar, which they always 
are. If it did, then I could easily count the exact and true 
number of error-less message asserts.

I think the results would be different but similar.

is that 402 roaches, 402 ants, maybe 402 golden tickets(if your a 
'glass is half  full' kinda person), I mean, not solving the real 
politicians, that's kinda been like the last 10-20 of our 
presidents, look how great it's been!

***In the meanwhile, 4 other programmers die of a stroke...



More information about the Digitalmars-d mailing list