How do you decide where to stop compressing?

Hello,

I am going through Day74 where Casey Muratori is defining the stairs and in that vein he implements Barycentric coordinates for the stairwell.

Now in this, when he wrote the GetBarycentric function I couldn't help but notice that its basically 3 vector equations that have to be written out because of the pesky division. If only it was a multiplication we could have used the Hadamard function that was already written earlier and be done with 1 equation.

so... "I focussed on that", and I found on wikipedia that there is a thing called Hadamard division as well. Then I implemented it:

inline v3 
HadamardDivide(v3 A, v3 B)
{
  v3 Result = V3(SafeRatio0(A.X, B.X), SafeRatio0(A.Y, B.Y), SafeRatio0(A.Z, B.Z));
  return Result;
}

And this "compressed" my GetBarycentric function into a single line like this:

inline v3
GetBarycentric(rectangle3 A, v3 P)
{
  v3 Result = HadamardDivide(P - A.Min, A.Max - A.Min);
  return Result;
}

Now, I am not even sure if Casey Muratori will even call this compression (hence my quotes before). Because its not like I am seeing this pattern repeat and using this to make things efficient. I'm simply doing a cute thing I found intriguing.

If I was still a haskell dude, I would take this even farther and say, well, why do I even have to call SafeRatio0 3 times when implementing the HadamardDivide ? I could somehow apply that as a functor on the vector right? Some kind of fmap would do that job nicely... But I see that this is a slipperly slope and I'm not gaining anything here except maybe making code that feels cute to me right now.

So, my question is, how do you decide when to stop?. Its not that hard for me to convince myself to do all this "fancy" stuff. Certainly before I found handmade hero, I would have absolutely done this. And I would have tried to "rewrite the whole thing in rust". So, does this judgement only come through experience or has Casey Muratori shown somewhere how to decide when its time to stop?

its-time-to-stop-stop.gif


Edited by Gaurav Gautam on

I comes from experience, and I would argue that what you did the inverse of compression.

"Compression" is about starting by writing the simplest thing possible at first to discover the problem space, and if you discover that you're doing similar things at different locations, see if it make sens to turn them into a single piece of code that you can call. Some times the small differences (or performance) are enough that it doesn't make sens to compress. And you might want to have more than just two places to study before compressing to avoid adding constraints too early.

In your example you abstracted some code that you only call once, but as it's a "standard" math operation it might still make sens. And it's likely (but no guaranteed) that the optimizer will inline that.

Hmm yeah I also thought that this doesn't feel good.

An aside, I'm stuck on day74 with a bug where as soon as I include ChunkZ in the gathering of entities for BeginSim I run out of memory. I don't think the simRegion is too big. Nor do I see how I could have added too many more entities than C.M. This is one of those bugs that will take me hours to figure out 😅


Replying to mrmixer (#26736)

I think about “concept compression” more than I think about “code compression”. Sometimes two pieces of code look very similar, but are dealing with such different domains that I prefer to keep them separate. On the other hand, sometimes two pieces of code look different, but are conceptually addressing a similar problem, and it makes sense to pull them both together under a larger system.

You’re already at such a small chunk of code that there’s no concept left to compress. Express it straightforwardly and move on.

From a pragmatic standpoint, there’s no reason to sink more thought into a function like this. Will you be confused when you read this later? Are you likely to cause bugs when maintaining this later? If the answer to those questions is no, just get on with the rest of your program.

In principle that makes sense. However, it is 3 lines of code that is doing the same thing as a simple vector equation. And if you have a math background it makes a lot of sense to do what I did above.

In the code of handmade hero, C.M. has implemented two different hash maps. One with internal probing and one with external probing. And obviously your criteria would say those can be abstracted into one.

I am not defending what I did above. I already said that I don't like it that much. But, I think, all of this is not really an exact science. I wouldn't be able two write a program to answer yes or no on whether or not to condense two parts of a program into one. Therefore, it seems to be just a matter of human taste ultimately.


Replying to bvisness (#26738)

Hey Simon,

So If you remember last time I said I was stuck on day74 with running out of memory. And I have found that once again, its the hashmap where I screwed up. Basically its inserting one particular chunk multiple times because I have made some mistake in chaining the new blocks. I haven't yet figured out what the mistake is but I can see that, that is the problem clearly.

I am having an issue where I made a mistake in the hashmap implementation for the 3rd or 4th time. Is this normal? I do not have any formal computer science background. But do you know if having this much difficulty with implementing slightly non trivial stuff eventually goes away? I won't stop even if this is just me being dumb 😅. I just want to know how much shit Im in ability-wise 😛.

I see Casey Muratori is able to write these things in one go as if they are nothing. Is that something that's innate to him or is that something he learned? Even if its innate to him and others like him, Im still going to try to get it by putting in effort. But Im just being a weakling here and asking if they have it just outright... I don't know how that would even make a difference for me. I have to work to get it anyways.


Edited by Gaurav Gautam on
Replying to mrmixer (#26736)

It's perfectly normal. Casey has 30 (40?) years of experience, so don't expect to program like him if you're beginning. It's not "innate", it's a lot of work across a long period of time.

I see Casey Muratori is able to write these things in one go as if they are nothing.

Casey (and everybody) makes mistakes all the time, that's why we use the compiler and debugger to find them. With time you learn from them, and write code in a way that avoids (some) mistakes or makes it easier to find them (e.g. zero initialization, using asserts...).

Maybe it would help you when you find a bug to think a little bit about how you could have some way of detecting that bug more easily, or how to write code to avoid that kind of bug in the future. It's not always possible but even just thinking about it might make it easier for you to reason about the problem in the future. And always use the debugger to step in everything, don't assume something is correct until you see it's correct.

Writing some code to visualize the data is almost always worth the effort. For example you might want to write some code that output in a text file each steps that went into creating and adding things in the hashmap. Input -> hash -> search -> add -> final state of the hash map, for every entry.


Edited by Simon Anciaux on

Yes that makes sense. Thankyou. Ill write some print statements like you said this time instead of just trying to step into that code repeatedly till I figure it out.


Replying to mrmixer (#26744)